Membuat widget sederhana

Widget aplikasi adalah tampilan aplikasi mini yang dapat Anda sematkan di aplikasi lain—seperti layar utama—dan menerima update berkala. Tampilan ini disebut sebagai widget di antarmuka pengguna, dan Anda dapat memublikasikannya dengan penyedia widget aplikasi (atau penyedia widget). Komponen aplikasi yang menyimpan widget lain disebut host widget aplikasi (atau host widget). Gambar 1 menunjukkan contoh widget musik:

Contoh widget musik
Gambar 1. Contoh widget musik.

Dokumen ini menjelaskan cara memublikasikan widget menggunakan penyedia widget. Untuk mengetahui detail tentang cara membuat AppWidgetHost Anda sendiri untuk menghosting widget aplikasi, lihat Mem-build host widget.

Untuk informasi tentang cara mendesain widget, lihat Ringkasan widget aplikasi.

Komponen widget

Untuk membuat widget, Anda memerlukan komponen dasar berikut:

Objek AppWidgetProviderInfo
Menjelaskan metadata untuk widget, seperti tata letak widget, frekuensi update, dan class AppWidgetProvider. AppWidgetProviderInfo ditentukan dalam XML, seperti yang dijelaskan dalam dokumen ini.
Class AppWidgetProvider
Menentukan metode dasar yang memungkinkan Anda berinteraksi secara terprogram dengan widget. Melalui aplikasi ini, Anda akan menerima siaran saat widget diupdate, diaktifkan, dinonaktifkan, atau dihapus. Anda mendeklarasikan AppWidgetProvider dalam manifes, lalu menerapkannya, seperti yang dijelaskan dalam dokumen ini.
Tata letak tampilan
Menentukan tata letak awal untuk widget. Tata letak ditentukan dalam XML, seperti yang dijelaskan dalam dokumen ini.

Gambar 2 menunjukkan bagaimana komponen ini sesuai dengan alur pemrosesan widget aplikasi keseluruhan.

Alur pemrosesan widget aplikasi
Gambar 2. Alur pemrosesan widget aplikasi.

Jika widget Anda memerlukan konfigurasi pengguna, terapkan aktivitas konfigurasi widget aplikasi. Aktivitas ini memungkinkan pengguna mengubah setelan widget—misalnya, zona waktu untuk widget jam.

Kami juga menyarankan peningkatan berikut: tata letak widget yang fleksibel, peningkatan lain-lain, widget lanjutan, widget koleksi, dan mem-build host widget.

Mendeklarasikan XML AppWidgetProviderInfo

Objek AppWidgetProviderInfo menentukan kualitas penting widget. Tentukan objek AppWidgetProviderInfo dalam file resource XML menggunakan satu elemen <appwidget-provider> dan simpan di folder res/xml/ project.

Hal ini ditunjukkan dalam contoh berikut:

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

Atribut ukuran widget

Layar utama default menempatkan widget di jendelanya berdasarkan petak sel yang memiliki tinggi dan lebar yang ditentukan. Sebagian besar layar utama hanya mengizinkan widget menggunakan ukuran yang merupakan kelipatan bilangan bulat dari sel petak—misalnya, dua sel secara horizontal dengan tiga sel secara vertikal.

Atribut ukuran widget memungkinkan Anda menentukan ukuran default untuk widget dan memberikan batas bawah dan atas pada ukuran widget. Dalam konteks ini, ukuran default widget adalah ukuran yang digunakan widget saat pertama kali ditambahkan ke layar utama.

Tabel berikut menjelaskan atribut <appwidget-provider> yang berkaitan dengan ukuran widget:

Atribut dan deskripsi
targetCellWidth dan targetCellHeight (Android 12), minWidth dan minHeight
  • Mulai dari Android 12, atribut targetCellWidth dan targetCellHeight menentukan ukuran default widget dalam hal sel petak. Atribut ini diabaikan di Android 11 dan yang lebih rendah, dan dapat diabaikan jika layar utama tidak mendukung tata letak berbasis petak.
  • Atribut minWidth dan minHeight menentukan ukuran default widget dalam dp. Jika nilai untuk lebar atau tinggi minimum widget tidak cocok dengan dimensi sel, nilai akan dibulatkan ke atas ke ukuran sel terdekat.
Sebaiknya tentukan kedua kumpulan atribut—targetCellWidth dan targetCellHeight, serta minWidth dan minHeight—sehingga aplikasi Anda dapat kembali menggunakan minWidth dan minHeight jika perangkat pengguna tidak mendukung targetCellWidth dan targetCellHeight. Jika didukung, atribut targetCellWidth dan targetCellHeight akan lebih diutamakan daripada atribut minWidth dan minHeight.
minResizeWidth dan minResizeHeight Tentukan ukuran minimum widget yang mutlak. Nilai ini menentukan ukuran yang akan menjadikan widget tidak terbaca atau tidak dapat digunakan. Penggunaan atribut ini memungkinkan pengguna mengubah ukuran widget ke ukuran yang lebih kecil dari ukuran widget default. Atribut minResizeWidth diabaikan jika lebih besar dari minWidth atau jika pengubahan ukuran horizontal tidak diaktifkan. Lihat resizeMode. Demikian pula, atribut minResizeHeight akan diabaikan jika lebih besar dari minHeight atau jika pengubahan ukuran vertikal tidak diaktifkan.
maxResizeWidth dan maxResizeHeight Tentukan ukuran maksimum widget yang direkomendasikan. Jika nilainya bukan kelipatan dimensi sel petak, nilai tersebut akan dibulatkan ke atas ke ukuran sel terdekat. Atribut maxResizeWidth diabaikan jika lebih kecil dari minWidth atau jika pengubahan ukuran horizontal tidak diaktifkan. Lihat resizeMode. Demikian pula, atribut maxResizeHeight akan diabaikan jika lebih besar dari minHeight atau jika pengubahan ukuran vertikal tidak diaktifkan. Diperkenalkan di Android 12.
resizeMode Menentukan aturan yang digunakan untuk mengubah ukuran widget. Anda dapat menggunakan atribut ini untuk membuat widget layar utama dapat diubah ukurannya secara horizontal, vertikal, atau pada kedua sumbu. Pengguna menyentuh lama widget untuk menampilkan tuas pengubah ukuran, lalu menarik tuas horizontal atau vertikal untuk mengubah ukurannya di petak tata letak. Nilai untuk atribut resizeMode mencakup horizontal, vertical, dan none. Untuk mendeklarasikan widget sebagai dapat diubah ukurannya secara horizontal dan vertikal, gunakan horizontal|vertical.

Contoh

Untuk menggambarkan pengaruh atribut dalam tabel sebelumnya terhadap ukuran widget, asumsikan spesifikasi berikut:

  • Sel petak berukuran lebar 30 dp dan tinggi 50 dp.
  • Spesifikasi atribut berikut disediakan:
<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" />

Mulai Android 12:

Gunakan atribut targetCellWidth dan targetCellHeight sebagai ukuran default widget.

Ukuran widget adalah 2x2 secara default. Ukuran widget dapat diperkecil hingga 2x1 atau diperbesar hingga 4x3.

Android 11 dan yang lebih lama:

Gunakan atribut minWidth dan minHeight untuk menghitung ukuran default widget.

Lebar default = Math.ceil(80 / 30) = 3

Tinggi default = Math.ceil(80 / 50) = 2

Ukuran widget adalah 3x2 secara default. Ukuran widget dapat diperkecil hingga 2x1 atau diperbesar hingga layar penuh.

Atribut widget tambahan

Tabel berikut menjelaskan atribut <appwidget-provider> yang berkaitan dengan kualitas selain ukuran widget.

Atribut dan deskripsi
updatePeriodMillis Menentukan seberapa sering framework widget meminta update dari AppWidgetProvider dengan memanggil metode callback onUpdate(). Update yang sebenarnya belum tentu terjadi tepat waktu dengan nilai ini, dan sebaiknya Anda mengupdate sesering mungkin —tidak lebih dari satu kali dalam satu jam—untuk menghemat baterai. Untuk daftar lengkap pertimbangan dalam memilih periode pembaruan yang sesuai, lihat Pengoptimalan untuk memperbarui konten widget.
initialLayout Menunjuk ke resource tata letak yang menentukan tata letak widget.
configure Menentukan aktivitas yang diluncurkan saat pengguna menambahkan widget, sehingga mereka dapat mengonfigurasi properti widget. Lihat Memungkinkan pengguna mengonfigurasi widget. Mulai Android 12, aplikasi Anda dapat melewati konfigurasi awal. Lihat Menggunakan konfigurasi default widget untuk mengetahui detailnya.
description Menentukan deskripsi untuk alat pilih widget yang akan ditampilkan untuk widget Anda. Diperkenalkan di Android 12.
previewLayout (Android 12) dan previewImage (Android 11 dan yang lebih lama)
  • Mulai Android 12, atribut previewLayout menentukan pratinjau skalabel, yang Anda berikan sebagai tata letak XML yang disetel ke ukuran default widget. Idealnya, XML tata letak yang ditentukan sebagai atribut ini adalah XML tata letak yang sama dengan widget sebenarnya dengan nilai default yang realistis.
  • Di Android 11 atau yang lebih rendah, atribut previewImage menentukan pratinjau tampilan widget setelah dikonfigurasi, yang akan dilihat pengguna saat memilih widget aplikasi. Jika tidak disediakan, pengguna akan melihat ikon peluncur aplikasi Anda. Kolom ini sesuai dengan atribut android:previewImage di elemen <receiver> dalam file AndroidManifest.xml.
Catatan: Sebaiknya tentukan atribut previewImage dan previewLayout agar aplikasi Anda dapat kembali menggunakan previewImage jika perangkat pengguna tidak mendukung previewLayout. Untuk mengetahui detail selengkapnya, lihat Kompatibilitas mundur dengan pratinjau widget yang skalabel.
autoAdvanceViewId Menentukan ID tampilan sub-tampilan widget yang dimajukan secara otomatis oleh host widget.
widgetCategory Mendeklarasikan apakah widget Anda dapat ditampilkan di layar utama (home_screen), layar kunci (keyguard), atau keduanya. Untuk Android 5.0 dan yang lebih tinggi, hanya home_screen yang valid.
widgetFeatures Mendeklarasikan fitur yang didukung oleh widget. Misalnya, jika Anda ingin widget menggunakan konfigurasi default saat pengguna menambahkannya, tentukan flag configuration_optional dan reconfigurable. Tindakan ini akan mengabaikan peluncuran aktivitas konfigurasi setelah pengguna menambahkan widget. Pengguna masih dapat mengonfigurasi ulang widget setelahnya.

Menggunakan class AppWidgetProvider untuk menangani siaran widget

Class AppWidgetProvider menangani siaran widget dan memperbarui widget sebagai respons terhadap peristiwa siklus proses widget. Bagian berikut menjelaskan cara mendeklarasikan AppWidgetProvider dalam manifes, lalu menerapkannya.

Mendeklarasikan widget dalam manifes

Pertama, deklarasikan class AppWidgetProvider dalam file AndroidManifest.xml aplikasi Anda, seperti yang ditunjukkan dalam contoh berikut:

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

Elemen <receiver> memerlukan atribut android:name, yang menentukan AppWidgetProvider yang digunakan oleh widget. Komponen tidak boleh diekspor kecuali jika proses terpisah perlu disiarkan ke AppWidgetProvider Anda, yang biasanya tidak terjadi.

Elemen <intent-filter> harus menyertakan elemen <action> dengan atribut android:name. Atribut ini menentukan bahwa AppWidgetProvider menerima siaran ACTION_APPWIDGET_UPDATE. Siaran ini merupakan satu-satunya yang harus Anda deklarasikan secara eksplisit. AppWidgetManager secara otomatis mengirimkan semua siaran widget lainnya ke AppWidgetProvider sesuai kebutuhan.

Elemen <meta-data> menentukan resource AppWidgetProviderInfo dan memerlukan atribut berikut:

  • android:name: menentukan nama metadata. Gunakan android.appwidget.provider untuk mengidentifikasi data sebagai deskripsi AppWidgetProviderInfo.
  • android:resource: menentukan lokasi resource AppWidgetProviderInfo.

Mengimplementasikan class AppWidgetProvider

Class AppWidgetProvider memperluas BroadcastReceiver sebagai class praktis untuk menangani siaran widget. Class ini hanya menerima siaran peristiwa yang relevan dengan widget, seperti saat widget diupdate, dihapus, diaktifkan, dan dinonaktifkan. Saat peristiwa siaran ini terjadi, metode AppWidgetProvider berikut akan dipanggil:

onUpdate()
Callback ini dipanggil untuk mengupdate widget pada interval yang ditentukan oleh atribut updatePeriodMillis di AppWidgetProviderInfo. Lihat tabel yang menjelaskan atribut widget tambahan di halaman ini untuk mengetahui informasi selengkapnya.
Metode ini juga dipanggil saat pengguna menambahkan widget, sehingga melakukan penyiapan penting seperti menentukan pengendali peristiwa untuk objek View atau memulai tugas untuk memuat data yang akan ditampilkan di widget. Namun, jika Anda mendeklarasikan aktivitas konfigurasi tanpa tanda configuration_optional, metode ini tidak dipanggil saat pengguna menambahkan widget, tetapi akan dipanggil untuk update berikutnya. Aktivitas konfigurasi bertanggung jawab untuk melakukan update pertama saat konfigurasi selesai. Lihat Memungkinkan pengguna mengonfigurasi widget aplikasi untuk informasi selengkapnya.
Callback yang paling penting adalah onUpdate(). Lihat Menangani peristiwa dengan class onUpdate() di halaman ini untuk mengetahui informasi selengkapnya.
onAppWidgetOptionsChanged()

Callback ini dipanggil saat widget pertama kali ditempatkan dan setiap kali ukuran widget diubah. Gunakan callback ini untuk menampilkan atau menyembunyikan konten berdasarkan rentang ukuran widget. Dapatkan rentang ukuran—dan, mulai Android 12, daftar kemungkinan ukuran yang dapat diambil instance widget—dengan memanggil getAppWidgetOptions(), yang menampilkan Bundle yang menyertakan hal berikut:

onDeleted(Context, int[])

Callback ini dipanggil setiap kali widget dihapus dari host widget.

onEnabled(Context)

Fungsi ini dipanggil saat instance widget dibuat untuk pertama kalinya. Misalnya, jika pengguna menambahkan dua instance widget Anda, callback ini hanya dipanggil untuk pertama kalinya. Jika Anda perlu membuka database baru atau melakukan penyiapan lain yang hanya perlu dilakukan sekali untuk semua instance widget, ini adalah tempat yang tepat untuk melakukannya.

onDisabled(Context)

Callback ini dipanggil saat instance terakhir widget Anda dihapus dari host widget. Ini adalah tempat Anda membersihkan semua pekerjaan yang dilakukan di onEnabled(Context), seperti menghapus database sementara.

onReceive(Context, Intent)

Callback ini dipanggil untuk setiap siaran dan sebelum setiap metode callback sebelumnya. Anda biasanya tidak perlu menerapkan metode ini, karena penerapan AppWidgetProvider default memfilter semua siaran widget dan memanggil metode sebelumnya yang sesuai.

Anda harus mendeklarasikan implementasi class AppWidgetProvider sebagai penerima siaran menggunakan elemen <receiver> di AndroidManifest. Lihat Mendeklarasikan widget dalam manifes di halaman ini untuk informasi selengkapnya.

Menangani peristiwa dengan class onUpdate()

Callback AppWidgetProvider yang paling penting adalah onUpdate(), karena dipanggil saat setiap widget ditambahkan ke host, kecuali jika Anda menggunakan aktivitas konfigurasi tanpa flag configuration_optional. Jika widget Anda menerima peristiwa interaksi pengguna apa pun, daftarkan pengendali peristiwa dalam callback ini. Jika widget Anda tidak membuat file atau database sementara, atau menjalankan pekerjaan lain yang memerlukan pembersihan, onUpdate() mungkin merupakan satu-satunya metode callback yang perlu Anda tentukan.

Misalnya, jika Anda menginginkan widget dengan tombol yang meluncurkan aktivitas saat diketuk, Anda dapat menggunakan penerapan AppWidgetProvider berikut:

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

AppWidgetProvider ini hanya menentukan metode onUpdate(), menggunakannya untuk membuat PendingIntent yang meluncurkan Activity dan melampirkannya ke tombol widget menggunakan setOnClickPendingIntent(int, PendingIntent). Ini mencakup loop yang melakukan iterasi melalui setiap entri di appWidgetIds, yang merupakan array ID yang mengidentifikasi setiap widget yang dibuat oleh penyedia ini. Jika pengguna membuat lebih dari satu instance widget, semua instance tersebut akan diupdate secara bersamaan. Namun, hanya satu jadwal updatePeriodMillis yang dikelola untuk semua instance widget. Misalnya, jika jadwal update ditentukan setiap dua jam, dan instance kedua widget ditambahkan satu jam setelah yang pertama, keduanya akan diperbarui pada periode yang ditentukan oleh yang pertama, dan periode update kedua akan diabaikan. Keduanya diperbarui setiap dua jam, bukan setiap jam.

Lihat class contoh ExampleAppWidgetProvider.java untuk detail selengkapnya.

Menerima intent siaran widget

AppWidgetProvider adalah class praktis. Jika ingin menerima siaran widget secara langsung, Anda dapat menerapkan BroadcastReceiver sendiri atau mengganti callback onReceive(Context,Intent). Intent yang perlu Anda perhatikan adalah berikut:

Membuat tata letak widget

Anda harus menentukan tata letak awal untuk widget dalam XML dan menyimpannya di direktori res/layout/ project. Lihat Panduan desain untuk mengetahui detailnya.

Membuat tata letak widget cukup mudah jika Anda sudah memahami tata letak. Namun, perlu diketahui bahwa tata letak widget didasarkan pada RemoteViews, yang tidak mendukung setiap jenis tata letak atau widget tampilan. Anda tidak dapat menggunakan tampilan kustom atau subclass tampilan yang didukung oleh RemoteViews.

RemoteViews juga mendukung ViewStub, yang merupakan View tidak terlihat dan berukuran nol yang dapat Anda gunakan untuk meng-inflate resource tata letak secara lambat saat runtime.

Dukungan untuk perilaku stateful

Android 12 menambahkan dukungan untuk perilaku stateful menggunakan komponen yang ada berikut:

Widget tetap stateless. Aplikasi Anda harus menyimpan status dan mendaftar peristiwa perubahan status.

Contoh widget daftar belanja yang menampilkan perilaku stateful
Gambar 3. Contoh perilaku stateful.

Contoh kode berikut menunjukkan cara menerapkan komponen ini.

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

Sediakan dua tata letak: satu menargetkan perangkat yang menjalankan Android 12 atau yang lebih tinggi di res/layout-v31, dan yang lainnya menargetkan Android 11 sebelumnya atau yang lebih rendah di folder res/layout default.

Menerapkan sudut bulat

Android 12 memperkenalkan parameter sistem berikut untuk menyetel radius sudut membulat widget Anda:

Contoh berikut menunjukkan widget yang menggunakan system_app_widget_background_radius untuk sudut widget dan system_app_widget_inner_radius untuk tampilan di dalam widget.

Widget yang menunjukkan radius latar belakang widget dan tampilan di dalam widget
Gambar 4. Sudut membulat.

1 Sudut widget.

2 Sudut tampilan di dalam widget.

Pertimbangan penting untuk sudut membulat

  • Peluncur pihak ketiga dan produsen perangkat dapat mengganti parameter system_app_widget_background_radius menjadi lebih kecil dari 28 dp. Parameter system_app_widget_inner_radius selalu 8 dp lebih kecil dari nilai system_app_widget_background_radius.
  • Jika widget Anda tidak menggunakan @android:id/background atau menentukan latar belakang yang mengklip kontennya berdasarkan garis batas—dengan android:clipToOutline yang disetel ke true—peluncur akan otomatis mengidentifikasi latar belakang dan memotong widget menggunakan persegi panjang dengan sudut membulat hingga 16 dp. Lihat Memastikan widget Anda kompatibel dengan Android 12.

Untuk kompatibilitas widget dengan versi Android sebelumnya, sebaiknya tentukan atribut khusus dan gunakan tema kustom untuk menggantinya untuk Android 12, seperti yang ditunjukkan dalam contoh file XML berikut:

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