Monday, January 9, 2017

Android Nougat’s Freeform Window Mode: What It Is and How Developers Can Utilize It

Freeform window mode, as first demonstrated by Ars Technica

When Android 7.0 Nougat was first announced early in 2016, it brought with it a much-requested feature to the Android platform — multi-window support. Most people are aware of the split-screen multi-window support enabled by default on all Android Nougat phones and tablets. Android TV devices with Android Nougat come with support for picture-in-picture multi-window support.

However, there is a third multi-window mode present in Android Nougat that not very many people are aware of: freeform window mode. This mode allows Android to present apps as floating windows that can be moved and resized at will by the user. It's essentially Android's implementation of a stacking window manager.

 

In the Android SDK documentation, it states that:

Manufacturers of larger devices can choose to enable freeform mode, in which the user can freely resize each activity. If the manufacturer enables this feature, the device offers freeform mode in addition to split-screen mode.

And also, in the Android 7.0 CDD:

Device implementations with screen size xlarge SHOULD support freeform mode.

This indicates that any new large screen Android device that ships with Android 7.0 could potentially have freeform window mode enabled by the manufacturer.

However, this is absolutely not a hard requirement. It is possible to force any Android Nougat device (with developer options enabled) to support freeform window mode using one of two different methods:


Enabling freeform window mode on any Android Nougat device

Turning on the "Force activities to be resizable" option allows apps to run in freeform mode on any device

Method 1 (a computer with adb is required)

Make sure USB Debugging is enabled in Developer Options. Then, hook your device up to a computer with adb installed, and execute the following command:

  adb shell settings put global enable_freeform_support 1  

Method 2 (no additional requirements)

Enable the "Force activities to be resizable" option at the bottom of Developer Options.

Both of these methods require the System UI to be restarted before they can take effect. The easiest way to do this is to reboot your device (or, if your device is rooted, you can simply kill the com.android.systemui process)


OK, so freeform mode is enabled… now what?

If you enabled freeform mode using Method 1, then there will be a new button on app entries in the Overview menu to launch an app into freeform window mode.

With Method 2, however, it is not possible to launch an app into freeform mode through Android itself. Fortunately, it is possible for any third-party launcher to launch an app into freeform window mode using standard Android APIs that were finalized as part of API level 24.

The key to launching an app in freeform mode is to call the ActivityOptions.setLaunchBounds() method. This method takes a Rect as an argument, containing the window bounds that the app will launch with.

You can then start the app with startActivity(Intent, Bundle). If you don't already have an ActivityOptions bundle, you can create one with ActivityOptions.makeBasic() and then calling setLaunchBounds() on the freshly created bundle.

Note that by default, if there is already a task for the app present in the Overview screen, then Android will simply redirect you to the existing (fullscreen) task that was previously launched by the user. You will need to clear any tasks for the app in Overview before attempting to launch the app into a freeform window. (For apps with activities that launch in standard or singleTop modes, you can force a new window to open by adding the Intent.FLAG_ACTIVITY_MULTIPLE_TASK flag to the intent before calling startActivity().)


How does freeform mode work under-the-hood?

There is an excellent article written that explains how multi-window mode, including freeform mode, is implemented in Android Nougat. (NOTE: the article is written in Chinese, so be sure to run it through Google Translate)

In a nutshell, apps in freeform mode run in a separate stack from the rest of the system (think: virtual desktop). Therefore, it is not possible for freeform apps to run on top of the launcher or on top of another full-screen app.

Apps running in freeform mode (that don't have android:windowIsFloating set to true) have a DecorCaptionView added as a child of the top-level DecorView. This view contains a LinearLayout defining the window's caption bar for moving, maximizing, and closing the window. While I don't recommend it personally, it is possible to access and customize this view by getting the DecorView using Window.getDecorView(), casting it to a ViewGroup and then accessing its child views.

Any app that is designed to behave well in Android's standard split-screen multi-window mode will work in freeform mode. isInMultiWindowMode() will return true for apps running in freeform mode. There are a few other publicly-available classes and methods that an app can use that relate specifically to freeform mode:

  • Window.setDecorCaptionShade(): this method can be used to override the shade of the caption controls (the maximize and close button) for apps in freeform mode.
  • Window.setRestrictedCaptionAreaListener(): this can be used to detect when a window is moved around in freeform mode. The Window.OnRectrictedCaptionAreaChangedListener is called every time the position of the caption controls change (when a user moves the window around), and provides a Rect with the new bounds of the caption controls.
  • ActivityInfo.WindowLayout: this class contains information declared in the app's manifest as to the initial positioning of a freeform window that an app can request on launch. For example, you can list the following in the <activity> tag of your manifest:
      <layout      android:defaultHeight="640dp"      android:defaultWidth="360dp"      android:gravity="center" />  

    Then, when the device is already in freeform mode and the app is launched, it will launch with these specified boundaries.


Examples of freeform window mode in action

Taskbar adds a start menu and recent apps tray to compliment freeform window mode

In the summer of 2016, while Android Nougat was still a developer preview, I released an app called Taskbar that provides a Windows-like start menu and recent app list in a system overlay. It allows users on Nougat to launch apps in freeform window mode — and, since Taskbar uses an overlay, it can stay on screen in the freeform window environment. The combination of Taskbar and freeform mode gives any Android device, especially tablets, a PC-like feel.

You can download Taskbar on Google Play, or view the source code yourself on GitHub. In addition to the concepts mentioned in this article, I also employ a few tricks to keep the freeform mode environment active even when no freeform windows are displayed on screen. Users can also optionally set Taskbar as their default launcher to allow their device to boot automatically to the freeform mode environment.

Since there are no devices that officially ship with freeform window support enabled by the OEM (as of this writing), I recommend using Taskbar as a tool for developers to test their apps in the freeform window environment on devices that don't otherwise support it.

In addition to Taskbar, I've also modified the Launcher3 source code from AOSP to allow it to launch apps into freeform mode. This is a straight clone of the stock Android 7.1.1 launcher, with the bare minimum modifications necessary to allow it to launch freeform apps. I've provided this modified launcher in the hope that other developers will implement support for launching freeform windows in their custom launchers. You can view the source code on GitHub, or download a sample APK.

My hope is that developers of custom launchers can utilize this code and enable support for launching freeform window apps for those users that desire greater flexibility for window management on their large-screened devices.



from xda-developers http://ift.tt/2j0pnDv
via IFTTT

No comments:

Post a Comment