[MUSIC PLAYING]
TAKESHI HAGIKURA: Hi.
I'm Takeshi.
I'm [INAUDIBLE] engineering the developer relations team,
based in Tokyo.
Today, we are talking about building modern Android app
widgets.
In this talk, we will talk about what are app widgets
and how they are different from normal apps at the beginning.
In the next part, we will talk about the improvements
in Android 12.
At the last part, we will talk about better tooling
for app widgets that has a more modern approach.
Let's look at what are app widgets
and how they are different from normal apps.
Let's imagine them as at-a-glance views
of an app that offers a quick glance of all functionalities,
without launching an app.
The key aspect of a widget is that the widget
runs in a remote process called, AppWidgetHost.
One example is Home Screen Launcher.
Because an app widget runs in a remote process,
certain limitations are applied.
Let's look at how app widgets work.
At the front, your app register the AppWidgetProvider
that defines the behavior and the AppWidgetProviderInfo that
defines the metadata.
Then the AndroidManifest points them.
This allows the OS to display widget preview.
And there are several methods, such as the initial layout
and the default size of the widget.
Then the provider [INAUDIBLE] [? redefines ?] the layout
and updates the widget.
It's important to note that only a limited the number
of [? builds ?] can be used for app widgets.
Then the OS provides updates through broadcast events
to the receiver, meaning that the widget is
updated periodically by the broadcast events.
I explained each step how an app widget works.
Finally, let's look at the entire picture that illustrates
how each piece fits together.
Android widgets have been core to Android since 2008,
and they are key for many users to drive users' engagement.
Also, the API for AppWidgets are there,
since basically the beginning of Android.
But they haven't changed much, until now.
As you can see in the graph, AppWidgets are there
from the early days of Android.
A few improvements were made along
the different Android versions.
And, of course, better widget designs
were running when it happened.
But those were minor changes, and there
hasn't been frequent updates.
For example, from 2012 to 2021, there
was only one Android version that
included updates on AppWidgets.
But Android 12 finally brings much needed improvements.
Let's look at the improvement in Android 12.
I'll cover important changes, because we brought significant
updates, and though I cannot cover them all in the talk.
In Android 12, many of the key UI elements
now have rounded corners, to make AppWidgets
look consistent across other widgets and the system
appearances.
New parameters are introduced.
The first one represents the corner radius
of the widget background.
To use the parameter for AppWidgets, let's
define a drawable that has corners where the system
parameter is applied.
Similarly, the second one represents the corner radius
of any viewing inside the widget.
Let's define another drawable for the background
of the inner views, then apply the drawable
to the outer container of the widget.
By doing that, you can apply the corner radius
provided by the system parameter to the background
of the widget.
Similarly, apply the drawable for the inner views
to the layout that represents the inner container
of the widget.
As you can see in the example, now the inner container
has the smaller radius than the outer container.
Dynamic colors-- as we announced at the Google I/O,
we introduced personalized theming
and the color experiences.
In Android 12, we added a dynamic color API
to allow widgets to be consistent with the system
resources and the home screen.
You can use dynamic color API, by using the theme provided
by the system on Pixel devices and the color attributes,
such as color background and the color accent.
As you can see in the example, the background
of the widget and the color of the image view
add up to the device theme.
For Pixel devices, colors extracted from the wallpaper
can be used to allow the widget to look uniformly in the home
screen.
As you can see in the examples, the dominant color
from the wallpaper is extracted and applied
to the image views in both light and the dark themes.
Let's look at the widget that has an old appearance
for comparison.
Before applying the changes, the widget layout is not broken,
but it doesn't look that great.
After applying the changes of the rounded corners
and the dynamic color, you can see more appealing widgets
that have consistent appearances with the device
themes and the colors.
Let's look at another API improvement.
Android 12 introduces a new API for achieving
responsive layouts.
As you can see in the screenshot,
different layouts are switched as the widget is being resized.
For example, let's look at the small layout.
The minimum supported width and the height
and the corresponding remote views
are supplied as arguments.
Regarding of the maximum support for widgets,
it supports up to 269 dp, because 270 dp
is specified as the minimum supported width
for the next layout.
Similarly, in terms of the height,
the smaller layout supports from 110 dp to 279 dp.
Then the system picks up the closest number
of cells within size range.
Sizing-- Android 12 has new attributes
for providing better sizing options.
Target for cell widths and the height attributes
are introduced in Android 12, which
has specified the default of greater cell sizes
when the widget is placed in the home screen.
MinWIdth and the Height attributes
have been available before Android 12, which specify
the default widget size in dp.
It's recommended to specify both,
in terms of keeping backward compatibility.
If your widget is resizable, you can now
constrain your widget's maximum resizable range
by using the maxResize Width and the Height
attributes that are introduced in Android 12,
along with the minResize Width and the Height
attributes that constrain your widget's minimum resizable
range.
Android 12 also improves the widget picker experience.
Two new attributes are introduced in Android 12.
The first one is description that
has a description the widget picker to understand
the purpose of the widget.
The second one is previewLayout that
specifies an XML layout that is displayed in the widget picker.
Before Android 12, preview image attribute
has been available that specifies a static resource.
But by using the previewLayout attribute,
you can see more accurate previews
that adapt to device light or dark theme,
because the preview is constructed at run time.
And soon your favorite group apps
will benefit of the new Android 12 changes,
making your home screen feel like you.
With [INAUDIBLE] more apps, like [INAUDIBLE]
was adopting the new modern styles,
we would be able to create a better widget
ecosystem for our users.
So I covered lots of improvements in Android 12,
but there are even more new features you can follow.
Please look at the description of the video.
I'm going to add the resources to learn more
about the changes in Android 12.
I'm going to hand over to Marcel.
He is talking about the better tooling for AppWidgets.
MARCEL PINTO BIESCAS: Thanks, Takeshi,
to show us some of the new additions in Android 12.
Hi, everyone.
My name is Marcel.
I'm a developer relations engineer at Google,
based in Singapore.
And today, I'm going to talk about how we're improving
tooling for our widgets.
We know that, to build great widgets, we need great tooling.
And while the widget API and the mode view
has been there since Cupcake, it was time
for a more modern approach.
Let's welcome Glance to the Jetpack family, a new API
powered by Compose Runtime, that will
allow us to create AppWidgets following
a syntax similar to the Compose that you're already
familiar with.
But not only widgets, we are exploring
how Glance could be the base for other Glance cells APIs,
by providing a common set of composables, that, together
with the model-specific components,
allow us to abstract the complexity of the platform
APIs.
In the specific case of AppWidget,
what that means is that Glance takes
the widget UI that you define using composables,
and translates them into actual remote views,
and then displays them on the widget, applying directly
the new theming and some of the new features
that Takeshi mentioned to you on Android 12
and, whenever it's possible, make them
backwards compatibility.
In addition, Glance hand out for you some
of the lifecycle and common actions,
doing most of the wiring for you,
so you can just focus on building great widgets.
Let's take a quick look on how building an AppWidget
with Glance looks like.
First, we still need to declare the AppWidget the same
as we did before.
In your AndroidManifest, you will link to your receiver.
In this case, instead of being the AppWidget provider,
it's going to be extending the Glance AppWidget receiver.
Basically, this receiver will handle
most of the things for you.
You only have to provide what is your AppWidget.
Then this Glance AppWidget will force
you to override the Composable Content function.
Here is where you actually define your UI.
Glance will take care of calling the method whenever
it is necessary and display the widget UI for you.
So, in a nutshell, no more XML with Glance.
We can just use composables that youre already familiar with,
like row, column, text, and so on.
And underneath, the content defined here
will be translated into the actual remote views
and displayed for you on the AppWidget.
It's important to understand, though,
that Glance uses Compose runtime,
and Compose-like syntax, but is an independent framework.
The components they look alike, but they
are adapted for our widgets, due to the remote
build limitations, since, as I mentioned
before, the library translates them into remote builds.
So it's not possible for us to reuse
the exact same composables that you might
be using Jetpack Compose UI.
But if you're familiar with that,
Glance will be really easy to understand.
In addition, Glance makes handling user interaction easy,
because we are changing how to handle that,
using an action API.
If you know how widgets work, they
work on a different process, making it hard [INAUDIBLE]
sometimes to handle simple actions,
because it's not inside your process.
You don't have ownership of those in that moment.
So you always need to get called back
from the other process that's handling the widget for you.
Instead, with Glance, you can just simply provide an action
to any composable through the clickable modifier.
Then Glance will abstract the complexity in the wiring
and just call back this action, whenever the user clicks
into that composable.
In addition, we are providing pre-defined common actions.
For example, to handle how to launch an activity,
it's as simple as calling launchActivity, passing
the activity target class, in addition
to some arguments if you want.
Then Glance will simply call and launch
the activity, whenever the user clicks on that composable.
Alternatively, we can provide custom actions,
allowing us to execute some of the code.
For example, we want to maybe update the location
and refresh our widget whenever the user clicks on this button.
What Glance is doing here underneath
is making the wiring for you and handling
this clickable remote click through a broadcast receiver
and calling your action that you define.
Although, whenever you execute this code,
make sure that you have set any consuming task, like network
requests or database access, to, for example,
a worker, using a work manager API.
Another big pain point on AppWidgets
was handling different sizes.
AppWidgets are placed onto the user home screen
where the space might be limited.
In addition, it is a good practice
to provide resizable widgets, to allow users to resize and fit
the widget the best into their home screen.
But we know it's hard to handle some
of this resizing and all these different responsive layouts.
So Glance tries to make that a bit more simple,
using the size mode mechanism that provides us
with three different options.
Let's look at the first one.
SizeMode.Single is the default option.
It basically specifies that the widget content
we are defining here will not change, regardless
of the available size.
What that means is that the content method then, is only
called once with the minimum supported size that we defined
on our widget metadata.
If the available size changes for the widgets--
so the user is resizing the widget--
the content will not be refreshed.
If you actually want to change the content whenever
the size changes, this is where you can use the SizeMode.Exact.
This mode basically recreates our widget UI every time
that the user resizes our widget,
calling the content function again, providing
the maximum available size on that moment,
allowing us, for example, to change our UI
and add an extra button if there is enough space.
While the previous mode allows us to completely
resize and change the content, based on the available size,
for each resizing, our UI must be recreated every time.
What that could cause is some bumpy transitions
whenever the user resizes and might be not the best
performance.
Especially for Android 12, we can use the responsive layouts.
And Glance makes that easier, by choosing
the SizeMode.Responsive.
It allows to define which sizes our widget can support,
using the DpSize format.
And for example, here, we are mapping these sizes
to specific shapes of our widget that we handle, just
for readability.
Whenever the AppWidget is created or updated,
Glance will call our Content method, which each of the sizes
provided before.
So in this case, we'll be calling three times
for the three sizes we defined.
Each of these calls will be mapped to that specific size
and stored in memory.
So the content that we defined there
will be stored, then allowing the system
to select the best-fitting one based
on the available size in the moment
that the user resizes the widget,
without having to recreate our full UI,
providing a more smoother transition and better
performance.
And similar as before, depending on the size that we get here,
we can change our UI, adding an extra text.
Or if it fits our horizontal rectangle size
that we defined before, we can add an extra button.
Or if it fits our big square, then
let's add an extra photo or text.
To showcase the different size mode here and make
the difference clear, we created this widget
that outputs the value of the local size current, whenever
the Content function is called.
In the first mode, you can see that, regardless
of the available size that the widget has,
it always shows 110 x 110.
That's because the content function is only called once
with the minimum supported size that we defined it
on our widget metadata, in this case 110 x 110.
In the Exact mode instead, you can
see that the values are changing every single time that the user
resizes that widget.
That's because, whenever the user resizes,
the Content function will be called, passing the exact size
value on that moment.
Instead, for the Responsive mode,
we defined two sizes here.
One is 80 x 100, and the other is 150 x 120.
So if you see, the content of the widget
only changes whenever one of these sizes fits.
It always tries to fit the best fitting one.
So basically means the biggest one
that fits on the available size, or falls back
to the closest one.
What is important to note is that we are not
recreating our UI.
Our content has been called twice at the beginning.
And then the content is just changed,
depending on the available size, making
the transition more smooth, and avoiding
recreating UI over and over.
There is more to come, like support
for widget state management, material themeing out
of the box.
But that's all we have time to cover today.
We hope you are as excited as us to try the new API
and build modern Android widgets.
Thanks, for watching this session.
Have a great one.
[MUSIC PLAYING]