Multi-window support is a neat feature we're waiting for in Android N, and one we've wanted to be available on all devices for a long time. For it to be an enjoyable experience, though, developers may have to make some changes in their apps to support it correctly.
One of the Google I/O sessions was for developers to learn about the new APIs and system behavioral changes multi-window support brings.
The session was presented by Wale Ogunwale, the Technical Lead Manager for the Android ActivityManager and WindowManager framework components — he and his team are the ones responsible for multi-window on Android.
You can watch the Multi-Window Mode session on YouTube, but we also provide an overview of the session here.
N introduces three different multi-window modes:
- Split-screen mode: this is the mode that's available by default. As the name implies, it allows you to open two applications side-by-side.
- Freeform mode: manufacturers can enable this on larger devices, which allows users to freely resize activities in addition to the split-screen mode.
- Picture-in-picture mode: aimed at Android TV devices, this mode is intended for video players to run in a pinned window while the user interacts with other applications.
It's worth noting that we've covered multi-window on N before and offered some criticism of the current system. With that in mind, we hope that the freeform mode moves a bit closer to the picture-in-picture mode, as that would have useful applications on all devices.
Adding Multi-Window Support
Enabling multi-window support in your apps is simple: you don't need to do anything if you're already targeting N.
Should you choose to disable multi-window, you can do so by setting the
android:resizeableActivity activity attribute in your manifest to
false. This should only be done if truly justified, as it makes your app stand out in a bad way by always launching in fullscreen mode even if the user (or another app) tries to launch it in multi-window mode.
It's important to note that a root activity's attributes apply to all activities within its task stack. In other words, if you have an activity that can be started by other apps, make sure it supports multi-window mode as you can't guarantee other apps will launch your activity in a new task using
Picture-in-picture mode support must be declared explicitly via the
android:supportsPictureInPicture attribute. Note that this attribute is ignored if
Layout attributes can be used to set default dimensions and placement for freeform windows, or to specify a minimal width or height both for freeform and split-screen modes:
android:defaultHeight: the default dimensions of the activity (freeform mode).
android:gravity: the initial position of the activity (freeform mode).
android:minimalHeight: the minimal dimensions of the activity (freeform and split-screen modes)
You can find a code example in Google's Multi-Window Playground sample app on GitHub: AndroidManifest.xml.
System behavioral changes
With the introduction of multi-window support, you might need to double check a few things in your apps to make sure they operate correctly.
Understanding the Activity lifecycle
The activity lifecycle is unchanged in multi-window mode:
That being said, some subtle differences between the activity states may result in unintended behavior you wouldn't normally notice before N. It's important to know that
Activity#onPause() are called when your app gains or loses focus, but not necessarily when it starts or stops being visible. (Remember that only one app may have focus at any given time.)
For apps that update the content constantly (e.g. video playback), make sure to handle starting and stopping content updates in
Activity#onStop() instead. Not doing so for video apps, for instance, will mean that playback will only occur if the app is focused, which defeats the purpose of multi-window mode. The official YouTube app had a similar problem when the Android N Developer Preview first launched.
Handling Runtime Changes
When an app is put into multi-window mode, some device configurations will change. You can either allow your activity to restart (in which case retaining Fragments might be a good idea, if your activity must perform an intensive operation on startup), or choose to handle the configuration changes explicitly instead.
Four device configurations may change when entering or inside multi-window mode:
orientation. Refer to the Android Developers documentation for more info about each attribute, but note that
orientation no longer refers to the device's orientation in this case. Instead, it merely indicates whether your activity's width is larger than its height (landscape) or not (portrait).
Declaring that your activity will handle these changes can be done from the manifest:
<activity android:name=".MyActivity" android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation" />
Keep in mind this means you'll actually need to handle these changes in
Activity#onConfigurationChanged(), by manually updating views or reloading some resources.
Disabled Features in Multi-Window Mode
Some system features won't be affected by your activities while in multi-window mode:
- Status bar and navigation bar changes, such as dimming/hiding the system bars or using immersive mode, will have no effect. This makes sense since your activity only occupies part of the screen.
android:screenOrientationactivity attribute also has no effect in multi-window mode: since your activity will be resizeable, it no longer makes sense for it to have a fixed orientation.
New API Additions
New callbacks have been added for multi-window events, as well as methods to query the current state.
Activity#onMultiWindowModeChanged(boolean inMultiWindow): called when activity state changes from fullscreen to multi-window and vice versa.
Activity#onPictureInPictureModeChanged(boolean inPictureOnPicture): called when activity state changes to/from PIP mode.
Activity#isInPictureInPictureMode(): return whether the activity is in multi-window/picture-in-picture mode or not.
Activity#overlayWithDecorCaption(boolean overlay): for freeform windows, this method can be used to make the caption (the bar used to drag the window around) overlay the content instead of pushing it down.
PS. Except for
Activity#overlayWithDecorCaption(), these methods are also provided by the
Starting Activities in Multi-Window Mode
Activity#enterPictureInPictureMode()can be used to put an activity in picture-in-picture mode. Note that activities in PiP mode don't get notified about input events — use
MediaSession#setMediaButtonReceiver()if you want to handle such events. Also make sure to check the Android Developers website if you're interested in Picture-in-picture on Android N.
- If the device is in split-screen mode, you can tell the system to launch another activity next to yours by using the
Intent#FLAG_ACTIVITY_LAUNCH_ADJACENTflag. The flag has no effect if not in split-screen mode.
- If the device is in freeform mode,
ActivityOptions#setLaunchBounds()can be used to specify the new activity's dimensions and location on the screen.
For code examples, check out the Multi-Window Playground sample app: adjacent activity example, launch bounds example.
Drag and Drop
While drag and drop support has been around since Honeycomb, it was previously only possible within the same activity. It's now supported in multi-window as well.
Implementing this seems to be mostly the same as before, with a few additions for cross-activity drag and drop:
- New alias for
- To enable cross-activity drag and drop, pass the new flag
- If you need to give URI permissions to the recipient activity, pass the new flags
View#DRAG_FLAG_GLOBAL_URI_WRITE, as appropriate.
- New alias for
- Replaces the drag shadow for a drag operation currently in progress. Can only be called by the app that originated the drag operation.
- Cancels a drag operation currently in progress. Can only be called by the app that originated the drag operation.
Other Notable Additions
- Checking if a device supports freeform or picture-in-picture modes is possible via
android:windowBackgroundattribute can be used as the background drawable, if the activity is being resized and its rendering is lagging behind. If
android:windowBackgroundFallbackis used instead. Refer to the Multi-Window Playground sample app for an example.
UX Best Practices:
Wale offered some best practices to make sure your users have the best experience possible:
- Handle mode changes elegantly:
- Maintain UI consistency regardless of orientation. Don't have elements change positions to allow for smooth transitions.
- Expanding on the above, don't switch between very different layouts for phone/tablet layouts. Instead, adapt the tablet layout for smaller sizes for consistency.
- Make sure your activities adapt to small sizes by following the Material Design patterns.
FLAG_ACTIVITY_LAUNCH_ADJACENTwhen it makes sense to make for a more enjoyable experience in split-screen mode.
- Only declare resizing incompatibility when justified. As we discussed above, it makes your app stand out in a bad way otherwise.
Wale ended the session by offering some additional useful resources:
- Multi-Window Documentation.
- Material Design guidelines for split-screen mode.
- Sample multi-window app.