Créer un widget simple

Les widgets d'application sont des vues d'application miniatures que vous pouvez intégrer dans d'autres telles que l'écran d'accueil, et recevoir régulièrement des mises à jour. Ces Les vues sont appelées widgets dans l'interface utilisateur, et vous pouvez publier une avec un fournisseur de widgets d'application (ou un fournisseur de widgets). Composant d'application qui contenant d'autres widgets est appelé hôte de widget d'application (ou hôte de widget). Figure 1 affiche un exemple de widget musical:

Exemple de widget Musique
Figure 1. Exemple de widget musical.

Ce document explique comment publier un widget à l'aide d'un fournisseur de widgets. Pour des détails sur la création de votre propre AppWidgetHost pour des widgets d'application hôte, consultez la section Créer un hôte de widget.

Pour en savoir plus sur la conception de votre widget, consultez Présentation des widgets d'application.

Composants du widget

Pour créer un widget, vous avez besoin des composants de base suivants:

Objet AppWidgetProviderInfo
Décrit les métadonnées d'un widget, telles que sa mise en page, sa mise à jour la fréquence et la classe AppWidgetProvider. AppWidgetProviderInfo est défini en XML, comme suit : décrites dans ce document.
Classe AppWidgetProvider
Définit les méthodes de base qui vous permettent d'interagir de manière programmatique avec la . Grâce à lui, vous recevez des annonces lorsque le widget est mis à jour, activées, désactivées ou supprimées. Vous déclarez AppWidgetProvider dans manifeste, puis l'implémentez, décrites dans ce document.
Afficher la mise en page
Définit la mise en page initiale du widget. La mise en page est définie XML, comme décrit dans ce document.

La figure 2 montre comment ces composants s'intègrent dans le traitement global des widgets d'application. le flux de travail.

Flux de traitement du widget d'application
Figure 2. Flux de traitement du widget d'application

Si votre widget nécessite une configuration utilisateur, implémentez la configuration du widget d'application. activité. Cette activité permet aux utilisateurs de modifier les paramètres des widgets, par exemple, le fuseau horaire d'un widget d'horloge.

Nous recommandons également les améliorations suivantes: mises en page de widgets flexibles, différentes améliorations, widgets avancés, widgets de collection et création de widgets. d'hébergement.

Déclarer le fichier XML AppWidgetProviderInfo

L'objet AppWidgetProviderInfo définit les qualités essentielles d'un widget. Définissez l'objet AppWidgetProviderInfo dans un fichier de ressources XML à l'aide d'une seule <appwidget-provider> et enregistrez-le dans le dossier res/xml/ du projet.

Ce processus est illustré dans l'exemple suivant :

<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
    android:minWidth="40dp"
    android:minHeight="40dp"
    android:targetCellWidth="1"
    android:targetCellHeight="1"
    android:maxResizeWidth="250dp"
    android:maxResizeHeight="120dp"
    android:updatePeriodMillis="86400000"
    android:description="@string/example_appwidget_description"
    android:previewLayout="@layout/example_appwidget_preview"
    android:initialLayout="@layout/example_loading_appwidget"
    android:configure="com.example.android.ExampleAppWidgetConfigurationActivity"
    android:resizeMode="horizontal|vertical"
    android:widgetCategory="home_screen"
    android:widgetFeatures="reconfigurable|configuration_optional">
</appwidget-provider>

Attributs de dimensionnement des widgets

L'écran d'accueil par défaut positionne les widgets dans sa fenêtre en fonction d'une grille de cellules d'une hauteur et d'une largeur définies. Avec la plupart des écrans d'accueil, seuls les widgets peuvent s'afficher tailles qui sont des multiples entiers des cellules de la grille (par exemple, deux cellules) horizontalement de trois cellules verticalement.

Les attributs de dimensionnement de widget vous permettent de spécifier une taille par défaut pour votre widget et indiquent les limites inférieure et supérieure de la taille du widget. Dans ce contexte, la taille par défaut d'un widget est la taille qu'il prend en charge ajouté à l'écran d'accueil.

Le tableau suivant décrit les attributs <appwidget-provider> concernant au dimensionnement des widgets:

Attributs et description
targetCellWidth et targetCellHeight (Android 12), minWidth et minHeight
  • À partir d'Android 12, targetCellWidth et targetCellHeight Les attributs spécifient la taille par défaut du widget en termes de grille. cellules. Ces attributs sont ignorés dans Android 11. et inférieurs, et peuvent être ignorés si l'écran d'accueil sont compatibles avec une mise en page sous forme de grille.
  • Les minWidth et Les attributs minHeight spécifient la taille par défaut du widget en dp. Si les valeurs de la largeur ou de la hauteur minimales d'un widget ne correspondent pas les dimensions des cellules, les valeurs sont arrondies au la taille de cellule la plus proche.
Nous vous recommandons de spécifier les deux attributs : targetCellWidth et targetCellHeight, minWidth et minHeight, afin que votre application puisse revenir à l'utilisation minWidth et minHeight si l'appareil de l'utilisateur n'est pas compatible avec targetCellWidth et targetCellHeight S'il est compatible, Attributs targetCellWidth et targetCellHeight ont priorité sur les minWidth et minHeight .
minResizeWidth et minResizeHeight Spécifiez la taille minimale absolue du widget. Ces valeurs spécifient taille en dessous de laquelle le widget est illisible ou inutilisable. En utilisant ces attributs permettent à l'utilisateur de redimensionner le widget à une taille plus petite que la taille de widget par défaut. L'attribut minResizeWidth est ignorée si la valeur est supérieure à minWidth ou si elle est horizontale le redimensionnement n'est pas activé. Voir resizeMode De même, L'attribut minResizeHeight est ignoré s'il est supérieur à minHeight ou si le redimensionnement vertical n'est pas activé.
maxResizeWidth et maxResizeHeight Spécifiez la taille maximale recommandée pour le widget. Si les valeurs ne sont pas un multiple des dimensions d'une cellule de grille, elles sont arrondies à la valeur la taille de la cellule. L'attribut maxResizeWidth est ignoré s'il est inférieure à minWidth ou si le redimensionnement horizontal n'est pas est activé. Voir resizeMode. De même, L'attribut maxResizeHeight est ignoré s'il est supérieur que minHeight ou si le redimensionnement vertical n'est pas activé. Introduit dans Android 12.
resizeMode Spécifie les règles selon lesquelles un widget peut être redimensionné. Vous pouvez utiliser cette pour faire en sorte que les widgets de l'écran d'accueil puissent être redimensionnés horizontalement, verticalement, ou sur les deux axes. Les utilisateurs appuient sur appuyez de manière prolongée sur un widget pour afficher ses poignées de redimensionnement puis faites glisser les poignées horizontales ou verticales pour modifier sa taille sur le grille de mise en page. Les valeurs de l'attribut resizeMode incluent les suivantes : horizontal, vertical et none. À déclarer un widget comme redimensionnable à l'horizontale et à la verticale, utiliser horizontal|vertical

Exemple

Pour illustrer l'impact des attributs du tableau précédent sur le dimensionnement des widgets, supposent les spécifications suivantes:

  • Une cellule de grille fait 30 dp de large et 50 dp de hauteur.
  • Les spécifications d'attribut suivantes sont fournies:
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
    android:minWidth="80dp"
    android:minHeight="80dp"
    android:targetCellWidth="2"
    android:targetCellHeight="2"
    android:minResizeWidth="40dp"
    android:minResizeHeight="40dp"
    android:maxResizeWidth="120dp"
    android:maxResizeHeight="120dp"
    android:resizeMode="horizontal|vertical" />

À partir d'Android 12:

Utilisez les attributs targetCellWidth et targetCellHeight par défaut. la taille du widget.

Par défaut, la taille du widget est 2 x 2. Le widget peut être redimensionné à 2 x 1 ou jusqu'à 4x3.

Android 11 ou version antérieure:

Utilisez les attributs minWidth et minHeight pour calculer la taille par défaut de le widget.

Largeur par défaut = Math.ceil(80 / 30) = 3

Hauteur par défaut = Math.ceil(80 / 50) = 2

Par défaut, la taille du widget est 3 x 2. Le widget peut être redimensionné à 2 x 1 ou jusqu'en plein écran.

Autres attributs de widget

Le tableau suivant décrit les attributs <appwidget-provider> concernant à des qualités autres que le dimensionnement du widget.

Attributs et description
updatePeriodMillis Définit la fréquence à laquelle le framework de widget demande une mise à jour à partir du AppWidgetProvider en appelant la méthode onUpdate() . Il n'est pas garanti que la mise à jour ait lieu exactement avec cette valeur. Nous vous recommandons d'effectuer une mise à jour possible, pas plus d'une fois par heure, pour économiser la batterie. Pour obtenir la liste complète des éléments à prendre en compte pour choisir une période de mise à jour appropriée, voir Optimisations pour la mise à jour des widgets contenus.
initialLayout Pointe vers la ressource de mise en page qui définit la mise en page du widget.
configure Définit l'activité qui se lance lorsque l'utilisateur ajoute le widget. de configurer les propriétés des widgets. Voir Permettez aux utilisateurs de configurer des widgets. À partir d'Android 12, votre application peut ignorer l'étape initiale configuration. Reportez-vous à la section Utiliser le configuration par défaut du widget.
description Spécifie la description du sélecteur de widgets à afficher pour votre . Introduit dans Android 12.
previewLayout (Android 12) et previewImage (Android 11 ou version antérieure)
  • À partir d'Android 12, L'attribut previewLayout spécifie un aperçu évolutif, qui que vous fournissez en tant que mise en page XML définie sur la taille par défaut du widget. Dans l’idéal, le fichier XML de mise en page spécifié pour cet attribut est le même fichier XML de mise en page que widget réel avec des valeurs par défaut réalistes.
  • Sous Android 11 ou version antérieure, le previewImage spécifie un aperçu de l'apparence du widget que l'utilisateur voit lorsqu'il sélectionne le widget d'application. Si ce n'est pas le cas fournie, l'utilisateur voit à la place l'icône de lanceur de votre application. Ce le champ correspond à l'attribut android:previewImage dans l'élément <receiver> dans AndroidManifest.xml.
Remarque:Nous vous recommandons de spécifier à la fois previewImage et previewLayout pour que votre application à l'utilisation de previewImage si l'appareil de l'utilisateur n'est pas compatible previewLayout Pour en savoir plus, consultez Rétrocompatibilité avec des modèles des aperçus de widgets.
autoAdvanceViewId Spécifie l'ID de la vue de la sous-vue du widget qui est avancée automatiquement par à l'hôte du widget.
widgetCategory Indique si votre widget peut être affiché sur l'écran d'accueil (home_screen), l'écran de verrouillage (keyguard) ou les deux. Pour Android 5.0 ou version ultérieure, seul home_screen est valide.
widgetFeatures Déclare les fonctionnalités compatibles avec le widget. Par exemple, si vous souhaitez de votre widget afin qu'il utilise sa configuration par défaut lorsqu'un utilisateur l'ajoute, spécifiez à la fois configuration_optional et reconfigurable options. Cela permet de contourner l'activité de configuration après qu'un utilisateur ajoute le widget. L'utilisateur peut toujours reconfigurer le widget par la suite.

Utiliser la classe AppWidgetProvider pour gérer les diffusions de widget

La classe AppWidgetProvider gère les diffusions du widget et le met à jour. en réponse aux événements de cycle de vie des widgets. Les sections suivantes décrivent comment déclarer AppWidgetProvider dans le fichier manifeste, puis l'implémenter.

Déclarer un widget dans le fichier manifeste

Commencez par déclarer la classe AppWidgetProvider dans le AndroidManifest.xml de votre application. , comme illustré dans l'exemple suivant:

<receiver android:name="ExampleAppWidgetProvider"
                 android:exported="false">
    <intent-filter>
        <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
    </intent-filter>
    <meta-data android:name="android.appwidget.provider"
               android:resource="@xml/example_appwidget_info" />
</receiver>

L'élément <receiver> nécessite l'attribut android:name, qui spécifie AppWidgetProvider utilisé par le widget. Le composant ne doit pas être exporté sauf si un processus distinct doit être diffusé sur votre AppWidgetProvider, ce qui ce n'est généralement pas le cas.

L'élément <intent-filter> doit inclure un élément <action> avec le paramètre android:name. Cet attribut indique que AppWidgetProvider accepte les ACTION_APPWIDGET_UPDATE annonce. Il s'agit de la seule diffusion que vous devez déclarer explicitement. La AppWidgetManager envoie automatiquement toutes les autres annonces de widget à AppWidgetProvider en tant que nécessaires.

L'élément <meta-data> spécifie la ressource AppWidgetProviderInfo et requiert les attributs suivants:

  • android:name: spécifie le nom des métadonnées. Utilisez android.appwidget.provider pour identifier les données comme Descripteur AppWidgetProviderInfo.
  • android:resource: spécifie la ressource AppWidgetProviderInfo. l'emplacement.

Implémenter la classe AppWidgetProvider

La classe AppWidgetProvider étend BroadcastReceiver en tant que pour gérer les diffusions de widget. Il ne reçoit que l'événement des annonces pertinentes pour le widget, comme la mise à jour du widget, supprimé, activé et désactivé. Lorsque ces événements de diffusion se produisent, les éléments suivants Les méthodes AppWidgetProvider sont appelées:

onUpdate()
Cette méthode est appelée pour mettre à jour le widget à des intervalles définis par le updatePeriodMillis dans AppWidgetProviderInfo. Consultez le tableau décrivant d'autres attributs de widget sur cette page pour plus d'informations.
Cette méthode est également appelée lorsque l'utilisateur ajoute le widget afin qu'il effectue l'action configuration essentielle, comme la définition de gestionnaires d'événements pour Objets View ou démarrage de tâches pour charger des données s'affichent dans le widget. Toutefois, si vous déclarez une activité de configuration sans l'indicateur configuration_optional, cette méthode n'est pas appelée lorsque l'utilisateur ajoute le widget, mais il est appelé pour les mises à jour ultérieures. Il s'agit de l'activité de configuration pour effectuer la première mise à jour est terminée. Pour en savoir plus, consultez Permettre aux utilisateurs de configurer des widgets d'application.
Le rappel le plus important est onUpdate(). Consultez la section Gérer les événements à l'aide du module onUpdate() sur cette page.
onAppWidgetOptionsChanged()

Cette méthode est appelée lorsque le widget est placé pour la première fois et chaque fois qu'il est redimensionnée. Utilisez ce rappel pour afficher ou masquer le contenu en fonction de la taille du widget plages. Obtenez les plages de tailles et, à partir d'Android 12, la liste des tailles possibles d'une instance de widget en appelant getAppWidgetOptions(), qui renvoie un Bundle qui inclut le suivantes:

onDeleted(Context, int[])

Cette méthode est appelée chaque fois qu'un widget est supprimé de son hôte.

onEnabled(Context)

Cette méthode est appelée lorsqu'une instance du widget est créée pour la première fois. Par exemple, si l'utilisateur ajoute deux instances de votre widget, cette méthode ne sera appelée pour la première fois. Si vous devez ouvrir une nouvelle base de données ou effectuer une autre configuration ne doit se produire qu'une seule fois pour toutes les instances de widget, c'est l'endroit idéal pour le faire.

onDisabled(Context)

Cette méthode est appelée lorsque la dernière instance de votre widget est supprimée de hôte du widget. C'est ici que vous nettoyez tout le travail effectué dans onEnabled(Context), comme la suppression d'une base de données temporaire.

onReceive(Context, Intent)

Cette méthode est appelée pour chaque annonce et avant chacun des rappels précédents. méthodes. Normalement, vous n'avez pas besoin d'implémenter cette méthode, car la méthode par défaut L'implémentation de AppWidgetProvider filtre toutes les diffusions de widget et appelle la les méthodes précédentes, le cas échéant.

Vous devez déclarer l'implémentation de votre classe AppWidgetProvider en tant que diffusion. récepteur à l'aide de l'élément <receiver> dans AndroidManifest. Reportez-vous à la section Déclarer un dans le fichier manifeste sur cette page.

Gérer les événements avec la classe onUpdate()

Le rappel AppWidgetProvider le plus important est onUpdate(), car il s'agit appelé lorsque chaque widget est ajouté à un hôte, sauf si vous utilisez une règle de configuration d'activité sans l'indicateur configuration_optional. Si votre widget accepte les d'interaction utilisateur, puis enregistrez les gestionnaires d'événements dans ce rappel. Si votre widget ne crée pas de fichiers temporaires ou de bases de données et n'effectue aucun autre travail qui nécessite un nettoyage, onUpdate() peut être la seule méthode de rappel que vous à définir.

Par exemple, si vous voulez un widget avec un bouton qui lance une activité lorsque vous pouvez utiliser l'implémentation suivante de AppWidgetProvider:

Kotlin

class ExampleAppWidgetProvider : AppWidgetProvider() {

    override fun onUpdate(
            context: Context,
            appWidgetManager: AppWidgetManager,
            appWidgetIds: IntArray
    ) {
        // Perform this loop procedure for each widget that belongs to this
        // provider.
        appWidgetIds.forEach { appWidgetId ->
            // Create an Intent to launch ExampleActivity.
            val pendingIntent: PendingIntent = PendingIntent.getActivity(
                    /* context = */ context,
                    /* requestCode = */  0,
                    /* intent = */ Intent(context, ExampleActivity::class.java),
                    /* flags = */ PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
            )

            // Get the layout for the widget and attach an onClick listener to
            // the button.
            val views: RemoteViews = RemoteViews(
                    context.packageName,
                    R.layout.appwidget_provider_layout
            ).apply {
                setOnClickPendingIntent(R.id.button, pendingIntent)
            }

            // Tell the AppWidgetManager to perform an update on the current
            // widget.
            appWidgetManager.updateAppWidget(appWidgetId, views)
        }
    }
}

Java

public class ExampleAppWidgetProvider extends AppWidgetProvider {

    public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
        // Perform this loop procedure for each widget that belongs to this
        // provider.
        for (int i=0; i < appWidgetIds.length; i++) {
            int appWidgetId = appWidgetIds[i];
            // Create an Intent to launch ExampleActivity
            Intent intent = new Intent(context, ExampleActivity.class);
            PendingIntent pendingIntent = PendingIntent.getActivity(
                /* context = */ context,
                /* requestCode = */ 0,
                /* intent = */ intent,
                /* flags = */ PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE
            );

            // Get the layout for the widget and attach an onClick listener to
            // the button.
            RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.example_appwidget_layout);
            views.setOnClickPendingIntent(R.id.button, pendingIntent);

            // Tell the AppWidgetManager to perform an update on the current app
            // widget.
            appWidgetManager.updateAppWidget(appWidgetId, views);
        }
    }
}

Cet élément AppWidgetProvider définit uniquement la méthode onUpdate() et l'utilise pour créer un PendingIntent qui lance un Activity et l'associe au bouton avec setOnClickPendingIntent(int, PendingIntent). Elle comprend une boucle qui itère chaque entrée. dans appWidgetIds, qui est un tableau d'ID identifiant chaque widget créé par ce fournisseur. Si l'utilisateur crée plusieurs instances du widget, alors ils sont tous mis à jour en même temps. Cependant, une seule planification updatePeriodMillis est géré pour toutes les instances du widget. Par exemple, si le calendrier de mise à jour est définie pour être exécutée toutes les deux heures, et une deuxième instance du widget est ajoutée une heure après la première, ils sont tous les deux mis à jour sur la période définie par la première et la deuxième période de mise à jour est ignorée. Elles se mettent à jour toutes les deux pas toutes les heures.

Consultez le ExampleAppWidgetProvider.java pour en savoir plus.

Recevoir des intents de diffusion de widget

AppWidgetProvider est une classe de commodité. Si vous souhaitez recevoir le widget diffuse directement, vous pouvez implémenter votre propre BroadcastReceiver ou ignorer la Rappel onReceive(Context,Intent). Les intents dont vous devez vous soucier sont suivantes:

Créer la mise en page de widget

Vous devez définir une mise en page initiale pour votre widget au format XML et l'enregistrer dans le fichier dans le répertoire res/layout/ du projet. Consultez la section Conception consignes.

La mise en page des widgets est simple si vous connaissez mises en page. Toutefois, sachez que les widgets les mises en page sont basées sur RemoteViews, qui n'est pas compatible avec tous les types de mise en page ou de widget de vue. Vous ne pouvez pas utiliser des vues ou des sous-classes des vues compatibles avec RemoteViews.

RemoteViews est également compatible avec ViewStub, qui est une View invisible de taille nulle que vous pouvez utiliser pour gonfler la mise en page de manière différée ressources lors de l'exécution.

Compatibilité avec le comportement avec état

Android 12 prend en charge le comportement avec état à l'aide des éléments suivants : composants existants:

Le widget est toujours sans état. Votre application doit stocker l'état et s'inscrire à les événements de changement d'état.

Exemple de widget de liste de courses montrant un comportement avec état
Figure 3. Exemple de comportement avec état.

L'exemple de code suivant montre comment implémenter ces composants.

Kotlin

// Check the view.
remoteView.setCompoundButtonChecked(R.id.my_checkbox, true)

// Check a radio group.
remoteView.setRadioGroupChecked(R.id.my_radio_group, R.id.radio_button_2)

// Listen for check changes. The intent has an extra with the key
// EXTRA_CHECKED that specifies the current checked state of the view.
remoteView.setOnCheckedChangeResponse(
        R.id.my_checkbox,
        RemoteViews.RemoteResponse.fromPendingIntent(onCheckedChangePendingIntent)
)

Java

// Check the view.
remoteView.setCompoundButtonChecked(R.id.my_checkbox, true);

// Check a radio group.
remoteView.setRadioGroupChecked(R.id.my_radio_group, R.id.radio_button_2);

// Listen for check changes. The intent has an extra with the key
// EXTRA_CHECKED that specifies the current checked state of the view.
remoteView.setOnCheckedChangeResponse(
    R.id.my_checkbox,
    RemoteViews.RemoteResponse.fromPendingIntent(onCheckedChangePendingIntent));

Fournissez deux mises en page: l'une cible les appareils équipés d'Android 12 ou plus élevée dans res/layout-v31, tandis que l'autre ciblage Android 11 ou version antérieure dans le dossier res/layout par défaut.

Implémenter des angles arrondis

Android 12 introduit les paramètres système suivants pour définir le rayons des angles arrondis de votre widget:

  • system_app_widget_background_radius: le rayon de l'angle de l'arrière-plan du widget, qui ne doit jamais dépasser 28 dp.

  • system_app_widget_inner_radius: le rayon d'angle de n'importe quelle vue à l'intérieur du widget. Il fait exactement 8 dp. inférieur à l'arrondi de l'arrière-plan, pour un alignement optimal lors de l'utilisation d'une résolution de 8 dp. marge intérieure.

L'exemple suivant montre un widget qui utilise system_app_widget_background_radius pour l'angle du widget et system_app_widget_inner_radius pour les vues à l'intérieur du widget.

Widget affichant les rayons de l&#39;arrière-plan du widget et les vues à l&#39;intérieur du widget
Figure 4. Coins arrondis.

1 Coin du widget

2 Angle d'une vue dans le widget.

Remarques importantes concernant les angles arrondis

  • Les lanceurs d'applications tiers et les fabricants d'appareils peuvent ignorer system_app_widget_background_radius doit être inférieure à 28 dp. Le paramètre system_app_widget_inner_radius est toujours inférieur de 8 dp à la valeur de system_app_widget_background_radius.
  • Si votre widget n'utilise pas @android:id/background ou ne définit pas d'arrière-plan qui extrait son contenu en fonction du plan, avec android:clipToOutline définie sur true, le lanceur d'applications identifie automatiquement l'arrière-plan et rogne le widget à l'aide d'un rectangle dont les angles arrondis ne dépassent pas 16 dp. Consultez la section Vérifier que votre widget est compatible avec Android 12

Pour assurer la compatibilité des widgets avec les versions précédentes d'Android, nous vous recommandons définir des attributs personnalisés et utiliser un thème personnalisé pour les remplacer Android 12, comme illustré dans les exemples de fichiers XML suivants:

/values/attrs.xml

<resources>
  <attr name="backgroundRadius" format="dimension" />
</resources>

/values/styles.xml

<resources>
  <style name="MyWidgetTheme">
    <item name="backgroundRadius">@dimen/my_background_radius_dimen</item>
  </style>
</resources>

/values-31/styles.xml

<resources>
  <style name="MyWidgetTheme" parent="@android:style/Theme.DeviceDefault.DayNight">
    <item name="backgroundRadius">@android:dimen/system_app_widget_background_radius</item>
  </style>
</resources>

/drawable/my_widget_background.xml

<shape xmlns:android="http://schemas.android.com/apk/res/android"
  android:shape="rectangle">
  <corners android:radius="?attr/backgroundRadius" />
  ...
</shape>

/layout/my_widget_layout.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  ...
  android:background="@drawable/my_widget_background" />