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
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
onPause() for setting up and tearing down foreground work, we might
now switch to
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
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
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
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
setKeepScreenOn() to hold a full wakelock while they are visible…
well, that wakelock stays in force, and the device continues draining the
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
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
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
we are aiming to prevent other apps from reading or writing our files.
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
—Sep 21, 2016
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
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
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 (
A JAR (
gradle/wrapper/gradle/gradle-wrapper.jar) used by the shell
script and batch file
A properties file (
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
directory in your project and it contains a copy of Gradle,
delegates the work to it. Otherwise, it downloads the ZIP file pointed
to by that
distributionUrl, unZIPs it into
.gradle/, then delegates
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
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
Examine the existing
gradle-wrapper.properties file and its
distributionUrl to try to determine what version of Gradle the project
From the project root directory, run
gradle wrapper --gradle-version ...,
... 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,
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
There may be other security issues in the build process — these are the
ones that have come to mind.
—Sep 19, 2016