Opting Out of Multi-Window is Hard

The docs make it seem so easy:

Set [android:resizeableActivity] in your manifest’s <activity> or <application> node to enable or disable multi-window display. If this attribute is set to true, the activity can be launched in split-screen and freeform modes. If the attribute is set to false, the activity does not support multi-window mode. If this value is false, and the user attempts to launch the activity in multi-window mode, the activity takes over the full screen.

Alas, it’s not that easy, at least not in all situations.

The key rule of multi-window is: the task determines the window.

Suppose that you have two activities. One you are perfectly content with being used in split-screen or freeform modes. The other, not so much. So, you set android:resizeableActivity to be true on the first, false on the second. You’re thinking that these attributes will implement what you want.

What really happens is that either activity might behave in either fashion… depending on which one is started first, how it is started, and what other attributes you might have on the respective <activity> elements.

If the true activity is started first, then some other app tries starting the false activity (because it happens to be exported), that false activity will wind up in the same task as the true activity, by default. Since the true activity says that multi-window is cool, the false activity appears in split-screen mode, despite having android:resizeableActivity be false… because it is in a task that allows multi-window mode.

Since you have no control over what Intent flags are used for exported activities, your options are somewhat constrained:

  • Just support multi-window mode for all of your activities. This may or may not be that easy, since windows can get pretty small.

  • Use the same android:resizeableActivity value for all exported activities, so any task will have the right multi-window behavior.

  • Don’t export any activities other than the launcher activity, so you start all the rest of the activities yourself and have full control over the Intent flags that you use. You can then try to work out the right set of flags to give you the behavior that you want. For lots of apps, this will wind up being the answer, as many apps do not export anything other than the launcher activity already.

  • Use android:taskAffinity to try to route different activities to different tasks, and hope that this doesn’t screw other stuff up too much, since tasks are for more than just multi-window behavior.

  • Have the exported activity not be the “real” activity, but instead have it use Theme.Translucent.NoTitleBar (to have no UI of its own). Then, have it start the real not-exported activity with whatever Intent flags that you want, so you have better control over how your real activity gets started. This would be more practical if we had a reliable isInMultiWindowMode(), as that might impact what flags we choose.

Of course, there may be other options that I am not thinking of.

Making this more of a challenge is that we do not have real freeform multi-window mode support yet. Android-on-Chrome OS is starting, but it appears that Chrome OS support will be weird and not something that we can rely upon as a predictor of future results. I had expected a freeform multi-window announcement at Google I|O, other than Chrome OS, and that did not happen.

As with my earlier blog post on exported activities and freeform windows, getting multi-window right will require a fair amount of testing. Unfortunately, our time for this testing is running out, as Android N is supposed to ship to production devices in the July-September timeframe.

Want an expert opinion on your Android app architecture decisions? Perhaps Mark Murphy can help!