Enable users to configure app widgets

App widgets can be configurable. For example, a clock widget can allow users to configure which time zone to display.

If you’d like users to be able to configure your widget’s settings, create a widget configuration Activity. This activity will be automatically launched by the app widget host either when the widget is created or later, depending on the configuration options you specify.

Declare the configuration activity

Make sure to declare the configuration activity as a normal activity in the Android manifest file. It will be launched by the app widget host with the ACTION_APPWIDGET_CONFIGURE action, so the activity needs to accept this Intent. For example:

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

Also, the activity must be declared in the AppWidgetProviderInfo XML file, with the android:configure attribute (see Declare the AppWidgetProviderInfo XML). Here’s an example of how to declare the configuration activity:

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

The activity is declared with a fully-qualified namespace, because the launcher will reference it from outside your package scope.

That's all you need to get started with a configuration activity. Now you’ll implement the actual activity.

Implement the configuration activity

There are two important points to remember when you implement the activity:

  • The app widget host calls the configuration activity and the configuration activity should always return a result. The result should include the App Widget ID passed by the Intent that launched the activity (saved in the Intent extras as EXTRA_APPWIDGET_ID).
  • The system does not send the ACTION_APPWIDGET_UPDATE broadcast when a configuration activity is launched, which means that it does not call the onUpdate() method when the widget is created. It is the responsibility of the configuration activity to request an update from the AppWidgetManager when creating the widget for the first time. However, onUpdate() will be called for subsequent updates—it is only skipped the first time.

See the code snippets in the following section for an example of how to return a result from the configuration and update the widget.

Update the widget from the configuration activity

When a widget uses a configuration activity, it is the responsibility of the activity to update the widget when configuration is complete. You can do so by requesting an update directly from the AppWidgetManager.

Here's a summary of the procedure to properly update the widget and close the configuration activity:

  1. Set the activity result to RESULT_CANCELED.

    This way, if the user backs out of the activity before reaching the end, the system notifies the app widget host that the configuration was canceled and the host shouldn’t add the widget:

    Kotlin

    setResult(Activity.RESULT_CANCELED)
    

    Java

    setResult(Activity.RESULT_CANCELED);
    
  2. Get the App Widget ID from the Intent that launched the activity:

    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);
    }
    
  3. Configure the widget according to the user’s preferences.

  4. When the configuration is complete, get an instance of the AppWidgetManager by calling getInstance(Context):

    Kotlin

    val appWidgetManager = AppWidgetManager.getInstance(context)
    

    Java

    AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
    
  5. Update the widget with a RemoteViews layout by calling 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. Finally, create the return Intent, set it with the activity result, and finish the activity:

    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();
    

See the ListWidgetConfigureActivity.kt sample class on GitHub for an example.

Widget configuration options

By default, the app widget host only launches the configuration activity once, immediately after the user adds the widget to their home screen. However, you can specify options that let you enable users to reconfigure existing widgets or skip initial widget configuration by providing a default widget configuration.

Enable users to reconfigure placed widgets

To enable users to reconfigure existing widgets, specify the reconfigurable flag in the widgetFeatures attribute of appwidget-provider (see Declare the AppWidgetProviderInfo XML for more information). For example:

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

Users will then be able to reconfigure their widget by long-pressing the widget and tapping the Reconfigure button, which is labeled 1 in figure 1.

Button appears in bottom-right corner
Figure 1: Widget Reconfigure button

Use the widget's default configuration

You can provide a more seamless widget experience by allowing users to skip the initial configuration step. To do this, specify both the configuration_optional and reconfigurable flags in the widgetFeatures field. This bypasses launching the configuration activity after a user adds the widget. (As mentioned previously, the user can still reconfigure the widget afterwards.) For example, a clock widget could bypass the initial configuration and show the device time zone by default.

Here is an example of how to mark your configuration activity as reconfigurable and optional:

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

Allow users to pin a widget

On devices running Android 8.0 (API level 26) and higher, launchers that allow users to create pinned shortcuts also allow them to pin widgets onto their home screen. Similar to pinned shortcuts, these pinned widgets give users access to specific tasks in your app and can be added to the home screen directly from the app. For example, when a user adds a new city in a weather app, you could prompt the user to add a weather widget for that city to their home screen.

In your app, you can create a request for the system to pin a widget onto a supported launcher by completing the following steps:

  1. Make sure you’ve declared a widget in your app’s manifest file.

  2. Call the requestPinAppWidget() method, as shown in the following code snippet:

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
    // that the user allowed the widget to be pinned. 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
    // that the user allowed the widget to be pinned. 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);
}