From Punched Cards to Prompts
AndroidIntroduction When computer programming was young, code was punched into cards. That is, holes were punched into a piece of cardboard in a format...
Last week, a few nerds at Big Nerd Ranch attended the 2018 Android Dev Summit .
While the conference covered multiple topics, the biggest piece of news was support for foldable devices.
Foldables provide a new user experience – while folded, apps on the the device should prioritize quick and easy access.
Users can then unfold a device to get a tablet-like experience with more info and context for the current activity.
Samsung unveiled mockups for device that will go on sale in 2019 that has one window when folded but can display up to three when unfolded.
The unfolded display will contain one large screen and up to two more smaller screens on the side, allowing the user to move activities across these screens.
It’s important to note though that any foldable device will be able to choose how many windows activities can display on.
The first concept that Google introduced is “screen continuity” – where the user should be able to seamlessly continue what they’re doing after they fold or unfold the device.
If the device is unfolded, the user will be able to dive deeper into the current task.
So as a developer, how will you handle screen continuity?
The good news is that the guidelines and APIs for this already exist!
Whenever a device is folded or unfolded, a configuration change will fire in the displayed activities.
Android gives you tools to handle state during configuration changes, such as when the device is rotated or if the window size changes.
By default, an activity that receives a configuration change will restart – which is not ideal.
To handle the configuration change without restarting you can use the android:configChanges
attribute and declare resizableActivity=true
in your manifest.
If your app targets API level 24 and you do not specify a value for this attribute, resizableActivity
will default to true.
Then to properly handle the configuration change, you’ll want to override the onConfigChange
callback in your activity.
ConstraintLayout can also be a useful tool for dealing with resizable activities, which is covered in detail by the Android App Resizing for Chrome OS codelab.
If you choose not to handle configuration changes yourself, you can rely on the activity restarting and use the onCreate
and onSaveInstanceState
callbacks to handle configuration changes. ViewModels can also be used to persist data across the Activity lifecycle.
Currently in a multi-window environment, the activity the user last touched is in the resumed state, while all other visible activities are in the paused state. The current behavior is documented in the Android docs.
However, Google announced that starting in Android Q all activities will remain in the resumed state in a multi-window environment.
This is in large part because Google noticed it was not clear to users why some activities were in less interactive states in a multi-window environment and that apps weren’t properly handling the paused state.
While in the paused state, an activity could still be visible to the user, but some apps would not respect that behavior and instead started to tear down the activity in the onPause
callback.
So while in the paused state, some activities displaying video might pause, or activities with real time chat may stop listening for new messages.
For apps that want to use the new multi-resume mode in Android P, they can opt in by adding the following meta-data to the Android Manifest:
<meta-data android:name="android.allow_multiple_resumed_activities" android:value="true">
However the device OEM must also opt in for multi-resume mode to occur and currently no devices do.
This is to prevent breaking changes for apps and devices that can’t properly handle multiple activities in the resumed state.
If an app launches activities in multiple tasks, a user can view these activities side by side in a multi-window environment.
With the possibility of apps having multiple activities in the resumed state, one gotcha to look out for is your app or any dependencies attempting to hold a reference to “the only” resumed activity, since now there can be more than one!
Another thing to be cautious about is accessing shared state across your application.
Instead of having a LiveData
singleton that is shared across activities – have a single database and use multiple LiveData
instance to observe changes to that information.
Android apps can already support multiple displays on platforms such as Desktop Mode or Chrome OS.
So to ensure your app is ready for a foldable device, you can make sure your app performs correctly on those platforms.
Starting in Android Oreo, an activity can be launched on a non-default display.
These APIs allow you to query for what displays are available and what its characteristics are.
In a multiple display environment like a foldable device, you can use these APIs to launch on one of the available screens.
You may choose to inspect the characteristics of screens before you launching your activity.
Activities that are broadcasting media may choose to launch on larger displays, and you’ll want to filter out any displays that are currently off.
val displayManager = application.getSystemService(Context.DISPLAY_SERVICE) as DisplayManager
val displays = displayManager.displays
val targetDisplay = displays.first()
//Check if the display is public, private, or secure
targetDisplay.flags
//Get the size, resolution, and density of the display
targetDisplay.metrics
//Check if the display is on or off
targetDisplay.state
Then you can choose to launch your application on that screen.
val options = ActivityOptions.makeBasic()
options.launchDisplayId = targetDisplay.displayId
startActivity(intent, options.toBundle())
These screen can be windows on the device, or they could also be virtual displays that Android creates.
One example of this is Chromecast, where Android creates a virtual display on the user’s TV for apps to cast to.
However, there is the possibility that Android will not allow your app to launch in activity on that screen, even if it appears as an available screen.
In this case a SecurityException
will be thrown, which can be handled with a try
/catch
.
This exception could be thrown because Android has deemed the window as not a safe place to display your activity, as is the case for virtual displays.
You also need to be careful about which context you use, since resources accessed by your activity and application may resolve differently.
If you were to ask for the bounds of the window with the activity’s context, you would get the size of screen that the activity is taking up.
val currentDisplay = activity.windowManager.defaultDisplay
But if you were to query for the bounds of the window with the application’s context you would get the size of the entire device that the user is holding.
val appWindowManager = application.getSystemService(Context.WINDOW_SERVICE) as WindowManager
Behavior for drilling deeper into some activities while stopping others when folding or unfolding can vary by device.
If there aren’t enough displays for resumed activities to take up, the device will choose which activities will be stopped.
There is no way for your app to know if it’s about to be stopped or not, so your app should gracefully handle the onCreate
, onStop
, and onConfigChange
callbacks.
The teams at Android and Samsung have committed to sharing an emulator for foldable devices by Q4 of this year.
This emulator will initially be geared towards Samsung’s Infinity Flex device and will be made available on Samsung’s Developer site.
Later, an AOSP emulator will be made available through Android Studio that will have a toggle for folding and unfolding the device, and some options for configuring multiple displays.
If you’re eager to start support for foldable devices, there are currently two ways to try out your apps in a multi-window environment:
To learn more about resizable activities or multi-window environments, check out Google’s codelab about Optimizing your Android App for Chrome OS as well as Kristin’s previous blog post on UI Updates in a Multi-Window World.
If you want a deeper dive into Google’s and Samsung’s announcement on foldable devices, check out the recording of Is Your App Ready For Foldable Phones from Android Dev Summit and be sure to read the accompanying blog post from the Android Developers Blog.
Do you have thoughts or further questions about supporting foldable devices? Let us know in the comment section below!
Introduction When computer programming was young, code was punched into cards. That is, holes were punched into a piece of cardboard in a format...
Jetpack Compose is a declarative framework for building native Android UI recommended by Google. To simplify and accelerate UI development, the framework turns the...
Big Nerd Ranch is chock-full of incredibly talented people. Today, we’re starting a series, Tell Our BNR Story, where folks within our industry share...