How can I check if an app is running on an Android TV

private boolean isDirectToTV() {
  return(getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEVISION)
      || getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK));
}

This will return true if the device is advertising itself as having either the android.hardware.type.television or android.software.leanback system features. Android TV and Fire TV handle this correctly; I have not tried it on other environment as yet.


Summarizing previous answers:

  • If uiModeManager.currentModeType == UI_MODE_TYPE_TELEVISION that's definitely a TV
  • We can't rely on currentModeType to say that it is a TV, because some TV devices are actually return UI_MODE_TYPE_NORMAL
  • So we should check FEATURE_TELEVISION for pre-lollipop and FEATURE_LEANBACK for lollipop devices.
  • if you want to support not only tv's, but stationary devices with screen, you may add additional checks to predict it
  • you should be careful with that to not show tv ui on the phone

This is a kotlin code we actually use:

enum class UiModeType {
    NORMAL,
    DESK,
    CAR,
    TV,
    APPLIANCE,
    WATCH,
    VR
}

private val modeType: Int
    get() = uiModeManager.currentModeType

fun getUiModeType(): UiModeType = when {
    modeType == UI_MODE_TYPE_APPLIANCE -> UiModeType.APPLIANCE
    modeType == UI_MODE_TYPE_CAR -> UiModeType.CAR
    modeType == UI_MODE_TYPE_DESK -> UiModeType.DESK
    modeType == UI_MODE_TYPE_TELEVISION -> UiModeType.TV

    sdkInt >= Build.VERSION_CODES.KITKAT_WATCH &&
        modeType == UI_MODE_TYPE_WATCH -> UiModeType.WATCH

    sdkInt >= Build.VERSION_CODES.O &&
        modeType == UI_MODE_TYPE_VR_HEADSET -> UiModeType.VR

    isLikelyTelevision() -> UiModeType.TV

    modeType == UI_MODE_TYPE_NORMAL -> UiModeType.NORMAL
    else -> UiModeType.NORMAL
}

private fun isLikelyTelevision(): Boolean = with(packageManager) {
    return@with when {
        sdkInt >= Build.VERSION_CODES.LOLLIPOP &&
            hasSystemFeature(PackageManager.FEATURE_LEANBACK) -> true
        sdkInt < Build.VERSION_CODES.LOLLIPOP &&
            @Suppress("DEPRECATION")
            hasSystemFeature(PackageManager.FEATURE_TELEVISION) -> true
        isBatteryAbsent() &&
            hasSystemFeature(PackageManager.FEATURE_USB_HOST) &&
            hasSystemFeature(PackageManager.FEATURE_ETHERNET) &&
            !hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN)
}

@SuppressLint("NewApi")
private fun isBatteryAbsent(): Boolean {
    return if (sdkInt >= Build.VERSION_CODES.LOLLIPOP) {
        batteryManager?.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY) == 0
    } else {
        false
    }
}

From Handling TV Hardware in Android Docs:

public static final String TAG = "DeviceTypeRuntimeCheck";

    UiModeManager uiModeManager = (UiModeManager) getSystemService(UI_MODE_SERVICE);
    if (uiModeManager.getCurrentModeType() == Configuration.UI_MODE_TYPE_TELEVISION) {
        Log.d(TAG, "Running on a TV Device");
    } else {
        Log.d(TAG, "Running on a non-TV Device");
}

Some options are:

1) Query the system for a large screen

2) Use reflection to detect TV specific classes

3) Use hasSystemFeature to detect the lack of touchscreen

More info

https://developer.android.com/training/tv/start/hardware.html

And a similar answer for Google TV

Identify GoogleTv from Android app