Cómo permitir que los usuarios configuren widgets de apps

Se pueden configurar los widgets de las apps. Por ejemplo, un widget de reloj puede permitir que los usuarios configuren qué zona horaria mostrar.

Si quieres permitir que los usuarios establezcan la configuración del widget, crea una configuración del widget Activity. El host del widget de la app inicia automáticamente esta actividad, ya sea cuando se crea el widget o más adelante, según las opciones de configuración que especifiques.

Declara la actividad de configuración

Declara la actividad de configuración como una actividad normal en el archivo de manifiesto de Android. El host del widget de la app lo inicia con la acción ACTION_APPWIDGET_CONFIGURE, por lo que la actividad debe aceptar este intent. Por ejemplo:

<activity android:name=".ExampleAppWidgetConfigurationActivity">
    <intent-filter>
        <action android:name="android.appwidget.action.APPWIDGET_CONFIGURE"/>
    </intent-filter>
</activity>

Declara la actividad en el archivo AppWidgetProviderInfo.xml con el atributo android:configure. Obtén más información sobre cómo declarar este archivo. Este es un ejemplo de cómo declarar la actividad de configuración:

<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
    ...
    android:configure="com.example.android.ExampleAppWidgetConfigurationActivity"
    ... >
</appwidget-provider>

La actividad se declara con un espacio de nombres completamente calificado, porque el selector hace referencia a ella desde fuera del alcance del paquete.

Eso es todo lo que necesitas para iniciar una actividad de configuración. A continuación, debes implementar la actividad real.

Implementa la actividad de configuración

Hay dos puntos importantes que debes recordar cuando implementas la actividad:

  • El host del widget de la app llama a la actividad de configuración, que siempre debe mostrar un resultado. El resultado debe incluir el ID del widget de la app que pasó el intent que inició la actividad, guardado en los extras del intent como EXTRA_APPWIDGET_ID.
  • El sistema no envía la transmisión ACTION_APPWIDGET_UPDATE cuando se inicia una actividad de configuración, lo que significa que no llama al método onUpdate() cuando se crea el widget. Es responsabilidad de la actividad de configuración solicitar una actualización desde AppWidgetManager cuando se crea el widget por primera vez. Sin embargo, se llama a onUpdate() para actualizaciones posteriores (solo se omite la primera vez).

Consulta los fragmentos de código de la siguiente sección para ver un ejemplo de cómo mostrar un resultado de la configuración y actualizar el widget.

Actualiza el widget desde la actividad de configuración

Cuando un widget usa una actividad de configuración, es responsabilidad de la actividad actualizarlo cuando se completa la configuración. Para ello, solicita una actualización directamente desde AppWidgetManager.

Este es un resumen del procedimiento para actualizar correctamente el widget y cerrar la actividad de configuración:

  1. Obtén el ID del widget de la app desde el intent que inició la actividad:

    Kotlin

    val appWidgetId = intent?.extras?.getInt(
            AppWidgetManager.EXTRA_APPWIDGET_ID,
            AppWidgetManager.INVALID_APPWIDGET_ID
    ) ?: AppWidgetManager.INVALID_APPWIDGET_ID
    

    Java

    Intent intent = getIntent();
    Bundle extras = intent.getExtras();
    int appWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID;
    if (extras != null) {
        appWidgetId = extras.getInt(
                AppWidgetManager.EXTRA_APPWIDGET_ID,
                AppWidgetManager.INVALID_APPWIDGET_ID);
    }
    
  2. Establece el resultado de la actividad en RESULT_CANCELED.

    De esta manera, si el usuario cancela la actividad antes de llegar al final, el sistema notifica al host del widget de la app que se canceló la configuración y que el host no agrega el widget:

    Kotlin

    val resultValue = Intent().putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId)
    setResult(Activity.RESULT_CANCELED, resultValue)
    

    Java

    int resultValue = new Intent().putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
    setResult(Activity.RESULT_CANCELED, resultValue);
    
  3. Configura el widget según las preferencias del usuario.

  4. Cuando se complete la configuración, llama a getInstance(Context) para obtener una instancia de AppWidgetManager:

    Kotlin

    val appWidgetManager = AppWidgetManager.getInstance(context)
    

    Java

    AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
    
  5. Actualiza el widget con un diseño RemoteViews llamando a updateAppWidget(int,RemoteViews):

    Kotlin

    val views = RemoteViews(context.packageName, R.layout.example_appwidget)
    appWidgetManager.updateAppWidget(appWidgetId, views)
    

    Java

    RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.example_appwidget);
    appWidgetManager.updateAppWidget(appWidgetId, views);
    
  6. Crea el intent que se muestra, configúralo con el resultado de la actividad y finaliza la actividad:

    Kotlin

    val resultValue = Intent().putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId)
    setResult(Activity.RESULT_OK, resultValue)
    finish()
    

    Java

    Intent resultValue = new Intent().putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
    setResult(RESULT_OK, resultValue);
    finish();
    

Consulta la clase de muestra ListWidgetConfigureActivity.kt en GitHub para ver un ejemplo.

Opciones de configuración del widget

De forma predeterminada, el host del widget de la app solo inicia la actividad de configuración una vez, inmediatamente después de que el usuario agrega el widget a la pantalla principal. Sin embargo, puedes especificar opciones que les permitan a los usuarios volver a configurar widgets existentes, o bien omitir la configuración inicial del widget, si proporcionas una configuración de widget predeterminada.

Cómo permitir que los usuarios reconfiguren los widgets colocados

Para permitir que los usuarios vuelvan a configurar widgets existentes, especifica la marca reconfigurable en el atributo widgetFeatures de appwidget-provider. Consulta la guía para declarar el archivo AppWidgetProviderInfo.xml y obtener más información. Por ejemplo:

<appwidget-provider
    android:configure="com.myapp.ExampleAppWidgetConfigurationActivity"
    android:widgetFeatures="reconfigurable">
</appwidget-provider>

Para reconfigurarlo, los usuarios pueden mantenerlo presionado y presionar el botón Reconfigurar, que aparece etiquetado como 1 en la Figura 1.

El botón aparece en la esquina inferior derecha
Figura 1: Botón Reconfigurar del widget.

Cómo usar la configuración predeterminada del widget

Puedes brindar una experiencia de widget más fluida si permites que los usuarios omitan el paso de configuración inicial. Para ello, especifica las marcas configuration_optional y reconfigurable en el campo widgetFeatures. De esta manera, se evita iniciar la actividad de configuración después de que un usuario agrega el widget. Como se mencionó anteriormente, el usuario aún puede reconfigurar el widget más adelante. Por ejemplo, un widget de reloj puede omitir la configuración inicial y mostrar la zona horaria del dispositivo de forma predeterminada.

A continuación, se muestra un ejemplo de cómo marcar tu actividad de configuración como reconfigurable y opcional:

<appwidget-provider
    android:configure="com.myapp.ExampleAppWidgetConfigurationActivity"
    android:widgetFeatures="reconfigurable|configuration_optional">
</appwidget-provider>

Permite que los usuarios fijen un widget

En los dispositivos que ejecutan Android 8.0 (nivel de API 26) y versiones posteriores, los selectores que permiten a los usuarios crear accesos directos fijos también les permiten fijar widgets en su pantalla principal. Al igual que los accesos directos fijos, estos widgets fijados proporcionan a los usuarios acceso a tareas específicas de tu app y se pueden agregar a la pantalla principal directamente desde la app, como se muestra en el siguiente video.

Ejemplo de diseño responsivo
Figura 2: Ejemplo de cómo fijar un widget

En tu app, puedes crear una solicitud para que el sistema fije un widget a un selector compatible. Para ello, sigue estos pasos:

  1. Asegúrate de declarar un widget en el archivo de manifiesto de tu app.

  2. Llama al método requestPinAppWidget(), como se muestra en el siguiente fragmento de código:

Kotlin

val appWidgetManager = AppWidgetManager.getInstance(context)
val myProvider = ComponentName(context, ExampleAppWidgetProvider::class.java)

if (appWidgetManager.isRequestPinAppWidgetSupported()) {
    // Create the PendingIntent object only if your app needs to be notified
    // when the user chooses to pin the widget. Note that if the pinning
    // operation fails, your app isn't notified. This callback receives the ID
    // of the newly pinned widget (EXTRA_APPWIDGET_ID).
    val successCallback = PendingIntent.getBroadcast(
            /* context = */ context,
            /* requestCode = */ 0,
            /* intent = */ Intent(...),
            /* flags = */ PendingIntent.FLAG_UPDATE_CURRENT)

    appWidgetManager.requestPinAppWidget(myProvider, null, successCallback)
}

Java

AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
ComponentName myProvider = new ComponentName(context, ExampleAppWidgetProvider.class);

if (appWidgetManager.isRequestPinAppWidgetSupported()) {
    // Create the PendingIntent object only if your app needs to be notified
    // when the user chooses to pin the widget. Note that if the pinning
    // operation fails, your app isn't notified. This callback receives the ID
    // of the newly pinned widget (EXTRA_APPWIDGET_ID).
    PendingIntent successCallback = PendingIntent.getBroadcast(
            /* context = */ context,
            /* requestCode = */ 0,
            /* intent = */ new Intent(...),
            /* flags = */ PendingIntent.FLAG_UPDATE_CURRENT);

    appWidgetManager.requestPinAppWidget(myProvider, null, successCallback);
}