Creare un widget semplice

I widget delle app sono visualizzazioni di app in miniatura che puoi incorporare in altre app, ad esempio la schermata Home, e ricevere aggiornamenti periodici. Queste visualizzazioni sono chiamate widget nell'interfaccia utente e puoi pubblicarne una con un fornitore di widget per app (o fornitore di widget). Un componente dell'app che contiene altri widget è chiamato host widget dell'app (o host widget). La Figura 1 mostra un widget musicale di esempio:

Esempio di widget musicale
Figura 1. Esempio di widget di musica.

Questo documento descrive come pubblicare un widget utilizzando un fornitore di widget. Per maggiori dettagli sulla creazione di AppWidgetHost per l'hosting di widget di app, consulta Creare un host per i widget.

Per informazioni su come progettare il widget, vedi Panoramica dei widget delle app.

Componenti del widget

Per creare un widget, sono necessari i seguenti componenti di base:

Oggetto AppWidgetProviderInfo
Descrive i metadati per un widget, ad esempio il layout, la frequenza di aggiornamento e la classe AppWidgetProvider del widget. AppWidgetProviderInfo è definito in XML, come descritto in questo documento.
AppWidgetProvider corso
Definisce i metodi di base che ti consentono di interfacciarti in modo programmatico con il widget. Tramite il widget, ricevi annunci quando il widget viene aggiornato, attivato, disattivato o eliminato. Dichiari AppWidgetProvider nel manifest e poi lo implementa, come descritto in questo documento.
Visualizza layout
Definisce il layout iniziale del widget. Il layout è definito in XML, come descritto in questo documento.

La Figura 2 mostra come questi componenti si inseriscono nel flusso di elaborazione complessivo dei widget dell'app.

Flusso di elaborazione del widget dell'app
Figura 2. Flusso di elaborazione del widget dell'app.

Se il widget richiede la configurazione utente, implementa l'attività di configurazione del widget dell'app. Questa attività consente agli utenti di modificare le impostazioni del widget, ad esempio il fuso orario di un widget orologio.

Consigliamo inoltre i seguenti miglioramenti: layout flessibili dei widget, miglioramenti vari, widget avanzati, widget di raccolta e creazione di un host per i widget.

Dichiara il file XML AppWidgetProviderInfo

L'oggetto AppWidgetProviderInfo definisce le qualità essenziali di un widget. Definisci l'oggetto AppWidgetProviderInfo in un file di risorse XML utilizzando un singolo elemento <appwidget-provider> e salvalo nella cartella res/xml/ del progetto.

come illustrato nell'esempio seguente:

<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>

Attributi relativi alle dimensioni del widget

La schermata Home predefinita posiziona i widget nella finestra in base a una griglia di celle con altezza e larghezza definite. La maggior parte delle schermate Home consente ai widget di assumere dimensioni uguali a multipli interi delle celle della griglia, ad esempio due celle orizzontalmente per tre celle in verticale.

Gli attributi relativi alle dimensioni del widget consentono di specificare una dimensione predefinita per il widget e fornire limiti inferiori e superiori per le dimensioni del widget. In questo contesto, la dimensione predefinita di un widget è la dimensione che assume quando viene aggiunto per la prima volta alla schermata Home.

Nella tabella seguente vengono descritti gli attributi <appwidget-provider> relativi alle dimensioni dei widget:

Attributi e descrizione
targetCellWidth e targetCellHeight (Android 12), minWidth e minHeight
  • A partire da Android 12, gli attributi targetCellWidth e targetCellHeight specificano le dimensioni predefinite del widget in termini di celle della griglia. Questi attributi vengono ignorati in Android 11 e versioni precedenti e possono essere ignorati se la schermata Home non supporta un layout basato su griglia.
  • Gli attributi minWidth e minHeight specificano la dimensione predefinita del widget in dp. Se i valori per l'altezza o la larghezza minima di un widget non corrispondono alle dimensioni delle celle, i valori vengono arrotondati per eccesso alla dimensione della cella più vicina.
Ti consigliamo di specificare entrambi i set di attributi, targetCellWidth e targetCellHeight, minWidth e minHeight, in modo che la tua app possa utilizzare minWidth e minHeight se il dispositivo dell'utente non supporta targetCellWidth e targetCellHeight. Se supportati, gli attributi targetCellWidth e targetCellHeight hanno la precedenza sugli attributi minWidth e minHeight.
minResizeWidth e minResizeHeight Specifica la dimensione minima assoluta del widget. Questi valori specificano le dimensioni sotto le quali il widget è illeggibile o comunque inutilizzabile. L'utilizzo di questi attributi consente all'utente di ridimensionare il widget a una dimensione inferiore a quella predefinita. L'attributo minResizeWidth viene ignorato se è maggiore di minWidth o se il ridimensionamento orizzontale non è abilitato. Consulta la pagina resizeMode. Allo stesso modo, l'attributo minResizeHeight viene ignorato se è superiore a minHeight o se il ridimensionamento verticale non è abilitato.
maxResizeWidth e maxResizeHeight Specifica la dimensione massima consigliata del widget. Se i valori non sono multipli delle dimensioni delle celle della griglia, vengono arrotondati per eccesso alla dimensione della cella più vicina. L'attributo maxResizeWidth viene ignorato se è inferiore a minWidth o se il ridimensionamento orizzontale non è abilitato. Vedi resizeMode. Allo stesso modo, l'attributo maxResizeHeight viene ignorato se è superiore a minHeight o se il ridimensionamento verticale non è abilitato. Introdotta in Android 12.
resizeMode Specifica le regole in base alle quali un widget può essere ridimensionato. Puoi utilizzare questo attributo per rendere i widget della schermata Home ridimensionabili orizzontalmente, verticalmente o su entrambi gli assi. Gli utenti toccano e tieni premuti un widget per visualizzare i relativi punti di manipolazione di ridimensionamento, quindi trascinano quelli orizzontali o verticali per modificarne le dimensioni sulla griglia di layout. I valori dell'attributo resizeMode includono horizontal, vertical e none. Per dichiarare un widget come ridimensionabile orizzontalmente e verticalmente, utilizza horizontal|vertical.

Esempio

Per illustrare in che modo gli attributi nella tabella precedente influiscono sulle dimensioni del widget, supponiamo le seguenti specifiche:

  • Una cella della griglia ha una larghezza di 30 dp e un'altezza di 50 dp.
  • Vengono fornite le seguenti specifiche degli attributi:
<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" />

A partire da Android 12:

Utilizza gli attributi targetCellWidth e targetCellHeight come dimensione predefinita del widget.

Le dimensioni del widget sono 2 x 2 per impostazione predefinita. Il widget può essere ridimensionato a 2 x 1 o fino a 4 x 3.

Android 11 e versioni precedenti:

Utilizza gli attributi minWidth e minHeight per calcolare la dimensione predefinita del widget.

La larghezza predefinita = Math.ceil(80 / 30) = 3

L'altezza predefinita = Math.ceil(80 / 50) = 2

Le dimensioni del widget sono 3 x 2 per impostazione predefinita. Il widget può essere ridimensionato a 2 x 1 o in alto a schermo intero.

Attributi widget aggiuntivi

Nella tabella seguente vengono descritti gli attributi <appwidget-provider> relativi a qualità diverse dalle dimensioni del widget.

Attributi e descrizione
updatePeriodMillis Definisce la frequenza con cui il framework del widget richiede un aggiornamento da AppWidgetProvider chiamando il metodo di callback onUpdate(). Con questo valore non è garantito che l'aggiornamento effettivo avvenga esattamente in tempo, perciò ti consigliamo di eseguire l'aggiornamento il più raramente possibile e non più di una volta all'ora, per risparmiare batteria. Per l'elenco completo delle considerazioni sulla scelta di un periodo di aggiornamento appropriato, consulta la pagina Ottimizzazioni per l'aggiornamento dei contenuti del widget.
initialLayout Indica la risorsa di layout che definisce il layout del widget.
configure Definisce l'attività che viene avviata quando l'utente aggiunge il widget, permettendogli di configurare le proprietà del widget. Vedi Consentire agli utenti di configurare i widget. A partire da Android 12, la tua app può saltare la configurazione iniziale. Per maggiori dettagli, consulta Utilizzare la configurazione predefinita del widget.
description Specifica la descrizione del selettore del widget da visualizzare per il widget. Introdotta in Android 12.
previewLayout (Android 12) e previewImage (Android 11 e versioni precedenti)
  • A partire da Android 12, l'attributo previewLayout specifica un'anteprima scalabile, che fornisci come layout XML impostato sulle dimensioni predefinite del widget. Idealmente, il codice XML di layout specificato come attributo è lo stesso XML di layout del widget effettivo con valori predefiniti realistici.
  • In Android 11 o versioni precedenti, l'attributo previewImage specifica un'anteprima dell'aspetto del widget dopo la configurazione e l'utente vede quando seleziona il widget dell'app. Se non viene specificata, l'utente vede l'icona in Avvio applicazioni dell'app. Questo campo corrisponde all'attributo android:previewImage nell'elemento <receiver> nel file AndroidManifest.xml.
Nota: ti consigliamo di specificare entrambi gli attributi previewImage e previewLayout in modo che la tua app possa utilizzare previewImage se il dispositivo dell'utente non supporta previewLayout. Per maggiori dettagli, consulta la pagina relativa alla compatibilità con le versioni precedenti delle anteprime dei widget scalabili.
autoAdvanceViewId Specifica l'ID visualizzazione della visualizzazione secondaria del widget che viene avanzata automaticamente dall'host del widget.
widgetCategory Dichiara se il widget può essere visualizzato sulla schermata Home (home_screen), sulla schermata di blocco (keyguard) o su entrambe. Per Android 5.0 e versioni successive, è valido soltanto home_screen.
widgetFeatures Dichiara le funzionalità supportate dal widget. Ad esempio, se vuoi che il widget utilizzi la sua configurazione predefinita quando un utente lo aggiunge, specifica entrambi i flag configuration_optional e reconfigurable. Ciò ignora l'avvio dell'attività di configurazione dopo che un utente ha aggiunto il widget. L'utente può comunque riconfigurare il widget in seguito.

Utilizzare la classe AppWidgetProvider per gestire le trasmissioni del widget

La classe AppWidgetProvider gestisce le trasmissioni del widget e lo aggiorna in risposta agli eventi del ciclo di vita del widget. Le seguenti sezioni descrivono come dichiarare AppWidgetProvider nel file manifest e quindi implementarlo.

Dichiara un widget nel file manifest

Innanzitutto, dichiara la classe AppWidgetProvider nel file AndroidManifest.xml dell'app, come mostrato nell'esempio seguente:

<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'elemento <receiver> richiede l'attributo android:name, che specifica il valore AppWidgetProvider utilizzato dal widget. Il componente non deve essere esportato a meno che non sia necessario un processo separato per trasmettere al tuo AppWidgetProvider, il che di solito non è.

L'elemento <intent-filter> deve includere un elemento <action> con l'attributo android:name. Questo attributo specifica che AppWidgetProvider accetta la trasmissione di ACTION_APPWIDGET_UPDATE. Questa è l'unica trasmissione che devi dichiarare esplicitamente. AppWidgetManager invia automaticamente tutti gli altri annunci del widget a AppWidgetProvider, se necessario.

L'elemento <meta-data> specifica la risorsa AppWidgetProviderInfo e richiede i seguenti attributi:

  • android:name: specifica il nome dei metadati. Utilizza android.appwidget.provider per identificare i dati come descrittore AppWidgetProviderInfo.
  • android:resource: specifica la località della risorsa AppWidgetProviderInfo.

Implementare la classe AppWidgetProvider

La classe AppWidgetProvider estende BroadcastReceiver come classe di comodità per gestire le trasmissioni dei widget. Riceve solo le trasmissioni di eventi che sono pertinenti al widget, ad esempio quando il widget viene aggiornato, eliminato, attivato e disattivato. Quando si verificano questi eventi di trasmissione, vengono chiamati i seguenti metodi AppWidgetProvider:

onUpdate()
Questa operazione viene chiamata per aggiornare il widget a intervalli definiti dall'attributo updatePeriodMillis in AppWidgetProviderInfo. Per ulteriori informazioni, consulta la tabella che descrive gli attributi aggiuntivi del widget in questa pagina.
Questo metodo viene chiamato anche quando l'utente aggiunge il widget, quindi esegue la configurazione essenziale, come la definizione dei gestori di eventi per gli oggetti View o l'avvio di job per caricare i dati da visualizzare nel widget. Tuttavia, se dichiari un'attività di configurazione senza il flag configuration_optional, questo metodo non viene chiamato quando l'utente aggiunge il widget, ma viene richiesto per gli aggiornamenti successivi. È responsabilità dell'attività di configurazione eseguire il primo aggiornamento al termine della configurazione. Per ulteriori informazioni, vedi Consentire agli utenti di configurare i widget delle app.
Il callback più importante è onUpdate(). Per saperne di più, consulta Gestire gli eventi con la classe onUpdate() in questa pagina.
onAppWidgetOptionsChanged()

Questo avviene quando il widget viene posizionato per la prima volta e ogni volta che viene ridimensionato. Usa questo callback per mostrare o nascondere i contenuti in base agli intervalli di dimensioni del widget. Per conoscere gli intervalli di dimensioni e, a partire da Android 12, l'elenco delle possibili dimensioni che un'istanza di widget può assumere, chiama getAppWidgetOptions(), che restituisce un Bundle che include quanto segue:

onDeleted(Context, int[])

Questa operazione viene richiamata ogni volta che un widget viene eliminato dall'host.

onEnabled(Context)

Questo avviene quando viene creata un'istanza del widget per la prima volta. Ad esempio, se l'utente aggiunge due istanze del widget, l'operazione viene denominata solo la prima volta. Se devi aprire un nuovo database o eseguire un'altra configurazione che deve essere eseguita una sola volta per tutte le istanze del widget, questo è il posto giusto per farlo.

onDisabled(Context)

Questo avviene quando l'ultima istanza del widget viene eliminata dall'host del widget. È qui che esegui la pulizia di qualsiasi operazione eseguita in onEnabled(Context), ad esempio l'eliminazione di un database temporaneo.

onReceive(Context, Intent)

Questa operazione viene richiesta per ogni trasmissione e prima di ciascuno dei metodi di callback precedenti. Di solito non è necessario implementare questo metodo perché l'implementazione predefinita di AppWidgetProvider filtra tutte le trasmissioni dei widget e chiama i metodi precedenti in base alle esigenze.

Devi dichiarare l'implementazione della classe AppWidgetProvider come ricevitore trasmissione utilizzando l'elemento <receiver> in AndroidManifest. Per ulteriori informazioni, consulta la sezione Dichiarare un widget nel file manifest in questa pagina.

Gestire gli eventi con la classe onUpdate()

Il callback AppWidgetProvider più importante è onUpdate(), perché viene richiamato quando ogni widget viene aggiunto a un host, a meno che non utilizzi un'attività di configurazione senza il flag configuration_optional. Se il widget accetta eventi di interazione con l'utente, registra i gestori di eventi in questo callback. Se il widget non crea file temporanei o database o non esegue altre operazioni che richiedono una pulizia, onUpdate() potrebbe essere l'unico metodo di callback che devi definire.

Ad esempio, se vuoi un widget con un pulsante che avvia un'attività quando viene toccato, puoi utilizzare la seguente implementazione di 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);
        }
    }
}

Questo AppWidgetProvider definisce solo il metodo onUpdate(), utilizzandolo per creare una PendingIntent che avvia Activity e la collega al pulsante del widget utilizzando setOnClickPendingIntent(int, PendingIntent). Include un loop che esegue l'iterazione di ogni voce in appWidgetIds, che è un array di ID che identificano ogni widget creato da questo provider. Se l'utente crea più di un'istanza del widget, vengono aggiornate tutte contemporaneamente. Tuttavia, viene gestita una sola pianificazione updatePeriodMillis per tutte le istanze del widget. Ad esempio, se la pianificazione dell'aggiornamento è definita ogni due ore e una seconda istanza del widget viene aggiunta un'ora dopo la prima, entrambe vengono aggiornate nel periodo definito dalla prima, mentre la seconda istanza del widget viene ignorata. Entrambi si aggiornano ogni due ore, non ogni ora.

Per ulteriori dettagli, consulta la classe di esempio ExampleAppWidgetProvider.java.

Ricevi intent di trasmissione widget

AppWidgetProvider è un corso di convenienza. Se vuoi ricevere direttamente le trasmissioni del widget, puoi implementare BroadcastReceiver o sostituire il callback onReceive(Context,Intent). Ecco gli intenti che ti interessano:

Crea il layout del widget

Devi definire un layout iniziale per il widget in XML e salvarlo nella directory res/layout/ del progetto. Consulta le linee guida di progettazione per i dettagli.

Se hai dimestichezza con i layout, la creazione del layout del widget è semplice. Tuttavia, tieni presente che i layout dei widget sono basati su RemoteViews, che non supporta tutti i tipi di layout o widget di visualizzazione. Non puoi utilizzare le viste personalizzate o le sottoclassi delle viste supportate da RemoteViews.

RemoteViews supporta anche ViewStub, una View invisibile di dimensioni pari a zero che puoi usare per incrementare lentamente le risorse di layout in fase di runtime.

Supporto per il comportamento stateful

Android 12 aggiunge il supporto per il comportamento stateful usando i seguenti componenti esistenti:

Il widget è ancora stateless. L'app deve archiviare lo stato e registrarsi per gli eventi di modifica dello stato.

Esempio di widget lista della spesa che mostra il comportamento stateful
Figura 3. Esempio di comportamento stateful.

L'esempio di codice riportato di seguito mostra come implementare questi componenti.

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

Fornisci due layout: uno che ha come target i dispositivi con Android 12 o versioni successive in res/layout-v31 e l'altro che ha come target il sistema operativo Android 11 o versioni precedenti nella cartella res/layout predefinita.

Implementare gli angoli arrotondati

Android 12 introduce i seguenti parametri di sistema per impostare i raggi degli angoli arrotondati del widget:

  • system_app_widget_background_radius: il raggio d'angolo dello sfondo del widget, che non supera mai i 28 dp.

  • system_app_widget_inner_radius: il raggio d'angolo di qualsiasi vista all'interno del widget. Questo valore è esattamente 8 dp in meno rispetto al raggio dello sfondo, per un allineamento corretto quando si utilizza una spaziatura interna di 8 dp.

L'esempio seguente mostra un widget che utilizza system_app_widget_background_radius per l'angolo del widget e system_app_widget_inner_radius per le visualizzazioni all'interno del widget.

Widget che mostra i raggi dello sfondo e le visualizzazioni all&#39;interno del widget
Figura 4. Angoli arrotondati.

1 Angolo del widget.

2 Angolo di una visualizzazione all'interno del widget.

Considerazioni importanti per gli angoli arrotondati

  • Gli strumenti di avvio app e i produttori di dispositivi di terze parti possono sostituire il parametro system_app_widget_background_radius in modo che sia inferiore a 28 dp. Il parametro system_app_widget_inner_radius è sempre inferiore di 8 dp rispetto al valore di system_app_widget_background_radius.
  • Se il tuo widget non utilizza @android:id/background o non definisci uno sfondo che ritaglia i contenuti in base al contorno (con l'opzione android:clipToOutline impostata su true), Avvio app identifica automaticamente lo sfondo e taglia il widget utilizzando un rettangolo con angoli arrotondati fino a 16 dp. Vedi Assicurarsi che il widget sia compatibile con Android 12.

Per la compatibilità dei widget con le versioni precedenti di Android, ti consigliamo di definire attributi personalizzati e di utilizzare un tema personalizzato per sostituirli per Android 12, come mostrato nei seguenti file XML di esempio:

/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" />