Codelab de la API de sueño para Android

Qué compilarás

En este codelab, compilarás una app para Android que detecta el tiempo de sueño del usuario. La app hará lo siguiente:

  • Solicitará permisos
  • Registrará la API de sueño para Android
  • Recuperará los eventos de la API y los mostrará en la IU
  • Cancelará el registro cuando ya no sea necesario

Requisitos

  • Una versión reciente de Android Studio con la versión v21 de las herramientas de compilación de Android o una posterior
  • Un dispositivo con Android 10 (nivel 29 de API) o versiones posteriores

Clona el repositorio del proyecto inicial

A fin de que comiences lo antes posible, preparamos un proyecto inicial sobre el cual puedes compilar. Para verificar si tienes git, escribe git --version en la terminal o línea de comandos: Si no está instalado, sigue estas instrucciones para hacerlo. Luego, simplemente puedes ejecutar el siguiente comando para clonar el proyecto.

 git clone https://github.com/googlecodelabs/android-sleep/

Importa el proyecto

Inicia Android Studio, selecciona "Open an existing Android Studio project" en la pantalla de bienvenida y abre el directorio del proyecto.

Después de que se cargue el proyecto, es posible que aparezca una alerta que indique que Git no está realizando un seguimiento de todos los cambios locales. Puedes hacer clic en "Ignore" o en la "X" en la parte superior derecha. (No enviarás ningún cambio al repositorio de Git).

En la esquina superior izquierda de la ventana del proyecto, deberías ver una imagen similar a la que se muestra más abajo si estás en la vista Android. (Si estás en la vista Project, deberás expandir el proyecto para ver lo mismo).

1401a11c10711a60.png

Observarás dos íconos de carpeta (start y complete). Cada uno se conoce como "módulo".

Ten en cuenta que Android Studio puede tardar varios segundos la primera vez que compile el proyecto en segundo plano. Durante este período, verás un ícono giratorio en la barra de estado, en la parte inferior de Android Studio:

4bc64eb3b99eb0ae.png

Te recomendamos que esperes hasta que haya finalizado antes de realizar cambios en el código. De esa manera, Android Studio podrá extraer todos los componentes necesarios.

Además, si recibes el mensaje "Reload for language changes to take effect?", o uno similar, selecciona "Yes".

Comprende el proyecto inicial

Ya está todo listo y configurado para que agregues el reconocimiento de actividad. Utilizaremos el módulo start, que es el punto de partida de este codelab. En otras palabras, agregarás a start el código de cada paso.

El módulo complete se puede usar para verificar tu trabajo o para usarlo como referencia si encuentras algún problema.

Descripción general de los componentes clave:

  • MainActivity.kt: Renderiza la pantalla principal de la app cuando la inicia el usuario.
  • SleepReceiver.kt: Extrae los eventos de sueño de la API y los almacena en la base de datos.
  • BootReceiver.kt: Vuelve a registrarse en la API de sueño cuando se completa el inicio del dispositivo para continuar detectando los eventos de la API de sueño.

Ejecuta el proyecto inicial

Ejecutemos nuestra app.

  1. Conecta tu dispositivo Android a tu computadora.
  2. En la barra de herramientas, selecciona la configuración start en el selector desplegable, elige el dispositivo y, luego, haz clic en el botón triangular verde (Run) que está a un lado:

177045a302bf57d8.png

En el dispositivo, deberías ver la aplicación:

30efe28b9757e1e7.png

311c83ca64556d94.png

En realidad, todavía no agregamos ningún fragmento de código para hacer un seguimiento del sueño, pero lo haremos en las siguientes secciones.

En la próxima sección, verificaremos la biblioteca y los permisos necesarios.

Verifica build.gradle y AndroidManifest.xml

Para usar la API de sueño en tu app, debes declarar una dependencia a la API de ubicación y reconocimiento de actividad de Google, y especificar el permiso com.google.android.gms.permission.ACTIVITY_RECOGNITION en el manifiesto de la app.

  1. Busca el comentario TODO: Review play services library required for activity recognition en el archivo build.gradle para el módulo start. En este paso, no se requiere ninguna acción. Solo debes verificar la dependencia declarada que necesitamos. Debe tener el siguiente aspecto:
    // TODO: Review play services library required for activity recognition.
    implementation 'com.google.android.gms:play-services-location:18.0.0'
  1. En el módulo start, busca el comentario TODO: Add activity recognition and boot complete permissions en el objeto AndroidManifest.xml y agrega el siguiente código al elemento <manifest>.
<!-- TODO: Add activity recognition and receive boot complete permissions. -->
<!-- Required for 29+. -->
<uses-permission android:name="android.permission.ACTIVITY_RECOGNITION" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

Ahora, el código debería ser similar al siguiente:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
         package="com.android.example.sleepcodelab">
...
<!-- TODO: Add activity recognition and receive boot complete permissions. -->
<!-- Required for 29+. -->
<uses-permission android:name="android.permission.ACTIVITY_RECOGNITION" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
  ...
</manifest>

Como puedes observar en los comentarios, debes agregar el permiso de tiempo de ejecución para la versión 29 de la API.

Eso es todo. Ahora, tu app puede admitir el reconocimiento de actividad de sueño. Solo debemos agregar el código para obtenerlo.

Revisa la verificación de permisos del reconocimiento de actividad

Debemos verificar y solicitar los permisos de tiempo de ejecución si es necesario:

  • En el elemento MainActivity.kt, verificaremos los permisos de reconocimiento de actividad.
  • Si no se otorgan los permisos, llamaremos a displayPermissionSettingsSnackBar(). Esta barra de notificaciones explica las necesidades del permiso y permite que los usuarios lo aprueben en la configuración del sistema.

En el módulo start, busca el comentario TODO: Review Activity Recognition permission check en MainActivity.kt. Deberías ver el siguiente fragmento de código.

Ten en cuenta que, en esta sección, no se requiere ninguna acción.

// TODO: Review Activity Recognition permission checking.
private fun activityRecognitionPermissionApproved(): Boolean {
   return PackageManager.PERMISSION_GRANTED == ActivityCompat.checkSelfPermission(
           this,
           Manifest.permission.ACTIVITY_RECOGNITION
   );
}

Habilita o inhabilita el seguimiento del sueño.

En el módulo start, busca el comentario TODO: Enable/Disable Sleep tracking and ask for permissions if needed en MainActivity.kt. Reemplaza el método onClickRequestSleepData() por el siguiente código.

// TODO: Enable/Disable sleep tracking and ask for permissions if needed.
fun onClickRequestSleepData(view: View) {
   if (activityRecognitionPermissionApproved()) {
       if (subscribedToSleepData) {
           unsubscribeToSleepSegmentUpdates(applicationContext, sleepPendingIntent)
       } else {
           subscribeToSleepSegmentUpdates(applicationContext, sleepPendingIntent)
       }
   } else {
       requestPermissionLauncher.launch(permission.ACTIVITY_RECOGNITION)
   }
}

Si se aprueba el permiso del reconocimiento de actividad y si el usuario se suscribió a los datos de sueño, nos suscribiremos a las actualizaciones del sueño. De lo contrario, anulamos la suscripción.

En caso de que no se apruebe el permiso, le enviaremos al usuario a la actividad de la pantalla de presentación que en la que se explica por qué lo necesitamos y le permitiremos que lo habilite.

Crea un elemento PendingIntent

En el módulo start, busca el comentario TODO: Create a PendingIntent for Sleep API events en MainActivity.kt. Pega el siguiente fragmento.

// TODO: Create a PendingIntent for Sleep API events
sleepPendingIntent =
   SleepReceiver.createSleepReceiverPendingIntent(context = applicationContext)

Ahora, podemos recibir actualizaciones cuando estén disponibles los datos de la API de sueño.

Solicita actualizaciones de la API de sueño

En el módulo start, busca el comentario TODO: Request Sleep API update en MainActivity.kt. Pega el siguiente fragmento.

// TODO: Request Sleep API updates
val task = ActivityRecognition.getClient(context).requestSleepSegmentUpdates(
   pendingIntent,
   // Registers for both SleepSegmentEvent and SleepClassifyEvent data.
   SleepSegmentRequest.getDefaultSleepSegmentRequest()
)

task.addOnSuccessListener {
   mainViewModel.updateSubscribedToSleepData(true)
   Log.d(TAG, "Successfully subscribed to sleep data.")
}
task.addOnFailureListener { exception ->
   Log.d(TAG, "Exception when subscribing to sleep data: $exception")
}

Después de registrar, con éxito, las actualizaciones de la API de sueño, tu app recibirá notificaciones de detección de sueño en el elemento PendingIntent registrado.

Vuelve a suscribirte cuando se complete el inicio

En el módulo start, busca el comentario TODO: Request Sleep API upon boot complete en receiver/BootReceiver.kt. Pega el siguiente fragmento.

// TODO: Request Sleep API upon boot complete
val subscribedToSleepData = repository.subscribedToSleepDataFlow.first()
if (subscribedToSleepData) {
   subscribeToSleepSegmentUpdates(
       context = context,
       pendingIntent = SleepReceiver.createSleepReceiverPendingIntent(context)
   )
}

El código permitirá que la app continúe recibiendo actualizaciones de la API de sueño después de reiniciar el dispositivo.

Cuando se produce una clasificación del sueño o un evento de detección del tiempo de sueño, la app recibe una devolución de llamada de Intent. Del intent, se puede extraer una lista de objetos SleepSegmentEvent o SleepClassifyEvent.

Agreguemos el código para controlar esos eventos.

En el módulo start, busca el comentario TODO: Extract sleep information from PendingIntent en receiver/SleepReceiver.kt. Agrega el siguiente código después del comentario.

// TODO: Extract sleep information from PendingIntent.
if (SleepSegmentEvent.hasEvents(intent)) {
   val sleepSegmentEvents: List<SleepSegmentEvent> =
       SleepSegmentEvent.extractEvents(intent)
   addSleepSegmentEventsToDatabase(repository, sleepSegmentEvents)
} else if (SleepClassifyEvent.hasEvents(intent)) {
   val sleepClassifyEvents: List<SleepClassifyEvent> =
       SleepClassifyEvent.extractEvents(intent)
   addSleepClassifyEventsToDatabase(repository, sleepClassifyEvents)
}

De esta manera, se guardarán los datos de SleepSegmentEvent o SleepClassifyEvent en una base de datos de Room. El elemento MainActivity accede a la información de esa base de datos a través de un objeto ViewModel con LiveData. Para obtener más información sobre cómo funcionan estas clases en conjunto, consulta el codelab sobre Room con una View.

Eso es todo. ¡Terminaste! Prueba ejecutar la app.

Conecta tu dispositivo a la estación de trabajo con un cable. En Android Studio, haz clic en "Run" para instalar y ejecutar la app en tu dispositivo. Después de otorgar el permiso del reconocimiento de actividad y presionar el botón SUBSCRIBE TO SLEEP DATA, el primer elemento SleepClassifyEvent debería aparecer después de 10 minutos aproximadamente. SleepSegmentEvent debería aparecer en el plazo de un día.

No dudes en leer el código completo para repasar lo que hiciste y obtener una mejor idea de cómo funciona el código.

Revisiones opcionales del código

Las siguientes revisiones del código son opcionales. Brindan detalles sobre la asignación de datos entre la API de sueño y las entidades de la base de datos:

  • data/db/SleepClassifyEventEntity.kt
  • data/db/SleepSegmentEventEntity.kt

Documentos de referencia