Reputation: 1015
My app is fully usable and navigatable on AndroidTV using the DPad. Well, it certainly is on MY AndroidTV, as well as AVD.
However, Google keeps on rejecting my appeal to have it marked as AndroidTV capable.
There is no feedback, other than
Missing DPad functionality Your app requires user interaction for menus or app navigation. Please make sure that all menus and app navigation are fully functional using a DPad. Please refer to our DPAD Control and Hardware Declaration documentation.
Do you know if they actually test these apps, or do they just look for certain code patterns? The message from them looks automated, and I've not spoken to a person yet.
Would it help if I recorded my app in use and sent them a link to the demonstration?
Upvotes: 12
Views: 4414
Reputation: 745
In my case there were 3 problems.
after all of those measures - 12 hours later - I was approved. Now, I have removed the toast and my app was still accepted.
Update - 4/11/2024:
contacting support did not help. needed to override onKeydown which is what the pad buttons needs - and implement toasts everywhere. especially the volume buttons
int currentVolume = 50;
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
try {
switch (keyCode) {
case KeyEvent.KEYCODE_DPAD_UP:
if (remotevideoTrack != null && audioTrack != null ) {
currentVolume = Math.min(currentVolume + 5, 100);
audioTrack.setVolume(currentVolume);
ToastMeVeryShort("volume:" + currentVolume);
}
else
ToastMeVeryShort("no connection");
return true;
case KeyEvent.KEYCODE_MEDIA_PLAY:
if (remotevideoTrack != null && audioTrack != null ) {
ToastMeVeryShort("running already");
}
else
ToastMeVeryShort("no connection");
return true;
case KeyEvent.KEYCODE_MEDIA_PAUSE:
if (remotevideoTrack != null && audioTrack != null ) {
ToastMeVeryShort("running already");
}
else
ToastMeVeryShort("no connection");
return true;
case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
if (remotevideoTrack != null && audioTrack != null ) {
ToastMeVeryShort("running already");
}
else
ToastMeVeryShort("no connection");
return true;
case KeyEvent.KEYCODE_DPAD_DOWN:
if (remotevideoTrack != null && audioTrack != null ) {
if (audioTrack != null) {
currentVolume = Math.max(currentVolume - 5, 0);
audioTrack.setVolume(currentVolume);
ToastMeVeryShort("volume:" + currentVolume);
}
}
else
ToastMeVeryShort("no connection");
return true;
case KeyEvent.KEYCODE_DPAD_RIGHT:
return super.onKeyDown(keyCode, event);
case KeyEvent.KEYCODE_DPAD_LEFT:
return super.onKeyDown(keyCode, event);
case KeyEvent.KEYCODE_BACK: {
if (remotevideoTrack != null && audioTrack != null ) {
ToastMeVeryShort("bye");
}
try {
SayByeAndClose();
} catch (Exception ex) {
Log.e(TAG, ex.toString());
}
try{
finish();
System.exit(0);
} catch (Exception ex) {
Log.e(TAG, ex.toString());
}
return true;
}
}
}
catch (Exception ex)
{
Log.e(TAG, ex.toString());
}
return false;
}
Upvotes: 2
Reputation: 1
im facing the same problem.. i tested in fire tv and TV emulator and i think the dpad function is good..
Here is my manifest files
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.hsvision.hsvplay.android.tv">
<!--
io.flutter.app.FlutterApplication is an android.app.Application that
calls FlutterMain.startInitialization(this); in its onCreate method.
In most cases you can leave this as-is, but you if you want to provide
additional functionality it is fine to subclass or reimplement
FlutterApplication and put your custom class here.
-->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-feature android:name="android.hardware.touchscreen"
android:required="false"/>
<uses-feature android:name="android.hardware.faketouch"
android:required="false"/>
<uses-feature android:name="android.hardware.telephony"
android:required="false"/>
<uses-feature android:name="android.hardware.camera"
android:required="false"/>
<uses-feature android:name="android.hardware.nfc"
android:required="false"/>
<uses-feature android:name="android.hardware.location.gps"
android:required="false"/>
<uses-feature android:name="android.hardware.microphone"
android:required="false"/>
<uses-feature android:name="android.hardware.sensor"
android:required="false"/>
<uses-feature android:name="android.software.leanback"
android:required="true" />
<uses-feature android:name="android.hardware.wifi"
android:required="false"/>
<application
android:usesCleartextTraffic="true"
android:banner="@drawable/banner"
android:icon="@drawable/banner"
android:label="HSV PLAY TV"
android:theme="@style/Theme.Leanback">
<meta-data android:name="com.facebook.sdk.ApplicationId" android:value="@string/facebook_app_id"/>
<activity android:name="com.facebook.FacebookActivity"
android:configChanges="keyboard|keyboardHidden|screenLayout|screenSize|orientation"
android:label="@string/app_name" />
<activity
android:name="com.facebook.CustomTabActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="@string/fb_login_protocol_scheme" />
</intent-filter>
</activity>
<activity
android:exported="true"
android:name=".MainActivity"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:launchMode="singleTop"
android:theme="@style/LaunchTheme"
android:windowSoftInputMode="adjustResize" >
<!--
Specifies an Android theme to apply to this Activity as soon as
the Android process has started. This theme is visible to the user
while the Flutter UI initializes. After that, this theme continues
to determine the Window background behind the Flutter UI.
-->
<meta-data
android:name="io.flutter.embedding.android.NormalTheme"
android:resource="@style/NormalTheme" />
<!--
Displays an Android View that continues showing the launch screen
Drawable until Flutter paints its first frame, then this splash
screen fades out. A splash screen is useful to avoid any visual
gap between the end of Android's launch screen and the painting of
Flutter's first frame.
-->
<meta-data
android:name="io.flutter.embedding.android.SplashScreenDrawable"
android:resource="@drawable/launch_background" />
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LEANBACK_LAUNCHER" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<!--
Don't delete the meta-data below. This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
Upvotes: 0
Reputation: 11
AndroidTV applications support and expects leanback activities. Also, D-pad needs to minimum remote controller support like up, down, left, right, select, Back, and Home buttons.
D-pad minimum controls The default controller for a TV device is a D-pad. In general, your app should be operable from a remote controller that only has up, down, left, right, select, Back, and Home buttons. If your app is a game that typically requires a game controller with additional controls, your app should attempt to allow gameplay with these D-pad controls. In this case, your app should also warn the user that a controller is required and allow them to exit your game gracefully using the D-pad controller. For more information about handling navigation with D-pad controller for TV devices, see Create TV navigation.
Adding the below lines to your main activity in AndroidManifest.xml may help Dpad support.
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.LAUNCHER" />
<category android:name="android.intent.category.LEANBACK_LAUNCHER" />
</intent-filter>
If its not working and these lines already in manifest please share your manifest file.
Upvotes: 0