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
}
}