diff --git a/app/src/main/java/com/limelight/AppView.java b/app/src/main/java/com/limelight/AppView.java index 47769791..17112cf7 100644 --- a/app/src/main/java/com/limelight/AppView.java +++ b/app/src/main/java/com/limelight/AppView.java @@ -19,7 +19,6 @@ import com.limelight.utils.Dialog; import com.limelight.utils.ServerHelper; import com.limelight.utils.ShortcutHelper; import com.limelight.utils.SpinnerDialog; -import com.limelight.utils.TvChannelHelper; import com.limelight.utils.UiHelper; import android.app.Activity; @@ -51,7 +50,6 @@ public class AppView extends Activity implements AdapterFragmentCallbacks { private AppGridAdapter appGridAdapter; private String uuidString; private ShortcutHelper shortcutHelper; - private TvChannelHelper tvChannelHelper; private ComputerDetails computer; private ComputerManagerService.ApplistPoller poller; @@ -67,10 +65,10 @@ public class AppView extends Activity implements AdapterFragmentCallbacks { private final static int START_WITH_QUIT = 4; private final static int VIEW_DETAILS_ID = 5; private final static int CREATE_SHORTCUT_ID = 6; - private final static int ADD_TO_TV_CHANNEL = 7; public final static String NAME_EXTRA = "Name"; public final static String UUID_EXTRA = "UUID"; + public final static String NEW_PAIR_EXTRA = "NewPair"; private ComputerManagerService.ComputerManagerBinder managerBinder; private final ServiceConnection serviceConnection = new ServiceConnection() { @@ -187,9 +185,6 @@ public class AppView extends Activity implements AdapterFragmentCallbacks { shortcutHelper.disableShortcut(details.uuid, getResources().getString(R.string.scut_not_paired)); - //Delete channel of PC for now - tvChannelHelper.deleteChannel(details.uuid); - // Display a toast to the user and quit the activity Toast.makeText(AppView.this, getResources().getText(R.string.scut_not_paired), Toast.LENGTH_SHORT).show(); finish(); @@ -258,7 +253,6 @@ public class AppView extends Activity implements AdapterFragmentCallbacks { inForeground = true; shortcutHelper = new ShortcutHelper(this); - tvChannelHelper = new TvChannelHelper(this); UiHelper.setLocale(this); @@ -275,9 +269,8 @@ public class AppView extends Activity implements AdapterFragmentCallbacks { label.setText(computerName); // Add a launcher shortcut for this PC (forced, since this is user interaction) - shortcutHelper.createAppViewShortcut(uuidString, computerName, uuidString, true); + shortcutHelper.createAppViewShortcut(uuidString, computerName, uuidString, true, getIntent().getBooleanExtra(NEW_PAIR_EXTRA, false)); shortcutHelper.reportShortcutUsed(uuidString); - tvChannelHelper.createTvChannel(uuidString, computerName); // Bind to the computer manager service bindService(new Intent(this, ComputerManagerService.class), serviceConnection, @@ -356,9 +349,7 @@ public class AppView extends Activity implements AdapterFragmentCallbacks { } menu.add(Menu.NONE, VIEW_DETAILS_ID, 3, getResources().getString(R.string.applist_menu_details)); - if (tvChannelHelper.isSupport()) { - menu.add(Menu.NONE, ADD_TO_TV_CHANNEL, 4, getResources().getString(R.string.applist_menu_tv_channel)); - } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { // Only add an option to create shortcut if box art is loaded // and when we're in grid-mode (not list-mode). ImageView appImageView = info.targetView.findViewById(R.id.grid_image); @@ -434,10 +425,6 @@ public class AppView extends Activity implements AdapterFragmentCallbacks { } return true; - case ADD_TO_TV_CHANNEL: - tvChannelHelper.addGameToChannel(computer, app.app); - return true; - default: return super.onContextItemSelected(item); } diff --git a/app/src/main/java/com/limelight/Game.java b/app/src/main/java/com/limelight/Game.java index c888ff61..ddb68c07 100644 --- a/app/src/main/java/com/limelight/Game.java +++ b/app/src/main/java/com/limelight/Game.java @@ -268,10 +268,12 @@ public class Game extends Activity implements SurfaceHolder.Callback, return; } - // Add a launcher shortcut for this PC (forced, since this is user interaction) + // Report this shortcut being used shortcutHelper = new ShortcutHelper(this); - shortcutHelper.createAppViewShortcut(uuid, pcName, uuid, true); shortcutHelper.reportShortcutUsed(uuid); + if (appName != null) { + shortcutHelper.reportGameLaunched(uuid, pcName, ""+appId, appName); + } // Initialize the MediaCodec helper before creating the decoder GlPreferences glPrefs = GlPreferences.readPreferences(this); @@ -412,7 +414,7 @@ public class Game extends Activity implements SurfaceHolder.Callback, StreamConfiguration config = new StreamConfiguration.Builder() .setResolution(prefConfig.width, prefConfig.height) .setRefreshRate(prefConfig.fps) - .setApp(new NvApp(appName, appId, willStreamHdr)) + .setApp(new NvApp(appName != null ? appName : "app", appId, willStreamHdr)) .setBitrate(prefConfig.bitrate) .setEnableSops(prefConfig.enableSops) .enableLocalAudioPlayback(prefConfig.playHostAudio) diff --git a/app/src/main/java/com/limelight/PcView.java b/app/src/main/java/com/limelight/PcView.java index 45e51f62..c38b0406 100644 --- a/app/src/main/java/com/limelight/PcView.java +++ b/app/src/main/java/com/limelight/PcView.java @@ -25,7 +25,6 @@ import com.limelight.utils.Dialog; import com.limelight.utils.HelpLauncher; import com.limelight.utils.ServerHelper; import com.limelight.utils.ShortcutHelper; -import com.limelight.utils.TvChannelHelper; import com.limelight.utils.UiHelper; import android.app.Activity; @@ -63,7 +62,6 @@ public class PcView extends Activity implements AdapterFragmentCallbacks { private RelativeLayout noPcFoundLayout; private PcGridAdapter pcGridAdapter; private ShortcutHelper shortcutHelper; - private TvChannelHelper tvChannelHelper; private ComputerManagerService.ComputerManagerBinder managerBinder; private boolean freezeUpdates, runningPolling, inForeground, completeOnCreateCalled; private final ServiceConnection serviceConnection = new ServiceConnection() { @@ -217,7 +215,6 @@ public class PcView extends Activity implements AdapterFragmentCallbacks { completeOnCreateCalled = true; shortcutHelper = new ShortcutHelper(this); - tvChannelHelper = new TvChannelHelper(this); UiHelper.setLocale(this); @@ -443,7 +440,7 @@ public class PcView extends Activity implements AdapterFragmentCallbacks { if (toastSuccess) { // Open the app list after a successful pairing attempt - doAppList(computer); + doAppList(computer, true); } else { // Start polling again if we're still in the foreground @@ -542,7 +539,7 @@ public class PcView extends Activity implements AdapterFragmentCallbacks { }).start(); } - private void doAppList(ComputerDetails computer) { + private void doAppList(ComputerDetails computer, boolean newlyPaired) { if (computer.state == ComputerDetails.State.OFFLINE) { Toast.makeText(PcView.this, getResources().getString(R.string.error_pc_offline), Toast.LENGTH_SHORT).show(); return; @@ -555,6 +552,7 @@ public class PcView extends Activity implements AdapterFragmentCallbacks { Intent i = new Intent(this, AppView.class); i.putExtra(AppView.NAME_EXTRA, computer.name); i.putExtra(AppView.UUID_EXTRA, computer.uuid); + i.putExtra(AppView.NEW_PAIR_EXTRA, newlyPaired); startActivity(i); } @@ -594,7 +592,7 @@ public class PcView extends Activity implements AdapterFragmentCallbacks { return true; case APP_LIST_ID: - doAppList(computer.details); + doAppList(computer.details, false); return true; case RESUME_ID: @@ -640,9 +638,6 @@ public class PcView extends Activity implements AdapterFragmentCallbacks { shortcutHelper.disableShortcut(details.uuid, getResources().getString(R.string.scut_deleted_pc)); - //Delete channel of PC - tvChannelHelper.deleteChannel(details.uuid); - pcGridAdapter.removeComputer(computer); pcGridAdapter.notifyDataSetChanged(); @@ -671,7 +666,7 @@ public class PcView extends Activity implements AdapterFragmentCallbacks { // Add a launcher shortcut for this PC if (details.pairState == PairState.PAIRED) { - shortcutHelper.createAppViewShortcut(details.uuid, details, false); + shortcutHelper.createAppViewShortcutForOnlineHost(details); } if (existingEntry != null) { @@ -713,7 +708,7 @@ public class PcView extends Activity implements AdapterFragmentCallbacks { // Pair an unpaired machine by default doPair(computer.details); } else { - doAppList(computer.details); + doAppList(computer.details, false); } } }); diff --git a/app/src/main/java/com/limelight/ShortcutTrampoline.java b/app/src/main/java/com/limelight/ShortcutTrampoline.java index 6287403d..3a1cb212 100644 --- a/app/src/main/java/com/limelight/ShortcutTrampoline.java +++ b/app/src/main/java/com/limelight/ShortcutTrampoline.java @@ -104,7 +104,7 @@ public class ShortcutTrampoline extends Activity { if (appIdString != null && appIdString.length() > 0) { if (details.runningGameId == 0 || details.runningGameId == Integer.parseInt(appIdString)) { intentStack.add(ServerHelper.createStartIntent(ShortcutTrampoline.this, - new NvApp("app", Integer.parseInt(appIdString), false), details, managerBinder)); + new NvApp(null, Integer.parseInt(appIdString), false), details, managerBinder)); // Close this activity finish(); @@ -115,7 +115,7 @@ public class ShortcutTrampoline extends Activity { // Create the start intent immediately, so we can safely unbind the managerBinder // below before we return. final Intent startIntent = ServerHelper.createStartIntent(ShortcutTrampoline.this, - new NvApp("app", Integer.parseInt(appIdString), false), details, managerBinder); + new NvApp(null, Integer.parseInt(appIdString), false), details, managerBinder); UiHelper.displayQuitConfirmationDialog(ShortcutTrampoline.this, new Runnable() { @Override @@ -155,7 +155,7 @@ public class ShortcutTrampoline extends Activity { // If a game is running, we'll make the stream the top level activity if (details.runningGameId != 0) { intentStack.add(ServerHelper.createStartIntent(ShortcutTrampoline.this, - new NvApp("app", details.runningGameId, false), details, managerBinder)); + new NvApp(null, details.runningGameId, false), details, managerBinder)); } // Now start the activities diff --git a/app/src/main/java/com/limelight/utils/ShortcutHelper.java b/app/src/main/java/com/limelight/utils/ShortcutHelper.java index 376a58c6..71d9b4c7 100644 --- a/app/src/main/java/com/limelight/utils/ShortcutHelper.java +++ b/app/src/main/java/com/limelight/utils/ShortcutHelper.java @@ -1,7 +1,7 @@ package com.limelight.utils; import android.annotation.TargetApi; -import android.content.Context; +import android.app.Activity; import android.content.Intent; import android.content.pm.ShortcutInfo; import android.content.pm.ShortcutManager; @@ -22,9 +22,10 @@ import java.util.List; public class ShortcutHelper { private final ShortcutManager sm; - private final Context context; + private final Activity context; + private final TvChannelHelper tvChannelHelper; - public ShortcutHelper(Context context) { + public ShortcutHelper(Activity context) { this.context = context; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) { sm = context.getSystemService(ShortcutManager.class); @@ -32,6 +33,7 @@ public class ShortcutHelper { else { sm = null; } + this.tvChannelHelper = new TvChannelHelper(context); } @TargetApi(Build.VERSION_CODES.N_MR1) @@ -80,15 +82,20 @@ public class ShortcutHelper { return false; } - public void reportShortcutUsed(String id) { + public void reportShortcutUsed(String computerUuid) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) { - if (getInfoForId(id) != null) { - sm.reportShortcutUsed(id); + if (getInfoForId(computerUuid) != null) { + sm.reportShortcutUsed(computerUuid); } } } - public void createAppViewShortcut(String id, String computerName, String computerUuid, boolean forceAdd) { + public void reportGameLaunched(String computerUuid, String computerName, String appId, String appName) { + tvChannelHelper.createTvChannel(computerUuid, computerName); + tvChannelHelper.addGameToChannel(computerUuid, computerName, appId, appName); + } + + public void createAppViewShortcut(String id, String computerName, String computerUuid, boolean forceAdd, boolean newlyPaired) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) { Intent i = new Intent(context, ShortcutTrampoline.class); i.putExtra(AppView.NAME_EXTRA, computerName); @@ -122,10 +129,16 @@ public class ShortcutHelper { } } } + + if (newlyPaired) { + // Avoid hammering the channel API for each computer poll because it will throttle us + tvChannelHelper.createTvChannel(computerUuid, computerName); + tvChannelHelper.requestChannelOnHomeScreen(computerUuid); + } } - public void createAppViewShortcut(String id, ComputerDetails details, boolean forceAdd) { - createAppViewShortcut(id, details.name, details.uuid, forceAdd); + public void createAppViewShortcutForOnlineHost(ComputerDetails details) { + createAppViewShortcut(details.uuid, details.name, details.uuid, false, false); } @TargetApi(Build.VERSION_CODES.O) @@ -161,10 +174,11 @@ public class ShortcutHelper { return createPinnedGameShortcut(id, iconBits, cDetails.name, cDetails.uuid, app.getAppName(), Integer.valueOf(app.getAppId()).toString()); } - public void disableShortcut(String id, CharSequence reason) { + public void disableShortcut(String uuid, CharSequence reason) { + tvChannelHelper.deleteChannel(uuid); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) { - if (getInfoForId(id) != null) { - sm.disableShortcuts(Collections.singletonList(id), reason); + if (getInfoForId(uuid) != null) { + sm.disableShortcuts(Collections.singletonList(uuid), reason); } } } diff --git a/app/src/main/java/com/limelight/utils/TvChannelHelper.java b/app/src/main/java/com/limelight/utils/TvChannelHelper.java index 82daa2de..fd2b43d3 100644 --- a/app/src/main/java/com/limelight/utils/TvChannelHelper.java +++ b/app/src/main/java/com/limelight/utils/TvChannelHelper.java @@ -1,12 +1,12 @@ package com.limelight.utils; import android.annotation.TargetApi; -import android.app.UiModeManager; +import android.app.Activity; +import android.content.ActivityNotFoundException; import android.content.ContentUris; import android.content.ContentValues; -import android.content.Context; import android.content.Intent; -import android.content.res.Configuration; +import android.content.pm.PackageManager; import android.database.Cursor; import android.database.sqlite.SQLiteException; import android.graphics.Bitmap; @@ -21,99 +21,91 @@ import com.limelight.LimeLog; import com.limelight.PosterContentProvider; import com.limelight.R; import com.limelight.ShortcutTrampoline; -import com.limelight.nvstream.http.ComputerDetails; -import com.limelight.nvstream.http.NvApp; import java.io.IOException; import java.io.OutputStream; -@TargetApi(Build.VERSION_CODES.O) public class TvChannelHelper { private static final int ASPECT_RATIO_MOVIE_POSTER = 5; private static final int TYPE_GAME = 12; - public static final String[] CHANNEL_PROJECTION = {TvContract.Channels._ID, TvContract.Channels.COLUMN_INTERNAL_PROVIDER_ID}; - public static final int INTERNAL_PROVIDER_ID_INDEX = 1; - public static final int ID_INDEX = 0; - private Context context; + private static final int INTERNAL_PROVIDER_ID_INDEX = 1; + private static final int ID_INDEX = 0; + private Activity context; - public TvChannelHelper(Context context) { + public TvChannelHelper(Activity context) { this.context = context; } - public boolean createTvChannel(String computerUuid, String computerName) { - if (!isSupport()) { - return false; + void requestChannelOnHomeScreen(String computerUuid) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + if (!isAndroidTV()) { + return; + } + + Long channelId = getChannelId(computerUuid); + if (channelId == null) { + return; + } + + Intent intent = new Intent(TvContract.ACTION_REQUEST_CHANNEL_BROWSABLE); + intent.putExtra(TvContract.EXTRA_CHANNEL_ID, getChannelId(computerUuid)); + try { + context.startActivityForResult(intent, 0); + } catch (ActivityNotFoundException e) { + } } - - Intent i = new Intent(context, ShortcutTrampoline.class); - i.putExtra(AppView.NAME_EXTRA, computerName); - i.putExtra(AppView.UUID_EXTRA, computerUuid); - i.setAction(Intent.ACTION_DEFAULT); - ChannelBuilder builder = new ChannelBuilder() - .setType(TvContract.Channels.TYPE_PREVIEW) - .setDisplayName(computerName) - .setInternalProviderId(computerUuid) - .setAppLinkIntent(i); - - Long channelId = getChannelId(computerUuid); - - - if (channelId != null) { - context.getContentResolver().update(TvContract.buildChannelUri(channelId), - builder.toContentValues(), null, null); - return false; - } - - - Uri channelUri = context.getContentResolver().insert( - TvContract.Channels.CONTENT_URI, builder.toContentValues()); - - - if (channelUri != null) { - long id = ContentUris.parseId(channelUri); - updateChannelIcon(id); - return true; - } - return false; } - private void updateChannelIcon(long id) { - Bitmap bitmap = drawableToBitmap(context.getResources().getDrawable(R.drawable.ic_channel)); + void createTvChannel(String computerUuid, String computerName) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + if (!isAndroidTV()) { + return; + } + + Intent i = new Intent(context, ShortcutTrampoline.class); + i.putExtra(AppView.NAME_EXTRA, computerName); + i.putExtra(AppView.UUID_EXTRA, computerUuid); + i.setAction(Intent.ACTION_DEFAULT); + ChannelBuilder builder = new ChannelBuilder() + .setType(TvContract.Channels.TYPE_PREVIEW) + .setDisplayName(computerName) + .setInternalProviderId(computerUuid) + .setAppLinkIntent(i); + + Long channelId = getChannelId(computerUuid); + if (channelId != null) { + context.getContentResolver().update(TvContract.buildChannelUri(channelId), + builder.toContentValues(), null, null); + return; + } + + Uri channelUri = context.getContentResolver().insert( + TvContract.Channels.CONTENT_URI, builder.toContentValues()); + if (channelUri != null) { + long id = ContentUris.parseId(channelUri); + updateChannelIcon(id); + } + } + } + + @TargetApi(Build.VERSION_CODES.O) + private void updateChannelIcon(long channelId) { + Bitmap logo = drawableToBitmap(context.getResources().getDrawable(R.drawable.ic_channel)); try { - storeChannelLogo(id, bitmap); + Uri localUri = TvContract.buildChannelLogoUri(channelId); + try (OutputStream outputStream = context.getContentResolver().openOutputStream(localUri)) { + logo.compress(Bitmap.CompressFormat.PNG, 100, outputStream); + outputStream.flush(); + } catch (SQLiteException | IOException e) { + LimeLog.warning("Failed to store the logo to the system content provider."); + e.printStackTrace(); + } } finally { - bitmap.recycle(); + logo.recycle(); } } - - /** - * Stores the given channel logo {@link Bitmap} in the system content provider and associate - * it with the given channel ID. - * - * @param channelId the ID of the target channel with which the given logo should be associated - * @param logo the logo image to be stored - * @return {@code true} if successfully stored the logo in the system content provider, - * otherwise {@code false}. - */ - private boolean storeChannelLogo(long channelId, - Bitmap logo) { - if (!isSupport()) { - return false; - } - boolean result = false; - Uri localUri = TvContract.buildChannelLogoUri(channelId); - try (OutputStream outputStream = context.getContentResolver().openOutputStream(localUri)) { - result = logo.compress(Bitmap.CompressFormat.PNG, 100, outputStream); - outputStream.flush(); - } catch (SQLiteException | IOException e) { - LimeLog.warning("Failed to store the logo to the system content provider."); - e.printStackTrace(); - } - return result; - } - private Bitmap drawableToBitmap(Drawable drawable) { int width = context.getResources().getDimensionPixelSize(R.dimen.tv_channel_logo_width); int height = context.getResources().getDimensionPixelSize(R.dimen.tv_channel_logo_width); @@ -125,59 +117,62 @@ public class TvChannelHelper { return bitmap; } + void addGameToChannel(String computerUuid, String computerName, String appId, String appName) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + if (!isAndroidTV()) { + return; + } - public boolean addGameToChannel(String computerUuid, String computerName, String appId, String appName) { - if (!isSupport()) { - return false; + PreviewProgramBuilder builder = new PreviewProgramBuilder(); + Intent i = new Intent(context, ShortcutTrampoline.class); + + i.putExtra(AppView.NAME_EXTRA, computerName); + i.putExtra(AppView.UUID_EXTRA, computerUuid); + i.putExtra(ShortcutTrampoline.APP_ID_EXTRA, appId); + i.setAction(Intent.ACTION_DEFAULT); + + Uri resourceURI = PosterContentProvider.createBoxArtUri(computerUuid, appId); + + Long channelId = getChannelId(computerUuid); + if (channelId == null) { + return; + } + + builder.setChannelId(channelId) + .setType(TYPE_GAME) + .setTitle(appName) + .setPosterArtAspectRatio(ASPECT_RATIO_MOVIE_POSTER) + .setPosterArtUri(resourceURI) + .setIntent(i) + .setInternalProviderId(appId); + + context.getContentResolver().insert(TvContract.PreviewPrograms.CONTENT_URI, + builder.toContentValues()); + + TvContract.requestChannelBrowsable(context, channelId); } - - PreviewProgramBuilder builder = new PreviewProgramBuilder(); - Intent i = new Intent(context, ShortcutTrampoline.class); - - i.putExtra(AppView.NAME_EXTRA, computerName); - i.putExtra(AppView.UUID_EXTRA, computerUuid); - i.putExtra(ShortcutTrampoline.APP_ID_EXTRA, appId); - i.setAction(Intent.ACTION_DEFAULT); - - Uri resourceURI = PosterContentProvider.createBoxArtUri(computerUuid, appId); - - Long channelId = getChannelId(computerUuid); - - - if (channelId == null) { - return false; - } - builder.setChannelId(channelId) - .setType(TYPE_GAME) - .setTitle(appName) - .setPosterArtAspectRatio(ASPECT_RATIO_MOVIE_POSTER) - .setPosterArtUri(resourceURI) - .setIntent(i) - .setInternalProviderId(appId); - Uri programUri = context.getContentResolver().insert(TvContract.PreviewPrograms.CONTENT_URI, - builder.toContentValues()); - - - TvContract.requestChannelBrowsable(context, channelId); - return programUri != null; } - public boolean deleteChannel(String computerUuid) { - if (!isSupport()) { - return false; - } - Long channelId = getChannelId(computerUuid); - if (channelId == null) { - return false; - } - Uri uri = TvContract.buildChannelUri(channelId); - return context.getContentResolver().delete(uri, null, null) > 0; + void deleteChannel(String computerUuid) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + if (!isAndroidTV()) { + return; + } + Long channelId = getChannelId(computerUuid); + if (channelId == null) { + return; + } + Uri uri = TvContract.buildChannelUri(channelId); + context.getContentResolver().delete(uri, null, null); + } } - @TargetApi(Build.VERSION_CODES.LOLLIPOP) + @TargetApi(Build.VERSION_CODES.O) private Long getChannelId(String computerUuid) { Uri uri = TvContract.Channels.CONTENT_URI; + final String[] CHANNEL_PROJECTION = {TvContract.Channels._ID, TvContract.Channels.COLUMN_INTERNAL_PROVIDER_ID}; + Cursor cursor = context.getContentResolver().query(uri, CHANNEL_PROJECTION, null, @@ -202,11 +197,6 @@ public class TvChannelHelper { } } - - public void addGameToChannel(ComputerDetails computer, NvApp app) { - addGameToChannel(computer.uuid, computer.name, String.valueOf(app.getAppId()), app.getAppName()); - } - private static String toValueString(T value) { return value == null ? null : value.toString(); } @@ -215,15 +205,12 @@ public class TvChannelHelper { return intent == null ? null : intent.toUri(Intent.URI_INTENT_SCHEME); } - public boolean isSupport() { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) { - return false; - } - - UiModeManager uiModeManager = (UiModeManager) context.getSystemService(Context.UI_MODE_SERVICE); - return uiModeManager.getCurrentModeType() == Configuration.UI_MODE_TYPE_TELEVISION; + @TargetApi(Build.VERSION_CODES.O) + public boolean isAndroidTV() { + return context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK); } + @TargetApi(Build.VERSION_CODES.O) private static class PreviewProgramBuilder { private ContentValues mValues = new ContentValues(); @@ -275,6 +262,7 @@ public class TvChannelHelper { } + @TargetApi(Build.VERSION_CODES.O) private static class ChannelBuilder { private ContentValues mValues = new ContentValues();