Uso de las notificaciones de Android

Este codelab es parte del curso Aspectos avanzados de Android en Kotlin. Aprovecharás al máximo este curso si trabajas con los codelabs de forma secuencial, aunque no es obligatorio. Todos los codelabs del curso se indican en la página de destino de los codelabs de Aspectos avanzados de Android en Kotlin.

Introducción

Las notificaciones son mensajes que se muestran al usuario fuera de la IU de tu app. Las notificaciones se muestran en la parte superior de la pantalla si el dispositivo está desbloqueado o, según la configuración de seguridad, en la pantalla de bloqueo cuando el dispositivo está bloqueado.

Una notificación típica consta de un título, una descripción y un ícono. Las notificaciones también pueden tener acciones en las que se puede hacer clic, respuestas rápidas, contenido extensible e imágenes.

Las notificaciones pueden entregar material oportuno y tener botones para permitir que el usuario realice acciones rápidas, como enviar una respuesta o posponer una alarma. Cuando el usuario hace clic en una notificación, se lo dirige a una vista de tu app relacionada con el contenido de la notificación.

Las notificaciones son una forma útil de recordarles a los usuarios una tarea importante, informarles que ocurrió algo o comunicarles información importante que necesitan de inmediato mientras tu app se ejecuta en segundo plano. Usa las notificaciones con moderación. Esto no solo respeta a los usuarios, sino que también aumenta las probabilidades de que la notificación de tu app reciba la atención que merece.

En este codelab, aprenderás a crear y usar notificaciones en una app para Android.

Conocimientos que ya deberías tener

Debes estar familiarizado con lo siguiente:

  • Cómo crear apps para Android en Kotlin En particular, trabajar con el SDK de Android
  • Cómo diseñar apps con los componentes de arquitectura y la vinculación de datos
  • Conocimientos básicos sobre BroadcastReceivers
  • Conocimientos básicos sobre AlarmManager

Qué aprenderás

  • Cómo crear, diseñar y enviar una notificación
  • Cómo cancelar las notificaciones
  • Cómo crear canales de notificaciones
  • Cómo agregar acciones rápidas a las notificaciones
  • Cómo mostrar distintivos de notificaciones en el ícono de la app

Actividades

  • Agrega una notificación a la app de inicio.
  • Cancela la notificación que enviaste anteriormente.
  • Crea canales para diferentes tipos de notificaciones.
  • Personaliza las notificaciones en la app de inicio.
  • Agrega acciones rápidas para que tu notificación sea interactiva.
  • Desactiva los distintivos de notificaciones.

Cocinar huevos es sencillo, pero puede ser una tarea difícil si no controlas el tiempo. En este codelab, trabajarás en una app de temporizador de huevos y la perfeccionarás, al igual que tus futuros huevos. Comenzarás con una app de temporizador de huevos que funciona y que permite al usuario establecer diferentes parámetros de configuración de tiempo de cocción para diferentes estilos de huevos. El temporizador realiza una cuenta regresiva desde el intervalo de tiempo seleccionado y muestra un mensaje emergente cuando los huevos están listos.

Esto puede parecer funcional, pero está lejos de ser perfecto y no es muy fácil de usar. Para empezar, el mensaje emergente solo se muestra durante un breve período, por lo que es fácil pasarlo por alto. Además, si la app no está en primer plano o el dispositivo está bloqueado, no hay ningún indicador visual del estado del temporizador una vez que desaparece el mensaje emergente.

Lo ideal es que el temporizador de huevos use notificaciones para avisar a los usuarios cuando se acabe el tiempo. El usuario realmente necesita saber que los huevos están listos de inmediato, de lo contrario, se cocinarán demasiado. Las notificaciones son visuales, pueden incluir sonidos y hacer que el dispositivo vibre. Todas estas son formas de captar la atención del usuario. De esta manera, puedes lograr huevos perfectos y usuarios felices y bien alimentados.

Para obtener la app de ejemplo, puedes hacer lo siguiente:

Clona el repositorio desde GitHub y cambia a la rama starter.

$  git clone https://github.com/googlecodelabs/android-kotlin-notifications


También puedes descargar el repositorio como un archivo ZIP, descomprimirlo y abrirlo en Android Studio.

Download Zip

  1. Abre y ejecuta la app en Android Studio.

Verás una imagen de un huevo y un menú desplegable con una lista de intervalos de tiempo predefinidos para cocinar un huevo. Haz clic en el triángulo del menú desplegable Huevo pasado por agua. La primera opción de la lista se proporciona con fines de prueba y configura la alarma en solo 10 segundos. Junto a la lista, hay un interruptor que inicia el temporizador de huevos. Puedes usar este interruptor para iniciar y detener el temporizador de huevos cuando quieras. El código de partida es completamente funcional, lo que significa que puedes configurar el temporizador de huevos y ver cómo hace la cuenta regresiva hasta 0. Una vez que finaliza el temporizador, se muestra un mensaje emergente, como se muestra a continuación.

  1. Inspecciona el código fuente. La app de inicio consta de una sola actividad llamada MainActivity. Hay tres paquetes secundarios llamados receiver, ui y util.

  • /receiver: El paquete receiver contiene dos receptores de transmisiones llamados AlarmReceiver y SnoozeReceiver. AlarmReceiver se activa con AlarmManager para enviar la notificación cuando finaliza el temporizador definido por el usuario. SnoozeReceiver controla el clic del usuario para posponer la notificación.
  • /ui: Contiene el EggTimerFragment, que forma parte de la porción de la IU de la app. EggTimerViewModel es responsable de iniciar y cancelar el temporizador, y de otras tareas de la app relacionadas con el ciclo de vida.
  • /util: En este paquete, hay dos archivos. BindingUtils.kt tiene adaptadores de vinculación para habilitar la vinculación de datos entre la IU de la app y el elemento ViewModel. NotificationUtils.kt tiene métodos de extensión en NotificationManager.

Usar notificaciones es una excelente manera de llamar la atención de los usuarios hacia tu app. Ya sea que tu app no se esté ejecutando o se esté ejecutando en primer plano, una notificación mostrará una ventana emergente en la parte superior de la pantalla y puede incluir sonido o vibración. Para crear una notificación, debes usar un compilador de notificaciones y proporcionar un texto de título, un texto de contenido y un ícono. Una vez que el compilador tiene todos los campos necesarios, NotificationManager, que es un servicio del sistema, te ayuda a mostrar este contenido como una notificación. NotificationManager es responsable de enviar una notificación, actualizar su contenido y cancelar la notificación. En los siguientes pasos, agregarás métodos de extensión a NotificationManager. De esta manera, cada vez que necesites usar NotificationManager, podrás usar estas funciones de extensión para lograr la funcionalidad que necesitas.

Paso 1: Crea una notificación básica

En esta tarea, crearás una notificación nueva, establecerás un mensaje para el usuario y enviarás la notificación.

  1. Abre la clase NotificationUtils.kt y busca TODO: Step 1.1. Encontrarás coincidencias en este codelab y en el código de la app.
  2. Examina la función sendNotification() proporcionada. Extenderás esta función de extensión a NotificationManager para enviar notificaciones.
//NotificationUtils.kt
// TODO: Step 1.1 extension function to send messages (GIVEN)
/**
 * Builds and delivers a notification.
 *
 * @param messageBody, notification text.
 * @param context, activity context.
 */
fun NotificationManager.sendNotification(messageBody: String, applicationContext: Context) {
  1. Obtén una instancia del compilador de notificaciones, pasa el contexto de la app y un ID de canal. El ID del canal es un valor de cadena para el canal.

Los canales de notificaciones son una forma de agrupar las notificaciones. Al agrupar tipos de notificaciones similares, los desarrolladores y los usuarios pueden controlar todas las notificaciones del canal. Una vez que se crea un canal, se puede usar para enviar cualquier cantidad de notificaciones.

//NotificationUtils.kt
// TODO: Step 1.2 get an instance of NotificationCompat.Builder
val builder = NotificationCompat.Builder(
        applicationContext,
        applicationContext.getString(R.string.egg_notification_channel_id)
)
  1. Establece el ícono de notificación para representar tu app, un título y el texto de contenido del mensaje que deseas mostrarle al usuario. En el codelab, verás más opciones para personalizar aún más tu notificación, pero esta es la cantidad mínima de datos que debes configurar para enviar una notificación.
//NotificationUtils.kt
   // TODO: Step 1.3 set title, text and icon to builder
   .setSmallIcon(R.drawable.cooked_egg)
   .setContentTitle(applicationContext.getString(R.string.notification_title))
   .setContentText(messageBody)
  1. A continuación, debes llamar a notify() con un ID único para tu notificación y con el objeto Notification de tu compilador.

Este ID representa la instancia de notificación actual y es necesario para actualizar o cancelar esta notificación. Dado que tu app solo tendrá una notificación activa en un momento determinado, puedes usar el mismo ID para todas tus notificaciones. Ya se te proporcionó una constante para este propósito llamada NOTIFICATION_ID en NotificationUtils.kt. Ten en cuenta que puedes llamar a notify() directamente, ya que realizas la llamada desde una función de extensión en la misma clase.

//NotificationUtils.kt
   // TODO: Step 1.4 call notify to send the notification
    // Deliver the notification
    notify(NOTIFICATION_ID, builder.build())
  1. Abre ui/EggTimerViewModel.kt y busca la función startTimer(). Esta función crea una alarma con el intervalo de tiempo seleccionado cuando el usuario habilita el temporizador de huevos.
  2. En esta función, activarás una notificación cuando el usuario inicie el temporizador. Para llamar a la función sendNotification() que implementaste anteriormente, necesitas una instancia de NotificationManager. NotificationManager es un servicio del sistema que proporciona todas las funciones expuestas para la API de Notifications, incluida la función de extensión que agregaste. Cada vez que quieras enviar, cancelar o actualizar una notificación, debes solicitar una instancia de NotificationManager al sistema. Llama a la función sendNotification()| con el mensaje de notificación y con el contexto.
// EggTimerViewModel.kt
// TODO: Step 1.5 get an instance of NotificationManager 
// and call sendNotification

val notificationManager = ContextCompat.getSystemService(
    app, 
    NotificationManager::class.java
) as NotificationManager
                notificationManager.sendNotification(app.getString(R.string.timer_running), app)

Ya casi terminas. Sin embargo, si ejecutas la app ahora y configuras el temporizador, no recibirás una notificación.

  1. Abre logcat y busca "No Channel found". Deberías ver un mensaje de error que indica que egg_channel no existe. En los siguientes pasos, obtendrás más información sobre los canales de notificaciones y solucionarás este problema.

Paso 2: Canales de notificación

A partir del nivel de API 26, todas las notificaciones deben asignarse a un canal. Si mantienes presionado el ícono del selector de apps, seleccionas la información de la app y presionas Notificaciones, verás una lista de los canales de notificaciones asociados a la app. Por el momento, la lista está vacía porque tu app no creó ningún canal.

Los canales representan un "tipo" de notificación. Por ejemplo, el temporizador de huevos puede enviar una notificación cuando el huevo esté cocido y también usar otro canal para enviar notificaciones diarias que te recuerden que comas huevos en el desayuno. Todas las notificaciones de un canal se agrupan, y los usuarios pueden configurar los parámetros de configuración de las notificaciones para todo el canal. Esto permite que los usuarios personalicen la configuración de notificaciones según el tipo de notificación que les interese. Por ejemplo, los usuarios pueden inhabilitar las notificaciones del desayuno, pero seguir viendo las notificaciones del temporizador.

Los desarrolladores establecen la configuración inicial, la importancia y el comportamiento que se aplicarán a todas las notificaciones de un canal. Después de establecer la configuración inicial, los usuarios pueden anularla.

En el paso 1.1, usaste egg_notification_channel_id como tu canal de notificaciones, por lo que ahora debes crear y personalizar la configuración y el comportamiento de las notificaciones de este canal.

  1. Abre EggTimerFragment.kt y busca la función createChannel().
  2. Pasa el ID de canal único al constructor de NotificationChannel.
  3. Pasa el nombre del canal de notificación, que los usuarios también verán en la pantalla de Configuración.
  4. Como último parámetro, pasa el nivel de importancia del canal de notificación. Los niveles de importancia se tratarán más adelante en este codelab, por lo que, por ahora, puedes usar NotificationManager.IMPORTANCE_LOW.
  5. En el objeto notificationChannel, establece enableLights como verdadero. Este parámetro de configuración habilitará las luces cuando se muestre una notificación.
  6. En el objeto notificationChannel, establece lightColor en rojo para mostrar una luz roja cuando se muestre una notificación.
  7. En el objeto notificationChannel, establece enableVibration como verdadero para habilitar la vibración.
  8. En el objeto notificationChannel, establece la descripción del canal en ‘Time for breakfast".
  9. Para obtener una instancia de NotificationManager, llama a getSystemService().
  10. Llama a createNotificationChannel() en NotificationManager y pasa el objeto notificationChannel que creaste en el paso anterior.
//EggTimerFragment.kt
private fun createChannel(channelId: String, channelName: String) {
    // TODO: Step 1.6 START create a channel
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        val notificationChannel = NotificationChannel(
            channelId,
            channelName,
            // TODO: Step 2.4 change importance
            NotificationManager.IMPORTANCE_LOW
        )
        // TODO: Step 2.6 disable badges for this channel

        notificationChannel.enableLights(true)
        notificationChannel.lightColor = Color.RED
        notificationChannel.enableVibration(true)
        notificationChannel.description = "Time for breakfast"

        val notificationManager = requireActivity().getSystemService(
            NotificationManager::class.java
        )
        notificationManager.createNotificationChannel(notificationChannel)
    }
    // TODO: Step 1.6 END create channel
}
  1. A continuación, para crear un canal, debes llamar a la función createChannel() que acabas de escribir (paso 1.7). Esta función toma dos parámetros: el ID del canal y el nombre del canal. Debes buscar el ID y el nombre de tu canal en los recursos de cadena que ya se proporcionan en tu proyecto.
// EggTimerFragment.kt
    // TODO: Step 1.7 call createChannel
    createChannel(
          getString(R.string.egg_notification_channel_id),
          getString(R.string.egg_notification_channel_name)
    )
  1. Debes pasar el ID del canal al compilador de notificaciones. Ya lo hiciste en el paso 1.2. Si se establece un valor incorrecto como ID del canal, la notificación fallará. Abre NotificationUtils.kt para verificar que el ID del canal que configuraste anteriormente sea correcto.
// NotificationUtils.kt
val builder = NotificationCompat.Builder(
        applicationContext,
       // TODO: Step 1.8 verify the notification channel name
        applicationContext.getString(R.string.egg_notification_channel_id)
)
  1. Ejecuta la app y verás que envía una notificación cada vez que inicias el temporizador.
  2. Desliza la barra de estado y observa que el título, el contenido y el ícono de la notificación son los que configuraste en los pasos anteriores.
  3. Para verificar el canal recién creado, cierra la app y busca el ícono de la app. Mantén presionado el ícono de la app y selecciona Información de la app.

  1. Selecciona Notificaciones en la lista de parámetros de configuración. Deberías ver un nuevo canal llamado Huevo justo debajo del parámetro de configuración Mostrar notificaciones.

Cuando ejecutes la app, ahora se mostrará la notificación. Tanto tú, como desarrollador de la app, como tus usuarios pueden personalizar la configuración y el comportamiento de todas las notificaciones que se envían en este canal. ¡Felicitaciones! Creaste una notificación.

Paso 3: Agrega notificaciones a tu app

Hasta ahora, se muestra el uso básico de la API de Notifications, pero enviar una notificación justo después de iniciar el temporizador no tiene mucho sentido. Es probable que los usuarios prefieran recibir una notificación cuando el huevo esté listo. En la siguiente parte del codelab, corregirás este problema y cambiarás el mensaje Toast por una notificación.

Ya enviaste la notificación y observaste cómo se muestra a los usuarios, pero este fue solo el primer paso para crear notificaciones excelentes. En este paso, cambiarás la notificación para que se envíe en un momento más adecuado.

Tu app usa AlarmManager para configurar una alarma. El código relacionado con AlarmManager ya se proporciona en el código de partida y se usa para mostrar el mensaje de notificación. AlarmManager realiza un seguimiento de la selección de tiempo deseada y activará la función onReceive() de AlarmReceiver.kt cuando se acabe el tiempo. Si abres AlarmReceiver.kt y navegas a onReceive(), deberías ver el mensaje emergente que se muestra cada vez que configuras un temporizador de huevos.

  1. Abre AlarmReceiver.kt, una instancia de NotificationManager, y llama a la función sendNotification() con el texto del mensaje y los parámetros de contexto.
// AlarmReceiver.kt
   // TODO: Step 1.9 add call to sendNotification
   val notificationManager = ContextCompat.getSystemService(
       context, 
       NotificationManager::class.java
   ) as NotificationManager
             
   notificationManager.sendNotification(
       context.getText(R.string.eggs_ready).toString(), 
       context
   )
  1. De manera opcional, quita el mensaje emergente, ya que tu app enviará una notificación cuando se acabe el tiempo.
// AlarmReceiver.kt
     // TODO: Step 1.10 [Optional] remove toast
//   Toast.makeText(
//       context, 
//       context.getText(R.string.eggs_ready),
//       Toast.LENGTH_SHORT
//   ).show()
  1. Ejecuta tu app . Deberías ver una notificación cada vez que inicies el temporizador y cada vez que se acabe el tiempo.

Esto no es ideal. No envíes demasiadas notificaciones a los usuarios. Puedes quitar la primera notificación que se envía cuando el usuario inicia el temporizador.

  1. Abre EggTimerFragment.kt y quita el código de notificación del paso 1.5.
// EggTimeViewModel.kt

// TODO: Step 1.5 get an instance of NotificationManager 
// and call sendNotification
// val notificationManager = ContextCompat.getSystemService(
//      app,
//      NotificationManager::class.java
// ) as NotificationManager
// notificationManager.sendNotification(app.getString(R.string.eggs_ready), app)
  1. Vuelve a ejecutar tu app.
  2. Configura un temporizador, ponlo en segundo plano y espera a que termine el tiempo. Verás una notificación. Esta es una notificación mucho más útil.

Paso 4: Agrega una intención de contenido

  1. Vuelve a ejecutar la app si aún no se está ejecutando.
  2. Haz clic en la notificación. No pasa nada.

Mostrar la notificación e informar al usuario es excelente, pero cuando un usuario hace clic en una notificación, espera volver a la app correspondiente. En esta parte del codelab, agregarás un intent a tu notificación para que el usuario vuelva a la pantalla del temporizador.

Un Intent es un objeto de mensajería que puedes usar para solicitar una acción de otro componente de la app. Los intents se pueden usar para iniciar una actividad, un servicio o entregar una emisión. En este caso, usas este intent para indicarle al sistema que abra MainActivity cuando el usuario presione la notificación. Como tu app consta de una sola vista, no tienes muchas opciones aquí. Sin embargo, en una app más grande, la notificación debería crear una experiencia fluida llevando al usuario a una pantalla que tenga sentido cuando interactúe con la notificación.

  1. Abre NotificationUtils.kt y busca la función de extensión sendNotification().
  2. Crea un Intent con tu applicationContext y la actividad que se lanzará, MainActivity::class.java.
// NotificationUtils.kt

fun NotificationManager.sendNotification(messageBody: String, applicationContext: Context) {
    // Create the content intent for the notification, which launches
    // this activity
   // TODO: Step 1.11 create intent
    val contentIntent = Intent(applicationContext, MainActivity::class.java)

Creaste el intent, pero la notificación se muestra fuera de tu app. Para que un intent funcione fuera de tu app, debes crear un nuevo PendingIntent.

PendingIntent otorga derechos a otra aplicación o al sistema para realizar una operación en nombre de tu aplicación. Un PendingIntent en sí es simplemente una referencia a un token que mantiene el sistema y que describe los datos originales que se usaron para recuperarlo. Esto significa que, incluso si se anula el proceso de la aplicación propietaria, el PendingIntent en sí seguirá siendo utilizable desde otros procesos a los que se haya proporcionado. En este caso, el sistema usará el intent pendiente para abrir la app en tu nombre, independientemente de si la app de temporizador se está ejecutando o no.

  1. Crea un PendingIntent con applicationContext, NOTIFICATION_ID, el contentIntent que creaste en el paso anterior y la marca PendingIntent. La marca PendingIntent especifica la opción para crear un PendingIntent nuevo o usar uno existente. Debes establecer PendingIntent.FLAG_UPDATE_CURRENT como la marca, ya que no quieres crear una notificación nueva si ya existe una. De esta manera, modificarás el PendingIntent actual que está asociado con el intent que proporcionas.
// NotificationUtils.kt
   // TODO: Step 1.12 create PendingIntent
    val contentPendingIntent = PendingIntent.getActivity(
        applicationContext, 
        NOTIFICATION_ID,
        contentIntent,
        PendingIntent.FLAG_UPDATE_CURRENT
    )
  1. Pasa el PendingIntent a tu notificación. Para ello, llama a setContentIntent() en NotificationBuilder. Ahora, cuando hagas clic en la notificación, se activará PendingIntent y se abrirá tu MainActivity.
  2. También establece setAutoCancel() en true para que, cuando el usuario presione la notificación, esta se descarte automáticamente mientras lo lleva a la app.
// NotificationUtils.kt
    // TODO: Step 1.13 set content intent
    .setContentIntent(contentPendingIntent)
    .setAutoCancel(true)
  1. Vuelve a ejecutar la app.
  2. Establece un temporizador, pon la app en segundo plano y espera a que aparezca la notificación.
  3. Una vez que veas la notificación, haz clic en ella tirando hacia abajo de la barra de estado y observa cómo la app se abre en primer plano.

Paso 5: Cancela la notificación

Tienes un temporizador de huevos funcional con notificaciones, pero hay un pequeño problema. Si configuras el temporizador, recibes una notificación y vuelves a configurarlo, la notificación anterior permanecerá en la barra de estado mientras se ejecuta el nuevo temporizador. Esto puede confundir al usuario si la app está en segundo plano y puede provocar que los huevos queden poco cocidos.

Para solucionar este problema, debes borrar la notificación anterior cuando inicies un nuevo temporizador. Comienza por crear otra función de extensión en tu NotificationUtils.kt. NotificationManager tiene una API para cancelar todas las notificaciones activas llamada cancelAll().

  1. Abre NotificationsUtil.kt.
  2. Agrega una función de extensión en NotificationManager que llame a cancelAll().
// NotificationUtils.kt

// TODO: Step 1.14 Cancel all notifications
/**
 * Cancels all notifications.
 *
 */
fun NotificationManager.cancelNotifications() {
    cancelAll()
}
  1. Abre EggTimerViewModel.kt y navega a la función startTimer().
  2. Dentro de startTimer(), obtén una instancia de NotificationManager del sistema y llama a cancelNotifications().
//  EggTimerViewModel.kt
   //TODO Step 1.15 call cancel notification
    val notificationManager =
       ContextCompat.getSystemService(
            app,
            NotificationManager::class.java
        ) as NotificationManager
    notificationManager.cancelNotifications()       
  1. Ejecuta la app y comienza el temporizador.
  2. Después de ver la notificación, vuelve a iniciar el temporizador y observa cómo nuestra app borra automáticamente la notificación anterior de la barra de estado.

El framework de notificaciones ofrece una variedad de opciones de personalización para que los desarrolladores establezcan acciones personalizadas y diseñen sus notificaciones según sea necesario. En esta tarea, aprenderás a personalizar las notificaciones del temporizador de huevos.

Paso 1: Aplica estilo a tu notificación

Si le aplicas un diseño a la notificación según tus necesidades y el contenido de la notificación, esta se destacará y se verá más como una extensión de tu aplicación. El framework de notificaciones incluye varios estilos integrados para ayudarte, y siempre puedes crear los tuyos.

NotificationCompat ofrece estilos integrados para lo siguiente:

  • BigTextStyle, que puede mostrar un bloque de texto grande, como el contenido de un correo electrónico cuando se expande.
  • BigPictureStyle, que muestra notificaciones de formato grande que incluyen un archivo adjunto de imagen grande.
  • InboxStyle, que muestra contenido de texto con estilo de conversación.
  • MediaStyle, que muestra los controles de reproducción de contenido multimedia
  • MessagingStyle, que muestra notificaciones de formato grande que incluyen varios mensajes entre cualquier cantidad de personas.

Puedes encontrar más información sobre otros estilos en la documentación de Cómo crear una notificación expandible. En este paso, usarás NotificationCompat.BigPictureStyle para crear una notificación expandible que muestre una imagen grande de un huevo cuando se expanda.

  1. Abre NotificationUtils.kt y busca la función sendNotification().
  2. Comienza por cargar una imagen desde resources con BitmapFactory.
// NotificationUtils.kt

// TODO: Step 2.0 add style
val eggImage = BitmapFactory.decodeResource(
     applicationContext.resources, 
     R.drawable.cooked_egg
)
  1. Crea un objeto BigPictureStyle nuevo y configura tu imagen.
  2. Establece bigLargeIcon() en null para que el ícono grande desaparezca cuando se expanda la notificación.
// NotificationUtils.kt

// TODO: Step 2.0 add style
val eggImage = BitmapFactory.decodeResource(
     applicationContext.resources, 
     R.drawable.cooked_egg
)
val bigPicStyle = NotificationCompat.BigPictureStyle()
        .bigPicture(eggImage)
        .bigLargeIcon(null)
  1. Establece el estilo con setStyle() en bigPicStyle.
  2. Establece el ícono grande con setLargeIcon() en eggImage, de modo que la imagen se muestre como un ícono más pequeño cuando se contraiga la notificación.
// NotificationUtils.kt
// TODO: Step 2.1 add style to builder
.setStyle(bigPicStyle)
.setLargeIcon(eggImage)
  1. Ejecuta la app y configura un temporizador. Cuando se muestra la notificación por primera vez, se encuentra en estado contraído en el panel de notificaciones. Si expandes la notificación, se mostrará una imagen grande en el área de notificación extendida.

Paso 2: Acciones de la notificación

Las acciones de notificación son otra personalización que puedes agregar a tus notificaciones. Actualmente, tus notificaciones redireccionan a tu app cuando los usuarios hacen clic en ellas. Además de esta acción de notificación predeterminada, puedes agregar botones de acción que ejecuten una tarea relacionada con la app desde la notificación.

Una notificación puede ofrecer hasta tres botones de acción que le permitan al usuario responder de manera rápida, como posponer un recordatorio o responder un mensaje de texto. Estos botones de acción no deben duplicar la acción realizada cuando el usuario presiona la notificación.

Para agregar un botón de acción, pasa un PendingIntent a la función addAction() en el compilador. Esto es similar a configurar la acción de toque predeterminada de la notificación llamando a setContentIntent(), excepto que, en lugar de iniciar una actividad, puedes llevar a cabo una variedad de otras funciones, por ejemplo, iniciar un BroadcastReceiver que realice un trabajo en segundo plano, de modo que la acción no interrumpa a la app que ya está abierta.

En este codelab, ya se te proporciona un BoadcastReceiver llamado SnoozeReceiver. Usarás SnoozeReceiver para recibir el clic del usuario en la acción de notificación. En los siguientes pasos, agregarás código para posponer la notificación del temporizador de huevos durante 60 segundos cuando el usuario haga clic en el botón de acción para posponer. Cuando se hace clic en la acción de posponer, el SnoozeReceiver recibirá una intención y creará una alarma nueva para enviar una notificación nueva después de 60 segundos.

  1. Abre SnoozeReceiver.kt. Esta clase es similar a AlarmReceiver, que usaste antes. En los siguientes pasos, agregarás código que activará la función onReceive() del SnoozeReceiver. En resumen, el código en SnoozeReceiver creará una alarma nueva para enviar una notificación nueva un minuto después. Desplázate hacia abajo hasta el final de la función onReceive, obtén una instancia de notificationManager del sistema y llama a cancelAll.
// SnoozeReceiver.kt
        val notificationManager = ContextCompat.getSystemService(
            context,
            NotificationManager::class.java
        ) as NotificationManager
        notificationManager.cancelAll()
  1. Para usar SnoozeReceiver, abre NotificationUtils.kt.
  2. Crea un nuevo Intent snoozeIntent para el SnoozeReceiver justo después del diseño en la función sendNotification().
  3. Crea un intent pendiente llamando al método getBroadcast() en PendingIntent, que espera los parámetros en los siguientes pasos. El sistema usará este PendingIntent para configurar una alarma nueva que publique una notificación nueva después de 60 s cuando el usuario presione el botón de posponer.
  4. El primer parámetro es el contexto de la aplicación en el que este PendingIntent debería iniciar la actividad.
  5. El segundo parámetro es el código de solicitud, que es el código de solicitud de este intent pendiente. Si necesitas actualizar o cancelar esta intención pendiente, debes usar este código para acceder a ella.
  6. A continuación, agrega el objeto snoozeIntent, que es el intent de la actividad que se iniciará.
  7. Por último, agrega el valor de la marca #FLAG_ONE_SHOT, ya que la intención se usará solo una vez. La acción rápida y la notificación desaparecerán después del primer toque, por lo que la intención solo se puede usar una vez.
// NotificationUtils.kt

// TODO: Step 2.2 add snooze action
val snoozeIntent = Intent(applicationContext, SnoozeReceiver::class.java)
val snoozePendingIntent: PendingIntent = PendingIntent.getBroadcast(
    applicationContext, 
    REQUEST_CODE, 
    snoozeIntent, 
    FLAGS
)
  1. A continuación, llama a la función addAction() en el notificationBuilder. Esta función espera un ícono y un texto para describir tu acción al usuario. También debes agregar snoozeIntent. Este intent se usará para activar el boadcastReceiver correcto cuando se haga clic en tu acción.
// NotificationUtils.kt
// TODO: Step 2.3 add snooze action
.addAction(
    R.drawable.egg_icon, 
    applicationContext.getString(R.string.snooze),
    snoozePendingIntent
)
  1. Ejecuta la app de temporizador de huevos para probar la acción de posponer.
  2. Ejecuta el temporizador y pon la app en segundo plano. Una vez que se acabe el tiempo, expande la notificación y verás que ahora tiene un botón de acción para posponer el temporizador de huevos por un minuto más.

Paso 3: Importancia de la notificación

La importancia determina el nivel de interrupción visual y auditiva de la notificación para el usuario. Las notificaciones con mayor importancia interrumpirán más a los usuarios.

Debes especificar el nivel de importancia en el constructor NotificationChannel. Originalmente, estableciste una importancia baja para la app de temporizador. Puedes usar uno de los cinco niveles de importancia, que van desde IMPORTANCE_NONE(0) hasta IMPORTANCE_HIGH(4). El nivel de importancia que asignas a un canal se aplica a todos los mensajes de notificaciones que publicas en este.

Niveles de importancia del canal

Nivel de importancia visible para el usuario

Importancia (Android 8.0 y versiones posteriores)

Prioridad (Android 7.1 y versiones anteriores)

Emite un sonido y aparece como una notificación emergente (aparece en la parte superior de la pantalla)

IMPORTANCE_HIGH

PRIORITY_HIGH o PRIORITY_MAX

Emite un sonido

IMPORTANCE_DEFAULT

PRIORITY_DEFAULT

Sin sonido

IMPORTANCE_LOW

PRIORITY_LOW

No emite sonido ni aparece en la barra de estado

IMPORTANCE_MIN

PRIORITY_MIN

Para obtener información sobre cómo elegir un nivel de prioridad adecuado, consulta la sección "Niveles de prioridad" en la Guía de diseño de notificaciones. Debes tener cuidado al seleccionar un nivel de importancia para las notificaciones de tu app. La importancia del canal se debe elegir teniendo en cuenta el tiempo y la atención del usuario. Cuando una notificación poco importante se disfraza de urgente, puede generar una alarma innecesaria y distraer. Los usuarios tienen control total sobre el nivel de importancia de sus notificaciones, por lo que, si creas una notificación molesta, pueden desactivar por completo tu canal de notificaciones.

Cuando creaste la notificación por primera vez en el paso 1.6, el temporizador de huevos se configuró para enviar notificaciones con prioridad baja, ya que se diseñó para no molestar al usuario con notificaciones. Sin embargo, puede ser una buena idea llamar la atención del usuario antes de que el huevo se cocine demasiado. Para cambiar el nivel de importancia de la notificación, comienza con la configuración del canal. La importancia del canal afecta el nivel de interrupción de todas las notificaciones publicadas en el canal y debe especificarse en el constructor NotificationChannel.

  1. Para cambiar el nivel de importancia del canal de notificación de tu app, abre EggTimerFragment.kt y navega a createChannel(). Cambia el nivel de importancia de IMPORTANCE_LOW a IMPORTANCE_HIGH.
// EggTimerFragment.kt
    val notificationChannel = NotificationChannel(
        channelId,
        channelName,
        // TODO: Step 2.4 change importance
        NotificationManager.IMPORTANCE_HIGH
    )

Para admitir dispositivos con Android 7.1 (nivel de API 25) o inferior, también debes llamar a setPriority() para cada notificación, utilizando una constante de prioridad de la clase NotificationCompat.

  1. Abre NotificationUtils.kt y agrega lo siguiente al objeto compilador de notificaciones.
// NotificationUtils.kt
   .addAction(
       R.drawable.common_google_signin_btn_icon_dark,
       applicationContext.getString(R.string.snooze),
       snoozePendingIntent
    )
   // TODO: Step 2.5 set priority
    .setPriority(NotificationCompat.PRIORITY_HIGH)
  1. Antes de ejecutar la app, mantén presionado el ícono de la app en tu dispositivo o emulador y selecciona desinstalar para borrar la configuración anterior del canal. Si no desinstalas la app, no se cambiará la configuración de prioridad del canal y no se producirá ningún cambio de comportamiento cuando se publique la notificación.
  2. Ahora, vuelve a ejecutar la app y, luego, inicia el temporizador. Esta vez, cuando se entregue la notificación, deberías ver una ventana emergente en la parte superior de la pantalla, independientemente de si tu app se ejecuta en primer plano o en segundo plano.

Paso 4: Insignias de notificación

Las insignias de notificación son pequeños puntos que aparecen en el ícono del selector de la app asociada cuando esta tiene una notificación activa. Los usuarios pueden mantener presionado el ícono de la app para mostrar las notificaciones.

Estos puntos, llamados insignias, aparecen de forma predeterminada, y tu app no necesita realizar ninguna acción. Sin embargo, es posible que en algunas situaciones no tenga sentido incluir insignias en las notificaciones, por lo que puedes inhabilitarlas en cada canal. Para ello, llama a setShowBadge(false) en tu objeto NotificationChannel. Dado que el temporizador de huevos solo tiene una notificación activa en un momento determinado, la insignia en el ícono de la app no ofrece muchos beneficios para los usuarios. En los siguientes pasos, inhabilitarás la insignia y solo mostrarás una notificación para el temporizador de huevos.

  1. Agrega setShowBadge(false) al código de creación del canal del temporizador de huevos para inhabilitar las insignias.
// EggTimerFragment.kt

    ).apply {
        // TODO: Step 2.6 disable badges for this channel
        setShowBadge(false)
    }
  1. Vuelve a ejecutar la app, inicia el temporizador y observa el ícono de la app. No deberías ver insignias en el ícono de la app.

El código de la solución se encuentra en la rama principal del código que descargaste.

Curso de Udacity:

Documentación para desarrolladores de Android:

Para obtener vínculos a otros codelabs de este curso, consulta la página de destino de los codelabs de Aspectos avanzados de Android en Kotlin.