[MUSIC PLAYING] VADIM CAEN: Good
morning, everyone. Thank you for coming
so early to our talk up, What's New in Android
Studio, UI Design and Debugging Tools. Thank you. [APPLAUSE] I'm Vadim, from Android Studio,
working on the design tools. JEROME GAILLARD: I'm Jerome,
from the Android Studio team. JOE BAKER-MALONE: I'm Joe,
from Android Studio team. ASHLEY ROSE: I'm Ashley, from
Android Framework and JetPack. VADIM CAEN: All right. Before we start, a little
word about product mobile. You've heard maybe yesterday
that the Android Studio team has been focused on
product mobile to improve the end-to-end user
experience of Android Studio. Improving Android Studio
is not just about fixes. It's also about
improving how you use it, and filling any gaps that
we might have identified. Our tool chain-- when
it comes to design-- it's building new layout,
building new navigation between this layout,
managing your resources, and dealing with the inspection
at runtime on your device. To go through this
tool chain, we're going to go through a
typical user journey, building the Google
Trips application. And to start with, Jerome will
talk about the Layout Editor and how to build the first
layout that you see here. JEROME GAILLARD:
Thank you, Vadim. So first of all,
we're going to build the first screen of
our Google Trips app, using the Layout Editor. Upon opening the Layout Editor,
this is the kind of screen you're going to see. Here, it's just a blank layout. The first thing we're going to
do is switch to blueprint mode, as it is faster,
and it's just less distracting when
trying to just build the constraints on your layout. You don't want to
be just looking at what the components
actually look like. I'm just going to--
from the palette-- just dragging all the components
that I need for my layout, more or less in
the definite place. Once I'm done with
that comes the time to build the constraints. As a way to be a bit more
efficient building constraints, I could build them one by one. But using the
contextual menus, we can build several
constraints in one go. For example here, I want
to center the RecyclerView within the layout. One thing I can do is right
clicking on the RecyclerView, and in the contextual
menu there is the option of centering horizontally. What that does is it
creates both a left and a right constraint
in one click, ensuring that the
RecyclerView will be centered. Once I'm done building
all my constraints, this is what my layout looks
like in the blueprint mode. Obviously, it doesn't
really tell me right now if I built the right
thing, compared to the design that I was given. So I'm going to go
back to Design mode, and see what it looks like. In the Design mode, you
can see that it looks not very much like the original
design I was given. The reason for that is
that the RecyclerView view is pretty much empty. As you know,
RecyclerView usually get the data
populated at runtime, but that's not very
helpful when you're trying to build
your layout and make sure that it displays
correctly with the data that you're going to see. To solve that
problem, you can use design [? tools ?] attribute. So design time attributes,
you can simply-- in the RecyclerView-- use
the contextual menu again, and the sample data picker,
just like you see on screen. And from the sample
data picker, you can pick one of the
predefined templates that we provide for you
for RecyclerView items. Here, I just picked the
first one, the email client. Doing that creates a layout
for that RecyclerView item, that email client card. And at the same time, it
links it to your RecyclerView, so that in the Layout
Editor it shows populated. Of course, we're not
building any email client. What we want to build
in the RecyclerView is those Trips card. So I'm going to edit that
RecyclerView item that was created to be a Trip card. In the resource manager panel-- in the left hand side
that you can see here, and that Vadim is
going to present to you in much more detail-- I can simply first, rename my
RecyclerView item to something more appropriate to
my project, and then I can start editing it. Double clicking on the layout
in the Resource Manager will simply open that
layout in the Layout Editor. As you can see on screen,
I pretty much have all the right components
right there for my Trip card, like an ImageView,
couple of tags views, but they're obviously not
having the right constraints. So I'm going to start by
deleting all the constraints, clicking that button
in the toolbar. Once that's done, I'm
going to just reorganize all those constraints. One issue here is that we
have quite a few components overlapping each
other in a small area. That can be a bit cluttered. And we've heard from you
that in this situation, building constraints
can be a bit difficult. It can be sometimes difficult
to drag the constraint to the right target, on the
right components-- especially when components are overlapping. So what we are
now allowing to do is dragging the constraint
directly onto any place in the component that
you want to attach it to, and then a pop-up menu
opens, asking you what type of constraint you want to set. It gets really
interesting when you are dragging a constraint
into a location that has overlapping component. In that situation, we
are offering not only several types of
constraint, but you can also select which of the
overlapping components you want to attach
that constraint to. And that should
make it much easier to build constraint
layouts in the cases where you have overlapping
and small components. One final way that
can be helpful for you to build
constraints efficiently is using the componentry. So in the componentry, if you do
multi selection of components-- like here, we selected
two text views-- again with the contextual menu,
right clicking and selecting one of the
constraints available, you can create
that one constraint over the multi components
that are selected. So here, we create
two constraints at the same time on
those two text views. Once we're done building
all our constraints, it's time to customize
our views a little bit. For that, we're going to
use the Attributes Panel, on the right hand side
of the Layout Editor. We have redesigned
the Attributes Panel to show a new section at the
top called Declared Attributes. In that section, we
put all the attributes for the selected view that
have been set specifically for that view. So right there, you
can edit any attributes that have already been set. If you want to set a new
attribute on that view, you can simply click
the plus button and add the name and
value for that attribute. Another thing you can do
in the Attributes Panel is use the Constraint
Widget to set margins. From your feedback,
we've heard that you would have liked to see-- in addition to being able to set
just actual values, like number value for the margin-- you wanted to also be able to
set custom dimensions defined in your project. That's why we've added
that @ dot dot dot option at the bottom of your dropdown. Clicking on that button
opens a resource picker, where you can pick a
dimension that you've already defined in your project,
or you can create a new dimension right there. One final thing that
needs to happen-- looking at that layout-- you see that the ImageView is
populated with sample data, but it's just
default sample data coming from Android Studio. So that's not really
representative of the kind of data that your RecyclerView
will receive at runtime. So what you can do is
set your own sample data to that ImageView. We've added images of cities
into a directory called cities, in the sample data
folder of our project. You can see that it appears
in the sample data picture, and we can select it to
set that sample data. Going back to our
original layout, we can now see
that it looks much more like the original
design that you got. From there, you can
really see if the design has been implemented
properly, and will work when receiving real
data, once the application is running on a device. Now we're done with the building
of the first constraint, the first screen, and
we want to move on to building our next
screen in our application. But instead of just going back
to creating a layout file, and building it from
the Layout Editor, we want to start right there
thinking of the navigation flow of our app, and how the
first screen will transition into the second screen. To do that, we're going to
have a look at the Navigation Editor. The Navigation Editor
is a visual tool that makes it easier to use
the Navigation Architecture component from the
JetPack library. The way the Navigation
Architecture component works is it relies on having
a navigation host fragment as the main layout
in your application. Here in our activity
main layout file, we're going to drag
from the Layout Editor palette a NavHostFragment-- it's there by default-- and we're going to drag it
onto the design surface. When doing that, it
will ask you to select a navigation graph associated
with that NavHostFragment. If you haven't already
created a navigation graph, you can do it right
in that dialog, which is what we're doing. This is what your
layout will look like. It's empty. There's just this
NavHostFragment, because the Navigation
Architecture component is the one that's
going to populate it with the various fragments
that you are going to load. But double clicking on it will
open the Navigation Editor. This is what a Navigation Editor
looks like when it's empty. First thing we're
going to want to do is add our first screen as
the starting destination for our app. In the add destination
menu, you have pre-selected all the layouts
that exist in your app. So for us, we're going to just
select that fragment welcome-- which is the layout we've
been working on previously-- and set it right there. Next, we want to select,
to add the second screen. But because we haven't created
a layout for it already, we can simply create
a new destination from the add destination menu. Doing that will offer you
the possibility of creating a new fragment class and
its associated layout, and that's the layout
that's going to be used as the second screen. Once the two screens are
in the Navigation Editor, comes the time of
linking them together. That can be done with actions. You can simply create an
action as shown on screen. In addition, you can directly--
in the Attributes Panel of the Navigation Editor-- set some of the properties
for that action, like what animation
will be played when transitioning through
that action, or pressing back. Another very interesting thing
that can be done with action is pass type-safe data from
one screen to the next. If you want to do
that, you can-- on the receiving destination-- click the plus button
in the arguments section of the Attributes
Panel, and that opens a dialog
where you can simply specify the name
of the argument, and the type of the argument. That can be a type
that is predefined, or that can be a type that
you defined in your project, for whatever object you want. Of course, building
the navigation graph is not enough to fully specify
the navigation of your app. You also need to write
a little bit of code. But it's pretty
simple, as you can see. Here, I'm just on the
item of the RecyclerView. For the OnClickListener,
I want to transition and go through that action. So what I do is I create
the action object, passing it the argument that
I specified in the Navigation Editor. And once I have the
action, I can simply call the navigate method
of the navigation library to actually perform
that transition. That's all you need to actually
do the transition you defined. One final thing you can do
in the Navigation Editor is use placeholder to fill the
rest of your navigation flow, if you don't want to bother
at that moment creating new fragments. Later on, when you're
ready to do so, you can simply go back and
replace them with layouts. I think now it's time
to actually build our second layout. As you can see, it's a layout
that involves a lot of images, and a lot of resources. We're going to see
how the resource manager can help us build it. VADIM CAEN: I was talking
before about filling gaps. One gap that was existing
in Android Studio was how to manage
your resources. So let's go to see
what the issue was. The Android Studio resource
directory structure is made for the
framework, not really for the user, because
when you get resources from your designer, it
might look like this. You might have a
bunch of folders-- I'm sorry, the other issue
first is that in Android Studio, you don't have any
thumbnail view of all the specific Android view. So layout, vector
rubble, or shapes-- the only way you can
preview those are is to double click on one
layout, or on one file, and see it in the preview. To solve this problem, we've
introduced in Android Studio 3.4 the Resource Manager,
which is a new tool that helps you import, use,
and explore your resources in a more graphical way. To open it, simply click the
button, Resource Manager, right below the project button, on
the left side of Android Studio, and it will open
this neutral window. One more time. So back to our problem. On the left side, we have
our project structure, and on the right side, we have
what the designer gave us. We can see the different
program on the file that the designer gave us. Maybe they used their
favorite design software, and used a default
export option, and it might be missing the
drawable prefix on the folder names. Or maybe they used the web
format, with the suffix, @2x. And what you would need to do
is to remove the @2x suffix, and then copy paste every
single file, one by one. The other issue is the
folder might be missing, and you would have to jump
back to the documentation to remember what the qualifier
for this specific folder was, and you have to put
them in the right order. How does it work with
the Resource Manager? Now you can simply drag
and drop the whole bunch of files that you got
onto the Resource Manager, and that will be automatically
imported and grouped by name. So as you can see here, our
resources are grouped by name, and the right qualifier
has been applied. So what just happened here? [APPLAUSE] Thank you. If we identify a qualifier-- it could be web or Android,
in your file path, like here-- we would simply create the
corresponding Android folder, and strip out any suffix that
might be present in the file, and copy it onto your project. Of course, if you want to add
more qualifiers, for example, randomly a local, and a
random language like French, and the region France,
you can simply do it here. And you don't have to
remember the order, or create manually
the folder, it will be created
automatically for you with the right qualifier. You can also rename your file
if you want to, at this point. Now, our resources are grouped
in the Resource Manager, and you can see
them all in one go. So you will see only one version
of your resources by default. But when you double
click on the resource, you will see all the
different versions with the different
qualifier applied on it, and the file type if
you were to analyze what files were taking the
most space on your application. Now, this is a feature
I'm really excited about. You can now drag
and drop your SVG, and they will be all converted
at once into VectorDrawable. [CROWD CHEERING] Thank you. So here, I have my
file picker open. I don't need to select anything. I can simply click,
open, and all my SVG will be imported and converted. Another really cool feature is
previewing all your layouts. It might be hard just
recognizing a layout by name. So when you open the Resource
Manager on the Layout tab, you can see all the
layouts, and it's way easier to find the one
you're looking for. As I was saying before,
we have a tool chain. I want to integrate this
whole tool chain together. What we did is
integrated [INAUDIBLE] with the Layout Editor. For example, here I have a
layout that I want to include, so the top part. I can simply drag and drop this
layout onto the Layout Editor, and it will create
an [INAUDIBLE].. The same applies for Drawable. Drag and drop Drawable, and
the ImageView will be created. Let's fast forward to
the end of this view. We can see that on
the previous layout our toolbar is not
the right color. What we can do is
open the color tab, and see all the colors that
are defined on our project. You can simply double
click on one of them, and it will move open the
file, and move the cursor where the color is defined. Then you can use
a new color picker to visually choose a color. The color picker
works in RGB and HSB, if you were to were to work
with a designer that chooses HSB value, or you can
use the material palette that is already there. So now, our two
layouts are ready, and we want to run
them on the app. We're going to welcome back
Ashley and Joe to tell us about inspecting new layouts. [APPLAUSE] JOE BAKER-MALONE:
Thank you, Vadim. Now, we're onto the next
part of the development cycle where we actually
get to run the app, see how it works with real
data, and make any adjustments that we might need to. Now today, if you want to see
how your layouts are working at runtime, there's the
Layout Inspector tool in Android Studio. The Layout Inspector
gives you a snapshot of the complete view
hierarchy of one screen, and some information
about the attributes that are set on each view. But right now, it has a
number of limitations. This is due in part to what
data the Android framework makes available
to Studio to show. Now in Android Q,
the framework has added a number of
new APIs for Studio to use to expose more
view and layout debugging information in Studio. Ashley is going to talk
about those new APIs shortly. To verify that the framework
additions are sufficient for us to show the information that
we want to, to the users, a couple of us from
the Android Studio team have taken a little bit of time
out from our Project Marvel work to adopt the new APIs, and
see what we can do with them. We started work on a completely
new Layout Inspector. What I'm going to show you now
is a sneak peak of the work that we've done so far. Now, this is early work. It's not yet in the
latest preview builds. But as Chad said yesterday
in the Developer Keynote, we love previews. We love developer feedback. And so, we're going to
get it out into your hands as soon as possible. Now, let's see how it works. We'll start with
the Google Trips app that we've been working on. You can see now that it's
running in the emulator. We've hooked things
up so that it's running on real
data from a user, rather than the sample data that
we were using at design time. As we scroll down
here, you can see that some of the trip
descriptions in the real data are significantly longer than
what we had in the sample data, to a point where
the text is sort of dominating the images in a
way that we hadn't intended. Let's take a look at this
in the new Layout Inspector. You can see that the new
Layout Inspector gives us a view similar to what we have
in the Layout Inspector today. If we select the
text view in question here, and then look at the
Attributes Panel on the right, we can see that there are
a few differences compared to what we have in the
current Layout Inspector. First of all, we have the
actual attribute names here, whereas previously we had a
collection of getter methods that may or may not
have corresponded very well to the actual attributes. This should make it much
easier for you to map back from what you see here,
to what you have defined in your own layouts and styles. Secondly, we have nicely
formatted attribute values for a number of
different value types, and we couldn't always
get that before. So for example, you can
see we have an ID, an enum value, a color, et cetera. Thirdly, we have
some information now about where that attribute
value is being set. So you can see that we have
this declared attributes section here, similar to what we
have in the Layout Editor, for those attributes
that are set directly on the view that's selected. Now, let's look at the relevant
attribute here, text size. Once we have this selected, you
can use your preferred navigate to declaration keystroke
to go directly from here to the layout xml where
that value is being set. Let's change it to make
it a little bit smaller. As you heard in the
Developer Keynote, in Android Studio
3.5 preview they have this new apply
changes functionality. You can hear more about that
right after this, in the What's New in Android
Developer Tools talk. But right now, we'll use it to
see our change in the emulator without having to
redeploy our app. In fact, we'll see the update
right away in the new Layout Inspector as well. This is because Layout
Inspector is mirroring what happens on the device live. If we were to
scroll back up here, we'd see that the Layout
Inspector scrolls right along as well. [APPLAUSE] Yay. Let's take a look
at another scenario. Let's say we want to implement
a dark theme for our app. Here you see we have a
light background color. Let's find out where
that background color is coming from. If we look in the
fragment xml we have here, we don't see it
set there directly. Let's take a look in
the Layout Inspector. If we select the background
here, you can see-- if you can see really well-- that we don't have
the background color set directly on this view. Now, why might that be? Well, we've only selected
the top most view here, and the background color might
be set somewhere lower down in the view hierarchy. But which view is
it being set on? Well, the new Layout
Inspector gives us an easy way to find out. [CROWD REACTION] [LAUGHS] So in the 3D view,
it's easy to see which view is drawing what here. Now, if we select that view,
you can see that the background color is indeed being set. But in what file
is it being set? It's not at the top in the
declared attributes section, so we know it isn't being
set on this view directly. But again, if we select the
property in the Attributes Panel, we can navigate
directly from there to where it's being set. In this case, it's
being set in a style. And we can navigate
directly to that style, even if it isn't referenced
explicitly by your view. The 3D representation
we saw allows us to visualize things
in other ways as well, and we're still exploring
what might be useful here. For example, it might
be useful to just focus on one view, and its children. Or it might be useful to group
views together based on what layout file they're defined in. So example for this screen,
you can see that at the top, we have the RecyclerView items,
and then the fragment, and then the activity. And behind that,
the various views that are defined
by the framework. We have a lot more planned for
the light new Layout Inspector, and I'm excited to see
what we can come up with. Now, to talk about the framework
changes that were needed to enable this, here's Ashley. ASHLEY ROSE: Thanks, Joe. [APPLAUSE] For Android Q, we've
added three new APIs to enable these new
inspection features. We have the ability to take
all the drawing commands that went into building a
frame on the screen and serialize them and send
them back over to Studio so it can replay them, and
build that lovely 3D view. We significantly
sped up how long it takes to get the properties
of views in the view hierarchy, as well as adding
additional metadata to that and making it more correct. And we added some new APIs to
the resource framework that let us see where an
attribute value came from, as well as some more
insight into the decision process of which themes
were applied when reaching that attribute value. So let's talk about
the Skia Picture. Skia is our 2D graphics library
that underlies the UI toolkit. This is a simplified view to
actually fit it on the slide, but it's a list of
drawing commands that go into building one of
our trip cards from earlier. If we look at it, it's composed
of shadows, rounded rectangles, images, text-- all of that, along
with the assets needed to render it, the image
data, the font data, et cetera. We get this from Skia natively. It's very quick. It allows us to do our
live preview because we can get this a few times a second. It's generally very small. But the problem
with this is, if we want to zoom in on
the switch here, it's composed of a text,
a rounded rectangle, and a little image for
the circle slider switch. We don't know which
views those came from. They're just drawing commands. We wanted some way to
group drawing commands by what view they came from. We looked at the
render note API-- which is an organization tree
that underlies both views and drawables-- and we added a
unique ID to each render note. We then exposed this
unique ID on the views, and annotated the
Skia Picture itself with where each render node
started and stopped drawing. This lets us on the
studio side walk through and see where a view started and
where it stopped, and associate these three drawing commands
back to the switch view. Additionally, since we
have start and stop, we have a nice nested
framework-- kind of like, HTML-- that lets us see, here's all
the drawing commands again, simplified, that went into
building this card view, as [? long as well ?] which
views they start and stop from, which let's us do nesting. Let's talk a little bit about
how we fix property inspection. To Joe's point earlier-- where everything was getter
names, or method names-- that was because we
were using reflection at runtime on the attributes
inside the view instance. Reflection isn't the
fastest thing in the world, especially on a mobile device. And for a very
complicated app, that could take up to several
seconds to render an entire view hierarchy. So we looked into
an approach of-- we have a method that
serializes everything. That gets a little brittle. If you add a new attribute to
your view, it's not updated. We added in a
annotation processor, which allows us to retain the
flexibility that the reflection provided us. All you have to do
is add an annotation if you add a new getter. Let's take a look at what that
might look like for a custom view because this will be
relevant for anyone who's building library views soon. We have a color view. It's property is a
color, and we annotate it with InspectableProperty. This gets us-- when the
annotation processor looks at it-- this gets us a
little bit more context than we had before of just
looking at the getter. So we're in Kotlin, and we can
see the @ColorInt annotation, as well as the
integer type, which we know that we've packed
a color into this integer and it's not just
a numerical value. We've got the name of
the property, which we can use to make inferences
about its attribute ID, what to call it. And of course, we
can override any of the inferences using
properties on the annotation itself. So what the code generation
for this looks like, is it builds a
companion object that will sit alongside this view. Let's take a look at what
one of those might look like. This is an inspection companion. It's a new API for Q.
It has two purposes. One, defines a list
of-- given a class-- here are the properties
defined on that class. In this case, we've
defined color. If you look into the
call to map color, we have the type there,
since it's a color. We have the property name
color, and we've inferred the attribute of ID off R.attr. This will also enable us to-- if you didn't have an
inferred attribute ID, or you supplied one-- we
would put it in there. This teaches the Studio,
if I have a view, here's what properties
I have on it, here's what their
attribute IDs are, and this allows us to
enable that part of that jump to code
completion function. The next step is
when we actually have an instance of the view,
we want to read the property. Again, since our view is defined
in Kotlin, and we're in Java-- because this is generated code-- we call view.getColor,
we have a direct call to the getter, no
reflection required. It's very fast. This enables us to do the live
updating of the view hierarchy in Studio, because
we do not have all the additional
overhead we did previously. Where all that gets us
is to a current value. We can say, here's this lovely
blue text color we have here. We can say what it
is, regardless of whether it was set in runtime. Maybe you called view.setColor. Or if it was set in resources. But most attribute values
are set in resources, so we wanted to
help with that case. We wanted to help with a
case where, in this case, it's defined in your widget. We added an API to
resources that lets you say, I've gotten this value. Tell me where it came from. We track that data, and we store
it through the entire resources framework. Additionally, we wanted
to get some insight into how styles affected this. So the resources framework--
when it's resolving an attribute value-- has to make a decision
about which style to apply. We took the decision tree and
we add an API to expose that. So it's essentially the list
of styles that were considered, but eventually maybe
used or not used while resolving that
attribute value. The problem with all this is
it's ephemeral, because views, once they've been inflated,
they forget their relationship to resources. Once they've been
constructed, they don't remember where they
came from, for the most part. We added a developer
option that allows views to store both the
map of attribute IDs, and locations where
they came from, and the style resolution stacks
from the themes on the view. So Studio-- when it's
ready, or you're interested and you want to drill down more
into a property-- come back to a view and ask
the view, hey, where did your attribute
values come from, and what are their styles? That pretty much wraps up
everything we have for Q, and I'd like to welcome
Vadim and Jerome back on the stage to wrap us up. [APPLAUSE] VADIM CAEN: You've heard
about the whole tool chain, and I hope you're going to be
using it when you go back home. There is building your layout
with the Layout Editor, and the new feature we've added. Building your navigation
with the Navigation Editor, managing resources with
a resource manager, and doing your inspection
with a new Layout Inspector. This year, I/O is packed
with Android Studio talks. Right after-- in
the Amphitheater-- you can watch the What's
New in Android Development Tools, presented by Tor
and [? Ja. ?] Then you have What's New in the Android
Build System on Stage 2, which is on the other side,
which starts this afternoon. I have little red dots here. Android Studio Tips
and Tricks, presented by a curated selection of
engineers and project managers, Stage 2. And finally tomorrow, What's
New in ConstraintLayout and Motion Layout
by Nicolas and John. We're going to be taking
questions right outside here. Thank you very much for
coming, and I'll probably see you next year. [MUSIC PLAYING]