NICK BUTCHER: Hello, good
morning, everyone, and welcome. Thank you for
coming to our talk. Today we're going to talk
about two very highly requested user features which
are new in Android Q, and that is dark theme
and gesture navigation. My name is Nick Butcher, I'm
an engineer on the Android Developer Relations Team. CHRIS BANES: My name
is Chris Baines, and I'm also an engineer on
the Android Developer Relations Team. ROHAN SHAH: And I'm Rohan. I'm a PM on the Android
System UI and Launcher Team. NICK BUTCHER: We got a lot to
go today, so let's get started. First up, we want to talk
about the dark theme. Wait, that's better, dark theme. So why is dark theme important? We think there's
three major reasons. The first up is supporting
using your applications in darker environments. How often have you used your
phone in a darkened room and been blinded by a
bright white screen, which is not what you want? Supporting a dark theme enables
usage of your app in many wider situations. Secondly, by lighting up
less pixels on the screen, we've seen significant
reductions in power usage. In fact, in our
tests we've seen up to 60% reduction
in power usage when the app is in the
foreground, which can be a real user benefit. And lastly, dark themes
can support accessibility while maintaining
sufficient contrast ratios. They have less eye
strain on the user so that could be used by
certain classes of user much more comfortably. So for those reasons, we've
introduced a new system setting in Android Q. So now under the devices
display settings, you can choose between
a light or a dark theme. You can also use a new
Quick Settings toggle to quickly flip
between those modes and the device
will automatically kick into dark theme when your
device enters Battery Saver. Now it's important to note the
dark theme is actually a system wide setting, not
just to the system UI, but it applies to all apps
running on the device. And as such we
think that users are going to increasingly expect
your applications that you're writing to respond when
they set this system toggle. So here for example I've got two
apps running in split screen, and when I toggle
into a dark theme, we can see that only
one of them responds. And we think the users are
going to increasingly expect your application to follow this. Now I've picked on Google
Drive here because they're not currently supporting theme,
but all Google applications are actually committed
to update to support dark theme by the time
Android Q rolls out. So this is only going to
increase the user expectations. So as such, we
strongly recommend that you look at supporting
dark theme in your applications. Now we recognize that's
going to be some work for you developers, us developers,
and so as such, we're introducing something
new in Android Q which is a feature called Force Dark. Now Force Dark attempts
to automatically apply a dark theme to a light
theme application. Well, let's take a look. So here's the Google
I/O application and here it is with Force
Dark being applied to it. And it does so in a
kind of intelligent way. It runs at rendering time and
actually inspects the views that it's rendering and
tries to smartly work out which ones should be inverted
in order to run dark. It even does some clever stuff
like looking bitmap drawables and tries to work out if
there's a variation in the hue, is this some kind
of photographic data and not invert certain
kind of images. So it's got some smart
heuristics in it. Force Dark is opt in,
you have to turn it on for your application. And you do so like
this, by setting Force Dark allowed to true. Here I'm setting it at the theme
level for my entire application theme so it will apply
everywhere throughout the app. But you can choose
where to turn it on so you could turn on just
for one or two activities and use it almost as
a kind of migration to help you rapidly
adopt a dark theme. So Force Dark can help you
to rapidly adopt dark theme, but we still actually
recommend that you look into designing a custom
dark theme, which you can do so using themes and styles. The reason for
this, well, there's two main reasons this really. The first one is that Force Dark
is only available on Android Q, so it's only going to
benefit users on Q forward. Whereas implementing
a custom dark theme is actually using the standard
Android styling techniques. You can roll out your dark
theme into all kind of major API levels. The second reason why
we think it's important go custom is it gives you
utmost control over exactly how your app renders, which
is what you want, right? You don't actually
get to hook into how Force Dark will darken
your applications or how it will
change the colors. So if you want control
over, if your designers wants to be able to control
the exact shades of blue that they're [INAUDIBLE]
here is going to change to, for example, then a custom
theme is the way to go. So to help you to
design for dark themes, we've just released this
week some updated guidance on the material.io
website, which covers how to generally design
a dark themed application. With specific guidance
around important areas such as accessibility
and guidance on how to adapt your apps color system
to work under a dark palette. In fact, there's another
session at Google I/O right after this one on
stage one which is all about how to
design for the dark theme. So to implement a dark
theme, we recommend that you take a look at the
AppCompat material design components libraries which Chris
is going to talk about now. CHRIS BANES: Thanks
Nick, so DayNight is a feature in
AppCompact which we've had for a number
of years now, which allows you to easily
implement one of those custom themes in your app. Now the way it works is by
enabling the Night Resource Qualifier, and it works back
to API 14, which Android 4.0. We've been hard at work for
the past couple of months to improve it and that is
available in AppCompact 1.1, which is available now. To implement a theme
using DayNight, the first thing you need to
do is change your theme parent to be one of the themes that
are compatible with DayNight variance. If you're using
materials on components, which I'd recommend
you do, it also provides a DayNight theme in its
version 1.1, again, available now. As we mentioned
earlier, AppCompat enables the -night
resource qualifier to work. And that is exactly how
the theme is implemented. You can see in our
default configuration that DayNight points to
Theme.AppCompat.Light, which means that when the
light theme is selected, we'll use a light theme. And when in our
night configuration, in values-night, it points to
a Theme.AppCompat, which means we'll go dark. The next thing we
need to do is tell AppCompat what mode to use. Now we have two APIs for that. The first is
setDefaultNightMode, which is used when
you want to set a mode across your entire app,
so all of your activities. If you need a local override
in a specific activity, we have setLocalNightMode. Now one thing to note
is that the values you set on these APIs
are not persisted. So therefore, you need to set-- use the method whenever your
app process is brought up. Usually you'll do in
you application object. Using those APIs, you
need to give it a mode. And we offer four main modes. The first is MODE_NIGHT_YES,
which means always dark. MODE_NIGHT_NO, which
is always light. FOLLOW_SYSTEM, which will follow
the current system setting. Now on Q because we have a new
system setting, which is great, it will do that basically. Whenever the system
setting is changed, your app will follow it. When your running on devices
before Q, so Pie or earlier, it will usually default
to a white theme. The next new mode is
called AUTO_BATTERY, which we've added in AppCompat 1.1. And that goes dark whenever
battery saver feature is enabled. And it works back to API 21. So you can see an
example where a device is going into battery saving mode. When that happens, your app
will automatically go dark. When the user plugs
the device back in, it goes back to charging,
and therefore we leave battery saver
mode, like so. We'll automatically
go light again. The final thing to
check is to make sure that your activities
are extended from AppCompat activity. This may sound super
obvious, but its something which is easily forgotten. So as I said earlier,
we've been hard at work over the past couple of
months to improve the DayNight feature. And so I'd like to take through
some of the things we've done. So one key change is that
setDefaultNightMode now recreates any
visible activities. It previously didn't
do this and you had to do all that
work yourself, whereas we now do it for you. We also have an
incompatibility with WebView. Whereas if you're using
DayNight and then later inflated WebView,
we'd reset the theme and then things
would go very wrong. And that's now fixed. [AUDIENCE CHEERING] The final thing is that
MODE_NIGHT_AUTO_TIME is now that deprecated. As I said earlier,
we've been hard at work over fixing many, many bug
fixes, which you've all raised. So hopefully, if you've had
any issues, they're fixed. That leads into an
app theme setting. So to support user
customization, we recommend providing
a way for users to choose the theme that
they want in your app. An example could be
an e-book reader. If a user knows
that they are always going to use the app at
night, and they always want it to be dark,
you want to find a way for the user to select that. We recommend there
be three options when we're [INAUDIBLE]
Android Q. Light, dark, and then system default. System
default being the default option for your app. If you're running
it on Android P or before, because we don't
have that system setting, the options are
slightly different. They're now light, dark,
and set by battery saver. Now the keen-eyed
among you will notice that those options
map pre-directly to some of the AppCompat modes
and that's totally on purpose. There's a 1-to-1 correlation
between those options and the modes we actually
have and we offer you. So now I'm going to
hand it over to Nick to talk about how elevation
works with dark theme. NICK BUTCHER: Elevation. So in material design,
elevation is a key concept for showing the
importance of some content in your application, by changing
the elevation of the surface and for hinting at
interaction cues. Now in light themes, this is
represented with a shadow. And as the elevation
raises up, the shadow becomes more diffuse. But when you have a dark
background, like in dark theme, this can be harder to see. And as such, we're introducing
the idea of elevation overlays. The idea here being that,
as the surface raises up to get closer to the
virtual light source, the actual surface
color itself changes, as if there was a
semi-opaque white layer on top of it, which gets
more opaque as you raise up in elevation. Don't worry. We're not actually
doing overdraw of the white layer on top. This is actually, we kind
of blend down the color and use it as a tint on
the background color. So to use elevation
overlays, then all of the components in
material design components version 1.1 onwards will
support this out the box. These are the
components which use the color surface attribute
for the background color and support elevation. And as such, just by setting
the elevation on the components, you'll get this surface
overlay behavior. But if you want to build this
behavior into your own custom components, there's
a couple of options. Firstly, you could use
the MaterialShapeDrawable, which is the kind of
background drawable which powers a lot of materials. Shape theming, as well as this
material elevation overlays. And you can use these in
your overviews as well. It's been augmented
with new API, such as
createWithElevationOverlay or setElevation or setTranslationZ,
which will give you this overlay behavior. If you can't use the
MaterialShapeDrawable for some reason, you
can instead take a look at the
ElevationOverlayProvider class, which is what
MaterialShapeDrawable uses under the hood. This gives you
lower level methods, such as working out the
surface color for a given elevation, which you can then
use in custom drawing the same. Now, implementing dark
themes, as we said, comes down a lot to good hygiene
with your applications, themes, and styles. And we've given you some
specific tips and gotchas when implementing dark modes. Quite commonly,
we've seen an issue where applications,
which are designed like this for a
light screen, where they might have dark text
on the light background. When they apply a
dark theme to the app, you see an issue like this,
where you end up with, say, dark text on a dark
background, which you end up not being able to read. Or perhaps the text
correctly inverts to light, but your background
remains light. So these are common issues
that we see in applications supporting dark theme. And generally when
this happens is you've made some assumption
that somewhere in your layouts about being running
under a light theme. And you've kind of
hardcoded some colors, like hardcoded a white
background or black text in this case. Now you're probably
not hardcoding things like this in your layout,
but you're probably using some kind of color resource. And this is
essentially the same. If you only provide color value
in the default configuration, this is essentially
the same, that it's not going to respond when
running under dark theme. What you need to do is
provide an alternative color when running under the
night configuration here in the values-night folder. And as such, these
colors will then respond to the theme change. Better yet, you can take a
look at using theme attributes. Theme attributes are
essentially semantically named colors, which have different
values when running under a light or a dark theme. So here for example,
I'm changing that hardcoded background
from white to materials color surface color, which is a
kind of background color. And so that will flip from
white in a light theme to a very dark gray when
running under dark theme. Or likewise, I'm using the
platforms text color primary here for the text color,
which will give you the inverse of that. So it will be dark
in a light theme and light in the dark theme. In fact, if you take a look
at the material color system, it has lots of these
semantically named colors, which are super useful
for using in your designs. So you're probably
familiar with things like color primary, color
secondary, color accents, and so on. But here's the surface color
that we looked at before. But they also provide a
series of on colors, so colors which will contrast on
top of the relevant color. So On Primary, On
Secondary, On Surface. So for example, the
On Surface color is a color which
will always contrast on top of that
background Surface color. So we can use this
in combination with a neat trick that
colors state list provides to great effect
during dark theme. So for example here,
I am using the fact that color state list
lets you separate out the color from the alpha channel
and define them separately. So I'm grabbing the
colorOnSurface, so something that will always
contrast the surface color, and applying an alpha
modification to it. So this can be
super useful if you want avoid having 50 different
shades of gray in your colors XML file that you are
scared to kind of update, because you don't know
where they're going to use. Instead of that, if you can
reference these colors always guaranteed to be the
right color to contrast, given a different theme. And just apply an
alpha modification. It can be super useful. One caveat is this alpha
kind of modification was introduced in
API 23, Marshmallow. So if you want to
use it beforehand, make sure you're using the
AppCompat resources path, or loading it like this in code. Similarly, whenever you're
loading colors in code using context compact,
.getColor, for example, be wary that you want to ensure
that those colors as well have night configurations. Or better yet, you might
want to do something like this code here, which
is querying the current theme for a theme attribute. So this is how
you can get access to something like text
color primary or color surface in your code. Another class of issues we've
seen is around drawables. So if you have
drawables, you probably want them to be showing up,
like these light drawables here, but you might encounter
similar issues, as we saw before, where you
might end up with dark-on-dark. Or you could look at providing
completely separate versions of the drawables under the
drawable-night configurations. A better way is
actually probably to look at tinting,
because usually these are monochrome icons that
you just want them to change the entire color of them. So you can tint at
a couple of levels. You can either tint at
the view level here. So here I am going
to tint whatever drawables giving me with
whatever colorSecondary is for the current theme. So it'll update it
depending on the theme. Or hopefully you're
using vector drawables throughout your
app assets, which natively support tinting on
the root element of the vector. So here I'm setting the
colorControlNormal theme attribute, which is the standard
kind of gray icon color. So setting this means
your icons will always be the exactly right color. Or if you're
working in code, you could also use the
DrawableCompat class, which can apply a tint
dynamically to a drawable as well. And lastly, it can be handy to
work out if you're currently running under a
dark theme, which you can do with some code like
this, which actually looks at the configuration's
UI mode and checks whether this is
currently in night mode. So this is useful for querying
whether you're under night mode and maybe branching your logic
or setting a different tint on a drawable or some such. Those were just quick tips about
working with themes and styles. We could spend the whole
talk talking about-- well, you could-- talking
about themes and styles. But we've actually already
done that a couple of times. So I highly recommend
you check out these with resources on that. Lastly, I want to
revisit Force Dark and talk about how it can help
you to migrate to a dark theme. So here's an
application designed for a light presentation. And when we apply
Force Dark to it, we can see it's generally
done a pretty good job of it. It's is generally inverted
a lot of the colors. There's a few opportunities. It could be better
in my opinion. In fact, if we compare it to
a custom dark theme, which I designed, you can see a few
things which force dark hasn't done quite right. For example, if we zoom
in on this drawable on the left, which is
indicating the depth of a threaded conversation,
Force Dark has made it a bit too light for my tastes. What you can do in
these situations, is you can set the
forceDarkAllowed to false on any given view or view
group and disable the Force Dark behavior just for
that part of the hierarchy. But remember, when you
set Force Dark to false, the general
configuration is still running under the night mode. And as such, we can use
things like tinting. And this tint
color will give you the right color for a
theme, so this will respond to the night configuration. So check out Force Dark. Like I said, it's one
line change in your theme to set it for your application. Or we've actually introduced
a new developer option where you can force the
entire device into this Force Dark mode. So if you want to
check it out now, if you're running
Beta 3 or newer, you can see how your app
responds to Force Dark. So next up, Chris going to
introduce some common scenarios we're seeing with dark mode. CHRIS BANES: Thanks, Nick. So the first thing we're
going to to talk about is web content. Now the good news is that
WebView works seamlessly with Force Dark. So if you're opted
into Force Dark when you're running under Q
and you have an example here. So we have an app
here, which you load into Google.com in a WebView. And we've enabled
Force Dark on this app. And when we go into night mode,
it changes the WebView as well. It also works in Chrome,
Chromium-based browsers, and WebView. So soon actual web
content will be able to support dark theme
natively, using their the CSS media query called
prefers-color-scheme. We've also added dark theme
support in custom browser tabs. And by that, we mean
the UI around it. So we have a new
method on Custom Tabs intent called setColorScheme. It takes one of
these three options. Now when-- here, we're in light
theme, but when we go to dark, it looks a little bit like this. Now you'll notice that
the content itself doesn't have Force Dark
applied or anything like that. That's because we're
aligned on the web content itself to use that
media query we just spoke about. Now MapView itself doesn't
support dark theme out of the box, but
we can easily make it do so by using its custom
map styling functionality. Now custom map
styling allows you to specify the colors
and text and stuff of a map via JSON file. You can see a link to a
website we can actually download some map styles
that we provide for you. I think there's nine
styles on there. Some are light, some are
dark, but you can also customize it to your needs. Now, we can actually
use that feature by using the -night
resource qualifier that we spoke about earlier
to make MapView sport dark theme natively. So in our default
configuration, we'll put a light-styled map in
the JSON file in res/raw. And then in res/raw-night, we'll
put a dark-styled JSON file. And that way MapView
will automatically load the correct map style and
then use the correct colors. NICK BUTCHER: Another issue we
see when adopting dark themes is with illustrations,
which you're probably using in empty states or
maybe onboarding or closing your applications. If you just use the
same illustration design for light theme
under a dark theme, you can see too
high contrast, where these colors are,
like, way too saturated and they contrast very highly
on these darkened backgrounds. We recommend that you
provide an alternate version when running under
a dark theme, which is more harmonious with
the darker backgrounds. Now again, you could just
provide an alternate version of this drawable, so
you have two versions of very similar drawables
in your application, but a better way
to do this might be to use an effective
drawables ability to reference color resources. The individual fills
or strokes of paths. And as such, you can vary
just the colors, when running under a night configuration. So this way, you
only have to ship one version of the
drawable, but have the colors respond to when it's
running under a dark theme. Next up is notifications. So notifications, when
running under a dark theme, will respond and go dark. So if you're using any of
the notification templates, these will work
just out of the box. But if you're using
a custom layout, you're setting a custom
layout, than all the rules we talked about before
about sliding still apply. So don't assume it's
running under a light mode. Don't hardcode colors. Use theme attributes. In fact, I'd encourage
you, if you're sliding any text in
particular, to look at the subclasses of the
notification text appearance, so that your text will
mirror that of the system's notifications as well. So that was dark mode. Our take aways
really are that users are going to increasingly
expect your applications to support dark theme,
so really, really do take a look at
supporting it as well. Use AppCompat, DayNight, and
material design components, which have lots of
built-in support for implementing this
in your applications. And be sure to look for these
latest versions, these 1.1.0, because there's been lots of
improvements and bug fixes in them. Consider Force Dark as
something to help you rapidly adopt a dark theme. And maybe use it as
a migration tool, so you can enable it
for certain activities and then roll out
custom themes gradually. And theme attribute
all the things. Don't think about
being hardcoded in a single configuration,
a single color scheme. Be very flexible. Whenever you see a
hardcoded color or color resource, if only
a single version, see that as a red flag. So now I'm going to
head over to Rohan, who's going to tell us
all about gesture nav. Cheers. ROHAN SHAH: All right, so I
have the benefit of telling you all about gesture nav. A few of you might have played
with it already on Beta 3. If you haven't, make
sure you give it a go. It's out there in settings. You can search for fully
gestural navigation. But I'll do a quick
refresher of what it looks like right now in Android Q. So we're adding a new nav mode,
if you haven't already heard, in Android Q that replaces
the beloved three buttons with three glorious gestures. And here's what they look like. On the left, you can see
that swipe up from the bottom will become the
gesture for home. Swiping up and
holding in the middle will take you to your
recent and/or overview. And on the left, you can see
that swiping in from an edge will take you back. Now the one thing that this
movie doesn't really do justice is that we're also introducing
swiping left and swiping right in order to go back. We think it's a super
awesome experience. Internally, we love it. We've heard really
great feedback. We definitely want to hear
how you feel about it. But definitely give it a try. So a big question
we've gotten is, we're introducing another nav
mode in Android, what do we do? Like, we're developers, what
are you trying to do in Android? So I want to talk about that
a little bit really quickly. In the future for
Android, we're going to be supporting two nav
modes moving forward. The first one is three buttons. You know, Android users
love three buttons. We know that it's super usable. And it also addresses a lot
of accessibility needs that gestures just cannot. On other hand, we also
know that there is a lot of desire for gestures. So we will be
supporting one gesture mode, which is what you saw,
moving forward in Android. And only that one. I want to take a quick
step back and talk about why we're doing this now,
before we dive into the details for developers. And talk about user trends here. So Dan Sandler talked
about this in his talk in what's new on Android. But users increasingly
want immersive experiences in Android. And one thing that
device makers have done is try to approach this
from a software side. And what they've done is
built their own gesture nav. And every device maker
has a different impression of how gesture nav should work. What we recognize,
on the platform side, is that kind of gets
insane for a developer, thinking about n different
gesture navs when you're trying to develop. Just design for, test for your
app, just kind of gets insane. So with that in mind, we
introduced this gesture nav in Q. And we're going
to be standardizing the ecosystem as of Q on
three buttons and our model moving forward. And just want to elaborate
the problem here. You know, there's a lot
of different gestures. These are just some of them. Dan's talk had
different swirl gestures and maybe a knock knock
does something different, but we do want to unify
that core set of gestures, back, home, and recents. Taking a slightly
different spin on this, why should you care as an app? I'm going to regurgitate
that immersion bit, but flipping this
a little bit, there is an opportunity
for you, as an app, to delight your user by bringing
this immersive experience to your app. And making sure that it's
compatible with this new nav mode. In terms of compatibility,
we recognize that there may be some
conflicts that you will need to handle as an app. And we'll talk about
that coming up. Cool. So how do you make
your app nav-ready? And nav just means, you
know, any nav mode, 3 button, gesture nav. How do you prepare for
this immersive experience? And more importantly, how do
you prepare for gesture nav? There are three
things you need to do. The first one is making
sure that your app goes edge-to-edge, which Chris
will explain a little bit more. The second thing you need to do
is leverage insets, old insets and new ones that we're
adding, to make sure that any kind of critical
content is in a safe place and is in optimal positioning. And the third and final
thing is handling conflicts. If you do have a conflict,
how do you handle it, and how can you override
certain gestures so you can bring a better
delightful experience to your app? Cool. So I'll hand it over to Chris
to talk about edge-to-edge. CHRIS BANES: Thanks, Rohan. Yeah, so what is
actually edge-to-edge? Well let's take a look
at a typical app when you're running Android Q today. So here you can see
the bounds of the app are actually below
the status bar and above the navigation bar. So what do you want on Q? Well simply, we want
the navigation bar to disappear, allowing
your apps content to be displayed
behind it, to create a more immersive experience. When it scrolls, it
looks a bit like this. So as recommendation, drawing
behind the navigation bar is now strongly recommended
on Q. It's optional before Q, but one thing to note is
that a lot of the APIs and how you do this
actually works back to previous versions of Android. So if you're going to
put the work in for Q, it's not that much more work
to do it for previous to Q, as well. Now let's take a look
at the status bar. Now similarly, we actually
want the status bar to go away as well. Again, allowing your app content
to be displayed behind it, creating a more
immersive experience. And you'll hear the
word immersive a lot in this presentation. So now our app looks a little
bit like this when it scrolls. Again, drawing behind the status
bar is now recommended on Q, and optional before Q. So if
we take a look at our bounds, they've come from
here to here, which is where we get edge-to-edge from. So let's take a look at
now about how much actually implement this stuff. So the good news is that
from Android Q onwards, the system is now responsible
for recoloring the system buttons and the handles. So you can see here, an
example, where as we scroll, that navigation bar
handle at the bottom is changing color based
on the content behind it. Now the recoloring
can take the form of both dynamic color adaption,
which you've just seen. Or it could be static coloring
on less powerful devices. When you're running
on older platforms, because that recurring
doesn't happen, we recommend that you set a
translucent nav bar color, so the user can actually
see those buttons. So to really make
your app go immersive, there are three
things you need to do. The first is change
your system bar colors. Second, request to be
laid out fullscreen. And then the final thing
is to avoid any overlaps with your views
with the system UI. So let's go for it. The first one is the change
in the navigation bar color. Now, we have this attribute
available in Lollipop onwards, which we can use. And we're just going to
set it to transparent. When you run on
Pie or before you should use a translucent
color as we just mentioned. The next thing we
need to do is request to be laid out fullscreen. Now we're going to use the
infamous set systemUiVisibility method, with a number of flags. The two flags we need
are FLAG_LAYOUT_HIDE, and that tells the system to
lay as out as if the navigation bar wasn't there. And a second is
LAYOUT_STABLE, which is special flag that
tells it to lay us out at it at our most extreme. If you also want to be
displayed behind the status bar, there's an additional
flag you need to use called LAYOUT_FULLSCREEN. Now when we lay
out fullscreen, we don't want our views to be
displayed behind the system bars. And that is where
insets come into play. Now insets are a collection
of values which tell you how much to move or
inset content by. Now what views you move,
how much you move it by, depends on the inset
and its purpose. And you might have seen
the in WindowInsets class. There are a number
of types of insets. The first type are called
system window insets and they tell you
where the system UI is being displayed over your app. They are commonly used to move
views that are not obscured by any of the system bars. So here you can see a
FAB at the bottom right. So we blow that up a little bit. Typically a FAB will have a
16 dip margin applied to it. And you can see that they are
denoted by these blue bars. So actually, in gesture
nav, it's not too bad. It's only obscured by
the bottom 2 dips or so. So we'll use the system window
inset to actually move that up. But in free button
navigation mode, it's actually a lot worse,
because the navigation bar is taller, our FAB
is a lot more obscured. So by using the
system insets, we can move out and make sure the
user can actually click it. So as a recap,
system window insets are used to move
clickable views. The next type are called
system gesturing insets. And they're new in
Q. Now they represent the areas of the window where
system gestures take priority. Visually, they look
a bit like this. So let's go through them. They include the vertical
edges for the back gesture. So if the user starts
dragging from an anywhere in the left and the
right hand zones, the back gesture will
start triggering. And again, on the bottom
side, where the home gesture takes place, again if the
user start dragging there, the home gesture will
take will take priority. Now as mentioned,
system window insets we use for clickable views,
system gesturing insets are used for draggable views. We'll go for
example a bit later. The next and final type
are called mandatory system gesturing insets. And they're a subset of system
gesture insets which define the areas which cannot be
used with exclusion APIs, which Rohan will talk
about in a minute. Now in Q, they are currently
only used for the home gesture, because that's a
protected gesture that users should always
be able to exit your app. ROHAN SHAH: Right. CHRIS BANES: Maybe
not over to Rohan. So as a quick overview, system
window insets are clickable. Gesturing insets are draggable. And mandatory system
gesture insets are used to check
the exclusion APIs. Now actually over to Rohan. ROHAN SHAH: There we go. So the third and final thing
in making your app nav ready is overwriting system gestures. So Chris already
talked a little bit about some of the system
gesture insets and ones that are mandatory. But I want to quickly talk
about what kinds of conflicts you may have to handle. And where you may
need to override. So any sort of horizontally
draggable content that resides in
those back zones, within those system
gesture insets, is an area where your
app may have conflict. I want to give a
quick example here. But I opened up a
photo in the Photos app and I wanted to crop a
picture and crop my buddy out. And you'll realize that the crop
handles, the little circles you can see on each
corner of that square, are awfully close to the edge. And unfortunately, those are
in the system gesture insets and in that back zone. So there are other examples like
this, you know with sliders, seek bars, video seek bars, for
example, other drag handles, et cetera, that your app
may need to be aware of. Great. So how do you override
some of these gestures? How do you make
sure that your user is able to use those
crop handles, et cetera? So there is a new
API available in Q that will allow you to opt out
of, at least the back gesture. Home is still a mandatory area. We know that's the only way
a user can leave your app, so we're not making
that opt-out-able. But basically how
the API works is that you can
specify a rectangles on screen where basically
you'll get touch events, instead of the system
consuming it for back, or for any gesture in that area. One quick word of caution. This is pretty powerful. One quick word of
caution here is that, be really careful
when using this. Users expect to be
able to go back. It is one of the most
frequently used system actions. I think it's used
twice as much as home. And if you suddenly
break that and decide to take over the entire
edge, for example, your users might get frustrated. So be really careful
when using this. And make sure that you have
very clear visual affordances, such as the drag handle, that
indicate that you can actually swipe there. And a user will start
interacting with app content instead of going back. Taking a quick look
at the API, it's going to be in the View class. And it's called
setSystemGestureExclusionRects. And it takes in a
list of rectangles where your app will get the
touch events first and only. You can use this in onLayout, if
you have kind of static content that isn't really shifting. Or you can set this
in onDraw, if you want more kind of real time
frame-by-frame updates. Cool. So let's talk about
some common scenarios with all of these three
pieces of guidance. And Chris will take over here. CHRIS BANES: Right,
so the first scenario we're going to look
through is scrolling views. Now, as you can
see here, content should be drawn behind
the navigation bar as the list scrolls,
but when they user reaches the end of that
list, that final item should still be above
the navigation bar, allowing the user
to interact with it. As you can see here. When we reach the
end of the list, we still want those bottom
items, lightning talks, in this instance, to still
be above the navigation bar, so that users can interact. So a common way to achieve
this would be through padding. And we'll pad our scrolling view
using the system window insets that we spoke about earlier. Here's a quick code example. We'll set an on apply
window insets listener, and then we'll
waive some insets. And then we'll just set the
pattern on the scrolling view, in this it's the recycler view,
using the system window inset pattern. And the final thing
we need to do here is something called
clip to padding. Now by default,
whenever a view group sets padding, or has
padding set on it, it will clip its children. Now that's because that's
the whole effect we want. We want our children to be
displayed behind our pattern. We need to turn
that feature off. So recycler view, list view, and
all the other scrolling views support this. So just need to set to false. The next scenario is all
about navigation drawers. Now if you've tried
Beta 3, you'll probably have noticed that a lot
of apps use navigation drawers and it can sometimes
get a bit funky. So DrawerLayout
will automatically exclude the correct
edges as necessary. So here you can see,
in the Google I/O App, that when the drawer is
closed, it will open. And the next gesture,
when it's open, the back gesture will
actually take preference. Now to use this, you need
updates on 1.1.0-alpha01, which just released this week. The bottom sheets,
generally, we want to avoid views near the
vertically scrolling gesture zones. But bottom sheets are obviously
a pattern which a lot of apps use. So for collapsible
bottom sheets, we want to make
sure there's enough content above the
navigation bar for the user to be able to actually drag it. So here we're
looking at an example where we haven't done that. And you can see that as the user
tries to drag the bottom sheet, actually the home gesture
is going to takeover. And we don't want
that obviously. So one way we get
around it is by using the system gesture insets to
increase our content size, allowing enough space for the
user to actually drag it as so. Since there's a code, here we're
using the bottom sheet behavior from material on components. And it provides peekHeight. So that's the amount of height
available when it's collapsed. So here, again, we're using on
apply window insets listener, we'll grab our system
gestures, and then we'll just increase
that peek height. Now it's also
available in ViewCompat in the core library in AndroidX. And again, we've released
a new version this week, called 1.2.0-alpha01. But remember, users
can always swipe to go home by swiping at
the bottom of the screen. So even though we've
done this and we've moved the peek high up, users
can still accidentally trigger this gesture. And that's obviously
annoying for users. So draggable content
near the gesture nav zone is possible, but be careful
if you're going to do it. One thing also to say
is to try and make the draggable content
more obvious to the user, so they drag the right bit. So here you can see
that the actual header bar is fully opaque,
the content below it actually has an
alpha effect applied, trying to guide the
user to the top section. The next scenario is carousels. What that would
mean, view pages, or any horizontally scrolling
lists, like recycler views. Now one thing we
don't really want is for apps to set
exclusion rects everywhere, because that's a
problem for users. If an app sets exclusion rects
all across the left and right zones, the user is not going
to know where they can actually trigger back. The final scenario is
what about landscape? So if you've gone edge-to-edge,
what we talked about earlier, in landscape, when in button
mode, what we'll actually get is, which obviously isn't great. So you can see that the
button options are actually obscured by our apps content. Now this doesn't
happen on gesture mode. You only have this
on button mode. So if you have content which
starts near a vertical edge, think about padding all of
the content in horizontally. And one thing to
note also is make sure you test your apps both
on button modes and also the gesture nav modes. As a code example,
it's pretty easy. You just need to find a
view somewhere [INAUDIBLE] near the top, set an on
apply window insets listener, and then set the left
and right padding based on the system window insets. And that's safe to use
in all our orientations, because it will always
give you the right values. And once you've done that,
you're looking a bit like this. I just want to say, we
are adding more support in our AndroidX libraries,
Jetpack libraries, to make this a lot
easier for you. The examples we've
just gone through are just trying to show you
how we've tried to implement this in our libraries. But if you have custom
views, obviously you're also going to need to
do something similar. Now if there's difficult
patterns that you're finding, please raise them, so we can
try and build better support for you via the bug tracker. So a quick TL;DR, users will
expect that to work on all navigation modes. Please support it. Try and create immersive UIs,
because it's giving your apps more real estate to display in. Proactively update the
Jetpack and MDC libraries, because we are going to add
more support as time goes. And only use the
gesture exclusion API if you really need them. They're really meant as an
escape hatch for your apps. And finally, let us know
about troublesome scenarios via the issue tracker
we just spoke about. Thank you very much. [MUSIC PLAYING]
Wait, did they just say 'Auto Night mode by time' has been depreciated?
Wow, I'm trying to figure out logical behind this...
Various scenarios including nav drawer talked of at around 36:38
Nav drawer will automatically exclude gestures using the latest library released this week
That BIG ASS back arrow, is a eyesore sometimes.
The new back gesture sucks with a case. The old back button with the pill was superior... They still have the P gesture pill as an option however mine isn't working the same. I liked how on P if you swiped right on the pill over and over it would consistently switch between the last two apps over and over. Now if I swipe right it goes to the app to the left in the tray, if I swipe right again it goes to the next app to the left and left and left. It no longer switches between the last two apps. Now I'm pretty disappointed in my Q Beta Upgrade on my Essential... Anyone else have this issue or is my phone broken? :)