Skip to content

Instantly share code, notes, and snippets.

@seventhmoon
Last active March 31, 2023 14:22
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save seventhmoon/3f2357f29a7cab0804289bbfa5100f91 to your computer and use it in GitHub Desktop.
Save seventhmoon/3f2357f29a7cab0804289bbfa5100f91 to your computer and use it in GitHub Desktop.
TvDeviceTypes
import android.annotation.SuppressLint
import android.content.Intent
import android.content.pm.PackageManager
import android.os.Build
import androidx.annotation.IntDef
//Make sure you have the following declared in Manifest when running on Android 11+
//<queries>
//<package android:name="com.google.android.tvlauncher" />
//<package android:name="com.google.android.leanbacklauncher" />
//<package android:name="com.google.android.apps.tv.launcherx" />
//</queries>
object TvDeviceTypes {
@IntDef(ANDROID_NON_TV, ANDROID_OTHER_TV, ANDROID_TV_WITH_WATSON,
ANDROID_TV, ANDROID_TV_OPERATOR_DEVICE, ANDROID_TV_OPERATOR_DEVICE_WITH_CUSTOM_LAUNCHER,
GOOGLE_TV)
@Retention(AnnotationRetention.SOURCE)
annotation class TvDeviceType
private const val LEANBACK = 0b10
private const val WATSON = 0b100
private const val CUSTOM_LAUNCHER = 0b1000
private const val OPERATOR_DEVICE = 0b10000
private const val AMATI = 0b100000
const val ANDROID_NON_TV = 0b0
const val ANDROID_OTHER_TV = 0b1
const val ANDROID_TV = LEANBACK
const val ANDROID_TV_WITH_WATSON = ANDROID_TV + WATSON
const val ANDROID_TV_OPERATOR_DEVICE = ANDROID_TV + OPERATOR_DEVICE
const val ANDROID_TV_OPERATOR_DEVICE_WITH_CUSTOM_LAUNCHER = ANDROID_TV_OPERATOR_DEVICE + CUSTOM_LAUNCHER
const val GOOGLE_TV = ANDROID_TV + AMATI
private const val PACKAGE_LEANBACK_LAUNCHER = "com.google.android.leanbacklauncher"
private const val PACKAGE_WATSON_LAUNCHER = "com.google.android.tvlauncher"
private const val PACKAGE_LAUNCHER_X = "com.google.android.apps.tv.launcherx"
private const val FEATURE_OPERATOR_TIER = "com.google.android.tv.operator_tier"
private const val FEATURE_CUSTOM_LAUNCHER = "com.google.android.tv.custom_launcher"
private const val FEATURE_AMATI_EXPERIENCE = "com.google.android.feature.AMATI_EXPERIENCE"
private const val FEATURE_TV = "android.hardware.type.television"
@TvDeviceType
fun PackageManager.obtainDeviceType(): Int {
return when {
hasSystemFeature(PackageManager.FEATURE_LEANBACK) -> {
if (hasSystemFeature(FEATURE_OPERATOR_TIER)) {
if (hasSystemFeature(FEATURE_CUSTOM_LAUNCHER)) ANDROID_TV_OPERATOR_DEVICE_WITH_CUSTOM_LAUNCHER
else ANDROID_TV_OPERATOR_DEVICE
} else {
when {
hasSystemFeature(FEATURE_AMATI_EXPERIENCE) &&
getDefaultLauncher() == PACKAGE_LAUNCHER_X -> GOOGLE_TV
Build.VERSION.SDK_INT >= Build.VERSION_CODES.O &&
getDefaultLauncher() == PACKAGE_WATSON_LAUNCHER -> ANDROID_TV_WITH_WATSON
getDefaultLauncher() == PACKAGE_LEANBACK_LAUNCHER -> ANDROID_TV
else -> ANDROID_OTHER_TV
}
}
}
hasSystemFeature(FEATURE_TV) -> ANDROID_OTHER_TV
else -> ANDROID_NON_TV
}
}
@SuppressLint("QueryPermissionsNeeded")
fun PackageManager.hasPackageInstalled(packageName: String): Boolean {
return getInstalledApplications(0)
.find { it.packageName == packageName } != null
}
fun PackageManager.getDefaultLauncher(): String? {
val intent = Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME).addCategory(Intent.CATEGORY_DEFAULT)
val resolveInfo = resolveActivity(intent, 0)
return resolveInfo?.activityInfo?.packageName
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment