The Android Developer Challenge is back! Submit your idea before December 2.

Cómo controlar hardware de TV

El hardware de TV es muy diferente de otros dispositivos Android. Las TV no incluyen algunas de las funciones de hardware que se encuentran en otros dispositivos Android, como pantallas táctiles, cámaras y receptores de GPS. Además, las TV dependen por completo de dispositivos de hardware secundarios. Para que los usuarios puedan interactuar con aplicaciones para TV, deben usar un control remoto o un controlador para juegos. Cuando creas una app para TV, debes prestar mucha atención a las limitaciones y a los requisitos de hardware para que pueda ejecutarse en hardware de TV.

En esta lección, se muestra cómo verificar si tu app se está ejecutando en una TV y qué hacer con las funciones de hardware no compatibles. Para obtener información sobre los distintos métodos de entrada, consulta Cómo administrar controladores de TV.

Cómo buscar un dispositivo de TV

Si estás creando una app para que se ejecute en dispositivos de TV y otros dispositivos, es posible que debas verificar en qué tipo de dispositivo se está ejecutando y ajustar su funcionamiento. Por ejemplo, si tienes una app que puede iniciarse mediante un Intent, esta debe verificar las propiedades del dispositivo para determinar si debe iniciar una actividad orientada a una TV o a un teléfono.

La práctica recomendada para determinar si tu app se ejecuta en un dispositivo de TV es usar el método UiModeManager.getCurrentModeType() a fin de verificar si el dispositivo se ejecuta en modo de TV. En el siguiente ejemplo de código, se muestra cómo comprobar si tu app se ejecuta en un dispositivo de TV:

Kotlin

    const val TAG = "DeviceTypeRuntimeCheck"

    val uiModeManager = getSystemService(UI_MODE_SERVICE) as UiModeManager
    if (uiModeManager.currentModeType == Configuration.UI_MODE_TYPE_TELEVISION) {
        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";

    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");
    }
    

Cómo manejar las funciones de hardware no compatibles

Según el diseño y la funcionalidad de tu app, es posible que puedas evitar el problema de que ciertas funciones de hardware no estén disponibles. En esta sección, se explica cuáles son las funciones de hardware que no suelen estar disponibles para TV, cómo detectar funciones de hardware faltantes, y se sugieren alternativas para estas funciones.

Funciones no compatibles para hardware de TV

Las TV tienen un propósito diferente al de otros dispositivos y, por lo tanto, no suelen tener las mismas funciones de hardware que otros dispositivos 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[1] android.hardware.microphone
Sensores android.hardware.sensor
Pantalla en orientación vertical android.hardware.screen.portrait

[1] Algunos controladores de TV tienen un micrófono, que no es el mismo que el de la función de hardware de micrófono que se describe aquí. El micrófono del controlador es completamente compatible.

Consulta la Referencia de funciones para obtener una lista completa de las funciones, las subfunciones y sus descriptores.

Cómo declarar requisitos de hardware para TV

Las apps de Android pueden declarar requisitos de funciones de hardware en el manifiesto de la app para garantizar que no se instalen en dispositivos que no poseen tales funciones. Si quieres expandir una app existente para que se use en TV, busca en el manifiesto de tu app 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 cámara) que no están disponibles en una TV, pero puede funcionar sin ellas, deberás modificar el manifiesto de tu app para indicar que no requiere estas funciones. En el siguiente ejemplo de código del manifiesto, se muestra cómo declarar que tu app no requiere funciones de hardware que no están disponibles en dispositivos de TV, incluso si las usa en otros dispositivos:

    <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"/>
    

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" todas las subfunciones que también se usen en tu app.

Todas las apps creadas 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 con apps para TV. Si tu app por lo general usa una o varias de las funciones que se mencionan más arriba, cambia la configuración del atributo android:required a false en tu manifiesto.

Precaución: Si declaras una función de hardware mediante la definición de true, evitarás que tu app se instale en dispositivos de TV o que aparezca en el selector de la pantalla principal de Android TV.

Si decides que las funciones de hardware son opcionales para tu app, deberás comprobar la disponibilidad de aquellas funciones durante el tiempo de ejecución y, luego, ajustar el comportamiento de tu app. En la siguiente sección, se explica cómo buscar 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 declarar permisos que llevan funciones de hardware implícitas

Algunas declaraciones del manifiesto uses-permission implican funciones del hardware. Este comportamiento supone que solicitar ciertos permisos en el manifiesto de tu app puede impedir que esta se instale y use en dispositivos de TV. Los siguientes permisos comúnmente solicitados crean un requisito implícito de funciones 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 (se orienta al nivel de API 20 o versiones anteriores únicamente)

ACCESS_FINE_LOCATION

android.hardware.location

android.hardware.location.gps (se orienta al nivel de API 20 o versiones anteriores únicamente)

Para obtener una lista completa de solicitudes de permisos que suponen un requisito de función implícita de hardware, consulta la guía de uses-feature. Si tu app solicita una de las funciones mencionadas anteriormente, deberás incluir una declaración uses-feature en tu manifiesto para la función de hardware implícita que indica que no es obligatoria (android:required="false").

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

Cómo buscar funciones de hardware

El marco de trabajo de Android puede indicarte si hay funciones de hardware no disponibles en el dispositivo en el que se ejecuta tu app. Usa el método hasSystemFeature(String) para buscar funciones específicas durante el tiempo de ejecución. Este método toma un único argumento de string que especifica la función que quieres buscar.

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

Kotlin

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

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

Java

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

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

Pantalla táctil

Como la mayoría de las TV no tienen pantalla táctil, Android no admite interacciones de este tipo para dispositivos de TV. Además, el uso de una pantalla táctil no es coherente con un entorno visual en el cual el usuario está sentado a 3 metros de la pantalla. Asegúrate de que tus elementos de IU y texto no requieran o impliquen el uso de una pantalla táctil.

En el caso de dispositivos de TV, deberías diseñar tu app para que funcione con este modelo de interacción: agrega compatibilidad con la navegación mediante un mando de dirección (pad direccional) en un control remoto para TV. Para obtener más información sobre cómo admitir la navegación mediante controles compatibles con la TV, consulta Cómo desarrollar la navegación para TV.

Cámara

Si bien las TV no suelen tener cámara, puedes proporcionar una app relacionada con la fotografía en una TV. Por ejemplo, si tienes una app cuya función es tomar, ver y editar fotos, puedes inhabilitar la funcionalidad de toma de fotos para la TV, pero permitir que los usuarios las vean y editen. Si decides permitir que tu app relacionada con la cámara funcione en una TV, agrega la siguiente declaración de función en el manifiesto de tu app:

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

Si permites que tu app se ejecute sin una cámara, deberás agregarle código para que detecte si la función de cámara está disponible y ajustar 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 if 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 if 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 TV son dispositivos fijos, de interior y no tienen receptores integrados de sistema de posicionamiento global (GPS). Si tu app usa información de ubicación, igualmente puedes permitir que los usuarios busquen una ubicación o usen un proveedor de ubicación estática, como un código postal que se ingresa durante la configuración inicial de dispositivo de TV.

Kotlin

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

    // Attempt to get postal or zip code from the static location object
    val geocoder = Geocoder(this)
    val address: Address? =
            try {
                geocoder.getFromLocation(location.latitude, location.longitude, 1)[0]
                        .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 or zip 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("Zip 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 el modo de bajo consumo cuando el usuario apaga el dispositivo. En lugar de apagarse, el dispositivo inhabilita la pantalla y sigue ejecutando Android TV en segundo plano. La salida de audio permanece habilitada en este modo, por lo que la app debería detener cualquier contenido que se esté reproduciendo cuando se activa el modo de bajo consumo.

Para evitar que se reproduzca contenido durante el modo de bajo consumo, debes anular la función onStop() y detener la reproducción:

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 encenderlo, si tu app es la app que está activa en primer plano, se llama a onStart(). Para obtener más información sobre cómo iniciar y detener una actividad, consulta El ciclo de vida de una actividad.