[MUSIC PLAYING]
ROB ORGIU: Hello, everyone.
And thanks for being here.
My name is Rob, and I'm an engineer on the Developer
Relations team.
RAN NACHMANY: Hello, everyone.
I'm Ran, and I'm also an engineer in the Android
Developer Relations team.
ROB ORGIU: The same team?
RAN NACHMANY: The same team.
ROB ORGIU: Oh, thanks.
I missed that.
OK, should we get started?
Please say yes.
AUDIENCE: Yes.
ROB ORGIU: Perfect.
OK.
So we used to live in a world where
one screen would mean a single activity being displayed,
right?
Yeah, that's no longer the case.
There are two ways in which this can happen.
So your users have much more powerful devices
in their pocket.
And they're actually much bigger than they used to be.
So it's perfectly fine for them to use multiple apps
at the same times.
You cannot really opt out of that.
And we call it Multi-Window.
On the other hand, as a developer,
you can actually opt in to a specific feature
that would allow you to show two activities side-by-side.
And we call it activity embedding.
Let's start with Multi-Window.
With Multi-Window, you can do two things at the same time
either from the same app or from different apps.
Of course, this means that some things have to change.
For example, multiple activities are
being resumed at the same time.
But let's take a step back.
There have been important changes
across versions of Android, one of which
is the change in lifecycle management for Multi-Window.
While before Android 10, only the focused activity
was resumed, with Android 10 and newer,
all the activities currently on-screen are resumed.
And the last one the user interacted with
is notified with a flag.
Let's see that in detail.
Up until Android 9, you would acquire resources
during the startup phase, update the UI during the resume step,
and finally, release the acquired resources
and stop UI updates in the stop phase.
With Android 10, things changed a little bit.
You do the same things in the start
and resume phase and stop UI updates in the stop phase.
But there is something new.
OnTopResumedActivityChanged will tell you via flag
if yours is the topmost activity, which
is the one the user most recently interacted with.
So let's see that in code.
onTopResumedActivityChanged it is a method in your activity
that you can override.
And this flag will tell you if you are the topmost activity.
If you are the topmost activity, you
will attempt to acquire new resources.
And if you're not, you should actually
release your resources.
Because that means that the user is not
interacting with your app anymore.
Oh, I lost a piece.
Well, talking about this, we need
to mention exclusive resource access.
Well, we should add in audio effect here,
like something sad.
RAN NACHMANY: Something like, [IMITATES BEETHOVEN'S 5TH
SYMPHONY].
[APPLAUSE]
ROB ORGIU: Yes, that.
So that set the mood right.
RAN NACHMANY: Perfect.
ROB ORGIU: OK.
What are exclusive resources?
Well, they are all the resources that
can be accessed by only one app at a given time,
like Microphone or Camera.
Why is that?
Well, each app can request a different bitrate
or resolution, for instance, or totally different features,
like video and still imagery.
If you're thinking about a way to get around
these limitations, we have bad news.
Remember that settings-- your activity is not resizable
will not grant you exclusive access,
as Android 12 and newer can force any app
to be Multi-Window.
Moreover, as we saw before the break,
Camera preview will freeze if not done properly.
It will not resolve on focusing back.
Or even worse, your app will crash.
Next up, the big elephant in the room--
configuration changes.
We really tried to avoid this, but you all
saw that coming, right?
So when Multi-Window is initialized,
activities are notified of one configuration change because
of course, the size of the window is changing.
But it often triggers multiple configuration changes
because orientation, size, position on the screen cannot
change.
The default behavior when configuration changes
occur on Android is to kill the activity
and restart it, with, more often than not, a loss of state.
Be it window contents, core position, long operation
stopping unexpectedly, or wrong position in the navigation
hierarchy, all of these will mean a bad experience
for your users.
There are basically two ways you can avoid losing your state.
The first way is to let the system handle the activity
destruction and recreation, leveraging onSaveInstanceState,
ViewModel, or rememberSaveables.
And the other is handling a specific set of configuration
changes in your code.
Let's see how.
Well first, in your AndroidManifest file,
you need to add the Config change line in your Activity
tab, listing all the configurations
that you want to manage.
Then in your activity, you override
the onConfigurationChanged method
and run your layout calculation and invalidation in there.
And now I would like to invite Ran to tell us something
more about activity embedding.
RAN NACHMANY: Hey.
Thank you, Rob.
So we've seen how a user can run two apps
at the same time, where each app has
one activity being displayed.
Now I want to talk to you about a different scenario, where
we as developers-- we want to show more than one activity,
two activities in our app.
And this is where Activity Embedding is really useful.
Activity Embedding allows you to display two activities
side-by-side, which is great if you
want to implement this little layout with minimum
or even zero code refactoring.
Activity Embedding will automatically
choose the right presentation based on the available screen
size and the configuration that you provide.
That means that you don't need to branch your code to handle
small and large screens.
In other words, there is no established Boolean.
So forget about that.
All right, here's an example of a great amazing application
that we wrote.
It has one activity that just shows a list of fruits.
And when the user clicks on the fruit,
it launches another activity that shows the lorem ipsum
details of that fruit.
I know it's super complicated.
This is how it runs on a Pixel 7.
Now, if I'm going to go ahead and I'm
going to launch the same app with the same activities
on a tablet, suddenly, there's enough room
to display both activities.
And Activity Embedding will automatically
choose the right presentation layer
and will show them side-by-side.
But now the cool thing.
The library also supports configuration changes
on runtime.
That means that if the user resizes my application,
Activity Embedding-- the library will automatically
switch between showing one activity or two activities
side-by-side.
Yeah, I hear that.
OK.
So let's take a look at how it works.
Activity Embedding doesn't change the fundamental way
that activity ordering on Android works, OK?
Under the hood, it creates two containers or activity stacks,
if you will--
primary and secondary.
The secondary one is always considered
to be above or on top of the primary one.
That means that if there is enough room,
we're going to display two containers side-by-side.
But if there is room to display only one container,
the one on top will be displayed.
And this is how we keep the same ordering the way we
used to have since Android--
I don't know-- 1.
Here's an example.
Let's say we have an app with a list activity on the left
and a details activity on the right, OK?
Let's assume that the user clicks
on something on the details activity, the one
on the right, which launches a subdetail activity--
another activity.
And as you can see, when a new activity is being launched,
it is automatically bound to the container
that it was launched from.
Let's take a look at another scenario.
In this example, we have two activities, A and B.
And for some reason, we decided to give activity B more room
because it's a foldable device.
There's more room.
We can display more information.
Makes perfect sense.
However, the library also supports physical changes
of the screen.
So if the user suddenly folds the device,
suddenly, we have a different physical screen.
The external screen of a foldable device
is usually way smaller than the internal one, right?
What will happen is that Activity Embedding
will resize and reposition the container,
resulting with the same ordering that we expect,
that the user expects, automatically.
We don't need to change anything in our code to support that.
And a similar thing happens when the user
will reopen their foldable.
And the secondary container will be expanded,
and both containers will be displayed side-by-side.
Let's take a look at the code.
This is basically the heart of Activity Embedding--
configuration file in XML.
First, I'm going to define, how do I want to split the screen?
The default is 50/50.
And in this case, I decided to go with 30/70, which sometimes
works better on tablets.
I also define the minimum width to trigger a split--
600 DP.
I chose this because this is the threshold
to move from compact screen size to medium one.
We also define that when all activities on one container
are being dismissed, the activities
on the other container will be dismissed as well.
This means that if the user navigates back
on all activities in one container,
the activities on the other container
will be finished as well.
And we define a split filter, which basically
tells the system that, hey, if I'm going to launch the detail
activity from the list activity, it will trigger a split.
Now, we need to inform the library about those rules.
And we should do that before any other component
of the application loads so that these rules
can be applied to any activity before it is started.
And we can use jetpackapps.library to do so.
So we're basically going to tell an Android manifest, hey,
we're going to use the apps.library.
And this is going to be my SplitInitializer class.
And we want to implement that class.
It's literally those two lines of code.
Call in the split controller.
Initialize it with the XML file that we provided.
The last thing we need to do is add the following lines
to both activities-- list and detail.
That's not a mistake.
All the lines that are needed to change my activities
are being displayed right here.
That means that I had to change zero lines of code,
and my refactoring is done.
That was the best coding software in my life.
[APPLAUSE]
[CHEERING]
Thank you.
So embedding activities from your own app
is great and super helpful if you
want to design for large scale.
But that's not all.
Starting with Android 13, you can embed activities
from other apps as well.
Yeah, I hear that.
All right.
Cross-application Activity Embedding
allows a tight visual integration between activities
that belong to different apps.
This allows the host application to provide
an immersive experience to the user.
Here's the real-world example.
Let's take a look at the wallpaper
selector that shows up--
all right.
Let's take a look at the wallpaper selector
that shows up in Settings.
The activity on the left belongs to the embedding host.
Basically, it comes from the Settings app.
The activity on the right belongs
to a completely different application,
which is the Wallpaper app.
Another scenario is where, we as developers-- we
want to allow the user to perform
a specific, focused task on another app
without leaving the visual context of our own app.
Think about if you have a file browser application
and you want to allow file preview, or a chat application,
and you want to allow the user to watch a video link,
or view a preview without leaving
the context of the visual context of your chat.
Now, allowing another application
to embed your own activity gives a lot of power
to that other application.
This is why this is an opt-in feature,
meaning that you need to tell Android OS that, hey, I
want to allow this activity to be embedded in other apps.
And there are basically two trust models
that you can do that.
If there is a tight integration between two or more apps,
you can actually specify the SHA1 certificate of the apps
that you want to allow embedding your activities.
But in some cases, you don't know what
the SHA1 certificate will be.
Maybe your activity is designed to be used by multiple apps.
Maybe that SHA1 certificate will change
after you publish your app or whatever.
So you can decide to go with an untrusted model.
Basically, you're allowing any application
to embed your activity.
And you do that with adding simple line to your activity
entry in the manifest.
So if you want to go with a trust model,
you can use the nonactivity embedding search.
You can define simple string or an array of certificates.
And if you want to allow any apps to embed your activity,
you can go with the allowUntrustedActivityEmbedding,
which is a pretty self-explanatory flag, I guess.
All right.
If you want to learn more, please
go ahead to developer.android.com,
where you can learn how to make your app Multi-Window
compatible and how to implement Activity Embedding.
I also encourage you to take a look
at the source code of the amazing fruit app
that we've shown here today.
Thank you, and we hope you are going
to have a fruitful day today with Android.
[APPLAUSE]
[MUSIC PLAYING]