Cómo controlar hardware de TV

El hardware de TV es muy diferente de otros dispositivos Android. Las TVs no incluyen algunas de las funciones de hardware que se encuentran en otros dispositivos Android, como pantallas táctiles, cámaras y receptores GPS. Las TVs también dependen por completo de dispositivos de hardware secundarios: para que los usuarios interactúen con las apps para TVs, deben usar un control remoto o un control de juegos. (Para obtener información sobre los distintos métodos de entrada, consulta Cómo administrar controles de TV).

Cuando crees una app para TV, considera cuidadosamente las limitaciones y los requisitos de hardware para funcionar en hardware de TV. Verifica si tu app se ejecuta en una TV y controla las funciones de hardware no compatibles.

Cómo buscar un dispositivo de TV

Si estás creando una app que funciona tanto en dispositivos de TV como en otros dispositivos, es posible que debas verificar en qué tipo de dispositivo se ejecuta tu app y ajustar su funcionamiento. Por ejemplo, si tienes una app que se puede iniciar a través de un Intent, verifica las propiedades del dispositivo para determinar si se debe iniciar una actividad orientada a la TV o una actividad de teléfono.

La forma recomendada de determinar si tu app se ejecuta en un dispositivo de TV es usar el método PackageManager.hasSystemFeature para verificar si el dispositivo se ejecuta en modo de televisión. En el siguiente código de ejemplo, se muestra cómo verificar si tu app se ejecuta en un dispositivo de TV:

Kotlin

const val TAG = "DeviceTypeRuntimeCheck"

val isTelevision = packageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK)
if (isTelevision) {
    Log.d(TAG, "Running on a TV Device")
} else {
    Log.d(TAG, "Running on a non-TV Device")
}

Java

public static final String TAG = "DeviceTypeRuntimeCheck";

boolean isTelevision = getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK);
if (isTelevision) {
    Log.d(TAG, "Running on a TV Device");
} else {
    Log.d(TAG, "Running on a non-TV Device");
}

Cómo manejar las funciones de hardware no compatibles

Según el diseño y la funcionalidad de tu app, es posible que puedas solucionar el problema de que algunas funciones de hardware no estén disponibles. En esta sección, se analizan las funciones de hardware que, por lo general, no están disponibles para TV, cómo detectar las funciones de hardware faltantes y qué alternativas se sugieren para estas funciones.

Funciones no compatibles para hardware de TV

Las TVs tienen un propósito diferente al de otros dispositivos, por lo que no tienen las funciones de hardware que suelen tener otros dispositivos con Android. Por este motivo, el sistema Android no admite las siguientes funciones para un dispositivo de TV:

Hardware Descriptor de funciones de Android
Pantalla táctil android.hardware.touchscreen
Emulador de pantalla táctil android.hardware.faketouch
Telefonía android.hardware.telephony
Cámara android.hardware.camera
Comunicación de campo cercano (NFC) android.hardware.nfc
GPS android.hardware.location.gps
Micrófono android.hardware.microphone
Sensores android.hardware.sensor
Pantalla en orientación vertical android.hardware.screen.portrait

Nota: Algunos controles de TV tienen un micrófono, que no es lo mismo que la función de hardware del micrófono que se describe aquí. El micrófono del control es totalmente compatible.

Consulta la referencia de funciones para obtener una lista completa de las funciones, las funciones secundarias y sus descriptores.

Declara los requisitos de hardware para TV

Las apps para Android pueden declarar requisitos de funciones de hardware en el manifiesto de la app para garantizar que no se instalen en dispositivos que no proporcionen esas funciones. Si extiendes una app existente para usarla en TV, revisa detenidamente el manifiesto de la app para ver si hay declaraciones de requisitos de hardware que puedan impedir que se instale en un dispositivo de TV.

Si tu app usa funciones de hardware, como una pantalla táctil o una cámara, que no están disponibles en una TV, pero puede funcionar sin ellas, modifica el manifiesto de la app para indicar que no son obligatorias. En el siguiente fragmento de código de manifiesto, se muestra cómo declarar que tu app no requiere funciones de hardware que no están disponibles en dispositivos de TV, pero que usa esas funciones en dispositivos que no son de TV:

<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"/>
<!-- Some TV devices have an ethernet connection only -->
<uses-feature android:name="android.hardware.wifi"
        android:required="false"/>

Nota: Algunas funciones tienen subfunciones, como android.hardware.camera.front, como se describe en la referencia de funciones. Asegúrate de marcar como required="false" las subfunciones que también se usan en tu app.

Todas las apps diseñadas para usarse en dispositivos de TV deben declarar que la función de pantalla táctil no es obligatoria, como se describe en Cómo comenzar a usar apps para TVs. Si tu app suele usar una o más de las funciones que no son compatibles con los dispositivos de TV, cambia el parámetro de configuración del atributo android:required a false para esas funciones en tu manifiesto.

Precaución: Si declaras una función de hardware como obligatoria estableciendo su valor en true, tu app no se podrá instalar en dispositivos de TV ni aparecerá en el selector de la pantalla principal de Android TV.

Ten en cuenta los permisos que implican funciones de hardware

Algunas declaraciones del manifiesto uses-permission implican funciones de hardware. Este comportamiento significa que solicitar algunos permisos en el manifiesto de la app puede excluirla de la instalación y el uso en dispositivos de TV. Los siguientes permisos que se solicitan con frecuencia crean un requisito implícito de función de hardware:

Permiso Función implícita de hardware
RECORD_AUDIO android.hardware.microphone
CAMERA android.hardware.camera y
android.hardware.camera.autofocus
ACCESS_COARSE_LOCATION

android.hardware.location

android.hardware.location.network (solo para el nivel de API objetivo 20 o inferior)

ACCESS_FINE_LOCATION

android.hardware.location

android.hardware.location.gps (solo para el nivel de API objetivo 20 o inferior)

ACCESS_WIFI_STATE
CHANGE_WIFI_STATE

android.hardware.wifi

Algunos dispositivos de TV solo tienen conexión Ethernet.

Para obtener una lista completa de las solicitudes de permiso que implican un requisito de función de hardware, consulta la guía de uses-feature. Si tu app solicita una de las funciones mencionadas anteriormente, incluye una declaración uses-feature en tu manifiesto para la función de hardware implícita que indique que no es obligatoria. android:required="false".

Nota: Si tu app se orienta a Android 5.0 (nivel de API 21) o versiones posteriores, y usa el permiso ACCESS_COARSE_LOCATION o ACCESS_FINE_LOCATION, los usuarios podrán instalarla en un dispositivo de TV, incluso si este no tiene una tarjeta de red o un receptor de GPS.

Después de hacer que las funciones de hardware sean opcionales para tu app, debes verificar la disponibilidad de esas funciones durante el tiempo de ejecución y, luego, ajustar el comportamiento de la app. En la siguiente sección, se analiza cómo verificar las funciones de hardware y se sugieren algunos enfoques para cambiar el comportamiento de tu app.

Para obtener más información sobre cómo filtrar y declarar funciones en el manifiesto, consulta la guía de uses-feature.

Cómo buscar funciones de hardware

El framework de Android puede indicarte si las funciones de hardware no están disponibles en el dispositivo en el que se ejecuta tu app. Usa el método hasSystemFeature(String) para verificar si hay funciones específicas durante el tiempo de ejecución. Este método toma un solo argumento de cadena que especifica la función que deseas verificar.

En el siguiente ejemplo de código, se muestra cómo detectar la disponibilidad de las funciones de hardware durante el tiempo de ejecución:

Kotlin

// Check whether the telephony hardware feature is available.
if (packageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
    Log.d("HardwareFeatureTest", "Device can make phone calls")
}

// Check whether android.hardware.touchscreen feature is available.
if (packageManager.hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN)) {
    Log.d("HardwareFeatureTest", "Device has a touchscreen.")
}

Java

// Check whether the telephony hardware feature is available.
if (getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
    Log.d("HardwareFeatureTest", "Device can make phone calls");
}

// Check whether android.hardware.touchscreen feature is available.
if (getPackageManager().hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN)) {
    Log.d("HardwareFeatureTest", "Device has a touchscreen.");
}

Pantalla táctil

La mayoría de los dispositivos de TV no tienen pantallas táctiles ni capacidades de entrada de puntero, y dependen por completo de los controles remotos con pad direccional (D-pad) para la navegación. Las apps para TVs siempre deben admitir un control remoto con pad direccional.

Para obtener más información sobre cómo admitir correctamente la navegación con controles compatibles con la TV, consulta Navegación en TV.

Cómo declarar la compatibilidad táctil

Algunos dispositivos de TV admiten controles remotos con puntero y pantallas táctiles. Tu app puede admitir interacciones de clic, desplazamiento y desplazamiento, como en un dispositivo móvil, para brindar una mejor experiencia en los dispositivos que las admiten.

Si tu app permite el modo táctil, puedes declarar la compatibilidad con la función táctil para toda la app o para actividades individuales agregando el elemento android.software.leanback.supports_touch <property> establecido en true dentro del elemento <application> o <activity> en tu AndroidManifest.xml:

<application ...>
    <property
        android:name="android.software.leanback.supports_touch"
        android:value="true|false" />
    ...
</application>

Nota: En los dispositivos que admiten un control remoto de puntero (como un mouse inalámbrico o un panel táctil), habilitar esta opción activa el modo de cursor y táctil en lugar de depender de la emulación de compatibilidad de la plataforma. Una declaración a nivel de la actividad anula la declaración a nivel de la aplicación para esa actividad. Si se omite esta propiedad, el valor predeterminado es false.

Cámara

Aunque una TV no suele tener cámara, puedes proporcionar una app relacionada con la fotografía en una TV. Por ejemplo, si tienes una app que toma, muestra y edita fotos, puedes inhabilitar la función de tomar fotos para TVs y permitir que los usuarios vean y editen fotos. Si decides habilitar tu app relacionada con la cámara para que funcione en una TV, agrega la siguiente declaración de función al manifiesto de la app:

<uses-feature android:name="android.hardware.camera" android:required="false" />

Si habilitas tu app para que se ejecute sin una cámara, agrega código a tu app que detecte si la función de cámara está disponible y realice ajustes en el funcionamiento de tu app. En el siguiente ejemplo de código, se muestra cómo detectar la presencia de una cámara:

Kotlin

// Check whether the camera hardware feature is available.
if (packageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA)) {
    Log.d("Camera test", "Camera available!")
} else {
    Log.d("Camera test", "No camera available. View and edit features only.")
}

Java

// Check whether the camera hardware feature is available.
if (getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)) {
    Log.d("Camera test", "Camera available!");
} else {
    Log.d("Camera test", "No camera available. View and edit features only.");
}

GPS

Las TVs son dispositivos fijos para interiores y no tienen receptores de sistema de posicionamiento global (GPS) integrados. Si tu app usa información de ubicación, puedes permitir que los usuarios busquen una ubicación o usen un proveedor de ubicación estático, como un código postal configurado durante la configuración del dispositivo de TV.

Kotlin

// Request a static location from the location manager.
val locationManager = this.getSystemService(Context.LOCATION_SERVICE) as LocationManager
val location = locationManager.getLastKnownLocation("static")
if (location == null) {
    Log.e(TAG, "Location is null")
    return
}

// Attempt to get postal code from the static location object.
val geocoder = Geocoder(this)
val address: Address? =
        try {
            geocoder.getFromLocation(location.latitude, location.longitude, 1)?.firstOrNull()
                    ?.apply {
                        Log.d(TAG, postalCode)
                    }
        } catch (e: IOException) {
            Log.e(TAG, "Geocoder error", e)
            null
        }

Java

// Request a static location from the location manager.
LocationManager locationManager = (LocationManager) this.getSystemService(
        Context.LOCATION_SERVICE);
Location location = locationManager.getLastKnownLocation("static");

// Attempt to get postal code from the static location object.
Geocoder geocoder = new Geocoder(this);
Address address = null;
try {
  address = geocoder.getFromLocation(location.getLatitude(),
          location.getLongitude(), 1).get(0);
  Log.d("Postal code", address.getPostalCode());

} catch (IOException e) {
  Log.e(TAG, "Geocoder error", e);
}

Cómo pausar la reproducción durante el modo de bajo consumo

Algunos dispositivos de TV admiten un modo de bajo consumo cuando el usuario apaga el dispositivo. En lugar de apagarse, el dispositivo inhabilita la pantalla y mantiene Android TV en ejecución en segundo plano. La salida de audio sigue habilitada en este modo, por lo que debes detener cualquier contenido que se esté reproduciendo cuando el dispositivo esté en modo de bajo consumo.

Para evitar la reproducción durante el modo de bajo consumo, anula onStop y detén cualquier contenido que se esté reproduciendo:

Kotlin

override fun onStop() {
    // App-specific method to stop playback.
    stopPlayback()
    super.onStop()
}

Java

@Override
public void onStop() {
  // App-specific method to stop playback.
  stopPlayback();
  super.onStop();
}

Cuando el usuario vuelve a encender el dispositivo, se llama a onStart si tu app es la que está activa en primer plano. Para obtener más información sobre cómo iniciar y detener una actividad, consulta El ciclo de vida de la actividad.