The CommonsBlog

In Split-Screen, Not All HOMEs Are Created Equal

Multi-window modes, such as split-screen on mobile devices, are shaping up to be a never-ending source of unfortunate behavior in edge cases.

This Stack Overflow question is yet another edge case, where your activity’s behavior when the user presses HOME differs, depending on whether the device is in normal mode, in split-screen mode with your activity in the left/top pane, or in split-screen mode with your activity in the right/bottom pane.

We are used to the notion that when the user presses HOME, we are called with onStop(). In fact, onStop() is even more important than before with Android 7.0, as our activities will be paused (but not stopped) a lot more with multi-window. So, whereas we might have used onResume() and onPause() for setting up and tearing down foreground work, we might now switch to onStart() and onStop().

However, onStop() is not always called when the user presses HOME.

If the device is in normal, non-split-screen mode, and the user presses HOME, your foreground activity moves to the background, and onStop() is called.

If the device is in split-screen mode, and your activity is in the bottom or right pane (depending on device orientation), and the user presses HOME, your activity is stopped, so you get an onStop() call. Visually, the activity animates off-screen fully, and if the user presses the RECENTS button, the pane you had been occupying is replaced with the recent-tasks list.

So far, so good.

But what the Stack Overflow question – and July’s bug report – point out is that if your activity is in the top or left pane of split-screen, and the user presses HOME, your activity is not stopped. Arguably, this is because a thin slice of the activity is still visible along that edge, as a hint to the user that they are not really at their home screen. Instead, they are in a state that I will call the “transient home” state.

Since your activity is not called with onStop(), your code keeps chugging along. The quintessential example, cited in the Stack Overflow question, is the video player: the video player keeps playing.

Google’s assertion is that this “transient home” state should indeed be transient:

we see the transition to the home screen as a very quick action is being performed to launch another app and the device will only be in that state for a very short amount of time

(from this issue comment)

I know, it feels weird, but it is supposed to be a mode that users are in only briefly

(from Ian Lake’s comment on his own answer to the Stack Overflow question)

The problem with this theory is that users are not automatons. They will do whatever they like. Some percentage of users will be oblivious to the differences between HOME-in-split-screen and HOME-otherwise. In particular, they will press HOME, and then not continue on to run some other app, but instead just leave their device.

For the video players, games, and other apps that use android:keepScreenOn or setKeepScreenOn() to hold a full wakelock while they are visible… well, that wakelock stays in force, and the device continues draining the battery.

This is bad.

For interactive activities that use full wakelocks, like games, you can kinda work around this. Rather than rely upon onStop() exclusively, also “stop” the activity if the user has not tapped the screen after some number of minutes.

However, this approach does not work for a video player or other activities that are not interactive. You will probably need to release the wakelock in onPause(), and then hope the device screen turns off of its own accord, triggering more lifecycle methods in your activity.

I filed a feature request to get notified either about entering/leaving this “transient home” state or to be notified that the user seems to have abandoned their device in that state, so we can take appropriate steps in our activity.

Sep 28, 2016

Android on Chrome OS: Shipping to Release Channel

The Play Store is shipping on the Chrome OS release channel to the ASUS Chromebook Flip and the Acer Chromebook R11.

In other words, the first few Chrome OS end users are starting to get access to Android apps, probably including yours.

The release announcement phrases it as “This build includes the Google Play Store (beta)”. It is unclear if they consider Android on Chrome OS to be in beta, or just the Play Store. Regardless, users might be given a bit of warning that this is very new tech.

The documentation regarding Android on Chrome OS has moved into the standard Android developer site. If you have not done so already, plan out what you are going to do, particularly with respect to testing, so see how your app behaves when running on a Chromebook rather than on a traditional Android device.

Sep 26, 2016

Internal Storage Metadata Leaks

Usually, with internal storage, we are aiming to prevent other apps from reading or writing our files.

However, as Arne Swinnen points out, there is another possibility: reading metadata about your files, such as size and last-modified timestamp, or even their simple existence. While reportedly this is fixed in Android 7.0, it is unclear how many older devices will get the fix. Most likely, the answer is “few”.

App developers should not assume that file metadata is protected. In particular, do not generate internal storage filenames based on private identifiers. Arne Swinnen’s blog post points out that both Instagram and Facebook do this, and particularly in the case of Instagram, it is possible for a third-party app to find out the Instagram user ID through brute-force techniques.

Sep 21, 2016

Multi-Window, Like It or Not, Again

About a week ago, I warned you that your activities might go into multi-window mode even if you opt out. That post was focused on Android apps enabling the capability for power users.

I failed to mention — because I failed to notice :-( — that there is a “Force activities to be resizable” setting in the “Developer options” area of the Settings app on Android 7.0. This knowledge is starting to make the rounds, not only of Android enthusiast blogs, but also more general-purpose media outlets.

The “seven taps” trick to enable “Developer options” helps avoid users accidentally messing with those options. However, as has occurred a few times in the past, plenty of users are willing to play around with “Developer options” to adjust settings to their liking, if they are given instructions to do so from some site that they like.

So, once again, do not assume that your opt-out of multi-window is going to hold up. For most users, it will. For power users — and even a few not-so-power users — your activity will be in multi-window mode, like it or not. The sooner you get your app to be friendly to multi-window, the fewer support issues you may have.

Sep 20, 2016

Reminder: Check Your Projects Before Importing Them

Building an Android project through Gradle — from Android Studio or from the command line — often results in arbitrary foreign code to run on your development machine. If that code contains malware, that malware has the run of your development machine and therefore has quite a bit of potential for damage.

So, before you go importing or building that really cool Android demo or library that you saw on GitHub, practice safe compiling, and examine the project first.

Replace the Gradle Wrapper

The Gradle Wrapper consists of:

  • A shell script (gradlew) and batch file (gradlew.bat)

  • A JAR (gradle/wrapper/gradle/gradle-wrapper.jar) used by the shell script and batch file

  • A properties file (gradle/wrapper/gradle/, containing, among other things, a distributionUrl property pointing to a copy of Gradle

When you run gradlew from the command line, if there is a .gradle/ directory in your project and it contains a copy of Gradle, gradlew delegates the work to it. Otherwise, it downloads the ZIP file pointed to by that distributionUrl, unZIPs it into .gradle/, then delegates to it.

This is fraught with security issues, as the random GitHub project could have:

  • Modified the shell script or batch file

  • Modified the JAR

  • Hacked a copy of Gradle, then have distributionUrl point to it

(and if the repo contains .gradle/, that too is a risk, though that usually that is blocked by .gitignore)

Worse, while Android Studio does not use the shell script, batch file, or JAR, it will blindly trust whatever copy of Gradle is pointed to by distributionUrl, download and unZIP it, and use it immediately to build your project. There is no attempt at tamper detection, nor is there any warning that you are downloading a copy of Gradle from some strange location rather than one of the standard distribution points. I even hacked a copy of Gradle and demonstrated to Google that Android Studio 2.2RC will happily build a project using the hacked version (to which Google responded that this “works as intended”).

The best solution is to replace all of that before attempting to use the project from the command line or attempting to import it into Android Studio. To do this:

  • Download and install a standalone copy of Gradle on your development machine

  • Examine the existing file and its distributionUrl to try to determine what version of Gradle the project wants

  • From the project root directory, run gradle wrapper --gradle-version ..., where the ... is the version of Gradle that you want (e.g., 2.14.1)

Of note, do not use gradlew for that third step — use the standalone copy of Gradle that you installed.

This will replace all of the Gradle Wrapper files with clean versions, including having distributionUrl point to an official copy of Gradle.

Examine Gradle Plugins and Compile-Time Annotation Processors

Both of these result in code that is downloaded and executed on your development machine. If you see plugins or processors in the various build.gradle files in the project, ask yourself: do you trust them? Do they seem to be common or popular ones, or are they something obscure?

Unlike the Gradle Wrapper scenario, I do not know if there is much that you can do to address this. It is up to you to determine how important that project is and whether it is worth the risks of using those plugins or processors.

There may be other security issues in the build process — these are the ones that have come to mind.

Sep 19, 2016

Older Posts