Updating your widget for Android 12

Murat Yener
Android Developers
Published in
7 min readJul 22, 2021

--

Widgets have been part of the core Android experience for a long time, with many apps using widgets effectively to increase their user engagement. Users love widgets because of the ability to use app features without launching an app and to customize their device’s home screen.

Android 12 brings an update to existing widget APIs and revamps the design of widgets to align with the “Material You” design language. These changes allow you to build better-looking widgets that use device theme colors and rounded corners while enhancing discoverability and visuals for searching and placing widgets.

Before changes (Android 11) vs. after changes with light and dark theme (Android 12)

In this mini article series, we’ll take a look at updating your Widget for Android 12. In this part we’ll see some simple changes, which will make your widget look great on devices running Android 12 while also offering a consistent experience on older versions of Android. In the second part, we’ll take a look at new APIs which will make your widget more personalizable, more responsive, and offer more interactivity.

Visual Changes

It’s no surprise that style and design changes are the most visible ones to users. Updating the visual elements such as colors and corner radius instantly presents a more refreshed look. To start implementing these changes, we recommend creating a custom theme.

Add Dynamic Colors

Material You aims for a more customized user experience. With Android 12, dynamic colors allow your widget to be more consistent with other widgets and the system. Widgets can use the system’s default theme Theme.DeviceDefault.DayNight and use theme color attributes on the UI elements of the widget.

To do this, you need to create a custom theme from parent DeviceDefault for versions below 31.

values/themes.xml
<!-- Copyright 2019 Google LLC.
SPDX-License-Identifier: Apache-2.0 -->
<style name="Theme.AppWidget.AppWidgetContainer"
parent="@android:style/Theme.DeviceDefault" />

For version 31, use the parent theme DeviceDefault.DayNight to create a custom theme.

values-v31/themes.xml
<!-- Copyright 2019 Google LLC.
SPDX-License-Identifier: Apache-2.0 -->
<style name="Theme.AppWidget.AppWidgetContainer"
parent="@android:style/Theme.DeviceDefault.DayNight" />

Alternatively, if your app uses Material Components, you can use Theme.MaterialComponents.DayNight for the base theme instead of Theme.DeviceDefault.

To make your widget dynamically adopt system colors, assign this theme to your widget and use theme color attributes on other views.

layout/widget_checkbox_list_title_region.xml
<!-- Copyright 2019 Google LLC.
SPDX-License-Identifier: Apache-2.0 -->
...
<TextView android:id="@+id/checkbox_list_title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginStart="8dp"
android:layout_weight="1"
android:text="@string/grocery_list"
android:textColor="?android:attr/textColorPrimary" />
<ImageButton
android:layout_width="@dimen/widget_element_min_length"
android:layout_height="@dimen/widget_element_min_length"
android:background="?android:attr/selectableItemBackground"
android:clickable="true"
android:contentDescription="@string/add_button_grocery_list_content_description"
android:src="@drawable/ic_add_24"
android:tint="?android:attr/colorAccent" />
...
Static colors vs. dynamic colors in light/dark theme

Rounded Corners

Starting with Android 12, rounded corners are automatically applied to widgets. This means that the contents of the widget might be cut off by the applied corner masking. To avoid this and provide a more consistent look and user experience with other widgets and the system, you can use system_app_widget_background_radius to add rounded corners to your widget’s outline, and system_app_widget_inner_radius to add rounded corners to views within the widget. This value should be 8dp less than the system_app_widget_background_radius.

While doing this, keep in mind that if your widget has content close to its corners, this content might be cropped. To fix this, you need to add enough padding to avoid the content of the widget colliding with the rounded corners.

values/attrs.xml
<!-- Copyright 2019 Google LLC.
SPDX-License-Identifier: Apache-2.0 -->
<declare-styleable name="AppWidgetAttrs">
<attr name="appWidgetPadding" format="dimension" />
<attr name="appWidgetInnerRadius" format="dimension" />
<attr name="appWidgetRadius" format="dimension" />
</declare-styleable>
values/themes.xml
<!-- Copyright 2019 Google LLC.
SPDX-License-Identifier: Apache-2.0 -->
<style name="Theme.AppWidget.AppWidgetContainerParent"
parent="@android:style/Theme.DeviceDefault">
<!-- Radius of the outer bound of widgets to make the rounded
corners -->
<item name="appWidgetRadius">16dp</item>
<!-- Radius of the inner view's bound of widgets to make the rounded corners. It needs to be 8dp or less than the value of appWidgetRadius -->
<item name="appWidgetInnerRadius">8dp</item>
</style>
<style name="Theme.AppWidget.AppWidgetContainer"
parent="Theme.AppWidget.AppWidgetContainerParent">
<!-- Apply padding to avoid the content of the widget colliding with the rounded corners -->
<item name="appWidgetPadding">16dp</item>
</style>
values-v31/themes.xml
<!-- Copyright 2019 Google LLC.
SPDX-License-Identifier: Apache-2.0 -->
<style name="Theme.AppWidget.AppWidgetContainerParent"
parent="@android:style/Theme.DeviceDefault.DayNight">
<item name="appWidgetRadius">
@android:dimen/system_app_widget_background_radius</item>
<item name="appWidgetInnerRadius">
@android:dimen/system_app_widget_inner_radius</item>
</style>
values/styles.xml
<!-- Copyright 2019 Google LLC.
SPDX-License-Identifier: Apache-2.0 -->
<style name="Widget.AppWidget.AppWidget.Container"
parent="android:Widget">
<item name="android:id">@android:id/background</item>
<item name="android:background">
?android:attr/colorBackground</item>
</style>

If your minTargetSDK is lower than version 21, you need to provide styles for version 21 since android:attr/colorBackground used in the drawables requires API level 21.

Now that you created a theme, you can set the style on the widget’s layout.

layout/widget_grocery_list.xml
<!-- Copyright 2019 Google LLC.
SPDX-License-Identifier: Apache-2.0 -->
<LinearLayout
style="@style/Widget.AppWidget.AppWidget.Container">
...
</LinearLayout>
Before vs. automatic corner masking vs. rounded corners and applied padding

Transitions

Android 12 offers improved transitions when an app is launched from a widget. This transition is handled automatically by the system and will not be shown on older versions of Android. To enable this, you need to specify an id and set its value to android:id/background on the root element of your widget layout.

<LinearLayout
android:id="@android:id/background">
...
</LinearLayout>
Transition in slow motion

If your widget uses broadcast trampolines, which means your widget creates a PendingIntent on user click, to launch an activity from a broadcast receiver or service, this animation will not be used.

New widget picker improvements

Previews

Android 12 has a new and improved widget picker. Instead of using a static drawable resource, the new widget picker uses XML layout to dynamically create a scaled preview of your widget.

If your widget does not contain dynamic elements such as a ListView or GridView, you can simply use the widget’s layout for the preview.

To make this work, you need to set the default values directly to the original layout.

<!-- Copyright 2019 Google LLC.
SPDX-License-Identifier: Apache-2.0 -->
<TextView
style="@style/Widget.AppWidget.Checkbox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/widget_title_preview" />
<TextView
style="@style/Widget.AppWidget.Checkbox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/widget_subject_preview" />

Setting default values on the layout might cause a slight delay where the fake placeholder value is shown before the real value is applied. To prevent this alternatively you can create a separate layout file for the preview and apply a custom preview theme.

<!-- Copyright 2019 Google LLC.
SPDX-License-Identifier: Apache-2.0 -->
<resources>
<!-- Declare attributes -->
<attr name="widgetTitlePreview" format="string" />
<attr name="widgetSubjectPreview" format="string" />
<!-- Declare styles -->
<style name="Theme.MyApp.Widget"
parent="@style/Theme.DeviceDefault.DayNight.AppWidget">
<item name="widgetTitlePreview"></item>
<item name="widgetSubjectPreview"></item>
</style>
<style name="Theme.MyApp.Widget.Preview">
<item name="widgetTitlePreview">Preview Title</item>
<item name="widgetSubjectPreview">Preview Subject</item>
</style>
</resources>

Once you have the preview theme, you can apply it to the preview item in the layout.

layout/my_widget_preview.xml
<!-- Copyright 2019 Google LLC.
SPDX-License-Identifier: Apache-2.0 -->
<LinearLayout ...>
<include layout="@layout/widget_header"
android:theme=”@style/Theme.MyApp.Widget.Preview” /></LinearLayout>
layout/my_widget_actual.xml<LinearLayout ...>
<include layout="@layout/widget_header"
android:theme=”@style/Theme.MyApp.Widget” />
</LinearLayout>

Finally, you need to set your widget’s layout to specify as the previewLayout attribute of the appwidget-provider.

xml/app_widget_info_checkbox_list.xml
<!-- Copyright 2019 Google LLC.
SPDX-License-Identifier: Apache-2.0 -->
<appwidget-provider
android:previewLayout="@layout/widget_grocery_list"
...
/>
Static preview vs. scaled preview

Setting default values directly on the layout is not possible for multiple items displayed in a ListView, GridView or a Stack. In such cases, you can create another layout for the widget preview and set multiple hard coded items in this layout.

While doing so, it is a good practice to not duplicate the whole layout and use <include> tag to reuse the parts of the layout which work with default values. You can set this new layout as the previewLayout attribute of the appwidget-provider.

Description

You can also set the description attribute to provide a description to be shown in the widget picker. While this is optional, providing a description can help users to better understand what your widget can do.

app_widget_info_checkbox_list.xml
<!-- Copyright 2019 Google LLC.
SPDX-License-Identifier: Apache-2.0 -->
<appwidget-provider
android:description="@string/app_widget_grocery_list_description"
...
/>
Widget description

Summary

That wasn’t too hard, was it? In this post you’ve seen how to update your widget’s design and offer a better user experience in the widget picker. These are really low hanging fruits to start updating your widgets for Android 12 and your users will instantly notice the visual difference.

But, that’s not all. In the next article, we’ll take a look at new APIs which will make your widget more personalizable, more responsive and offer more interactivity.

--

--