Mark L. Murphy's Blog, page 44

April 19, 2016

Exported Activities and Freeform Multi-Window Mode

I like to think that I���m pretty good about identifying the scary bits
of these developer previews. But, sometimes I miss things, ignoring
the ramifications of some warnings.



Ian Lake���s multi-window blog post
hammered home one such warning. He first quoted
the N Developer Preview docs:




If you launch an activity within a task stack, the activity replaces the activity on the screen, inheriting all of its multi-window properties. If you want to launch the new activity as a separate window in multi-window mode, you must launch it in a new task stack.




���and then he clarified it for people like me who missed the implication:




That means if you have an Activity that can be started by other apps, your activity will inherit the same multi-window properties as the calling Activity. This includes attributes such as minimal size.




So:





If you launch a third-party activity, and neither you nor that other
activity start a new task for that activity, that activity is part of
your task and works within the window for that task




If your exported activity is launched by third-party, and neither you
nor that other activity start a new task for you, you will be part
of that other task and you will reside in the window for that task





This does not seem so strange in practice when using split-screen mode
on mobile devices. There, we are used to other activities taking over
the whole screen, and saying that they now take over just our half of the
screen does not seem that unusual.



IMHO, it looks far more strange in freeform multi-window mode. This is
not officially released yet, but there are instructions floating around
the Internet for how to get an Android N emulator or rooted device to
support freeform multi-window mode.



For example, suppose that you need to have the user go into Settings to
configure something related to your app (e.g., make your app be a device
administrator). In a traditional desktop OS, if you needed to perform
an equivalent action ��� such as opening up the Windows Control Panel ���
the result would be a separate window for that third-party app. But, by
default, opening up Settings opens it up in the window used by your
app. If you are the one starting the third-party activity, you can
steer it into its own window using FLAG_ACTIVITY_LAUNCH_TO_ADJACENT
and FLAG_ACTIVITY_NEW_TASK��� but not everybody who launches a third-party
activity will think to do this. This is particularly true since,
at the moment, we do not have a way of determining if our app is in
a freeform multiwindow environment or not.



Worse, this behavior means that the controls offered by Android N
for your window ��� such as saying that your activity is not
resizeable ��� are not guaranteed for exported activities. If you
wind up in another app���s window, your activity will be sized for that
window, whether you like it or not.



If you have exported activities, ideally they support windows of all shapes
and sizes. If that is impractical for your particular activity, you will
need to decide what to do: change your UI/UX to accommodate windows of
varying sizes, try to use task-related manifest attributes to ensure
that you get a fresh window that meets your criteria, or find worse hacks
that cajole Android into giving you a fresh window.



My sincere hope is that official freeform multi-window support is not
that far away, such as perhaps around the time of Google I|O. I am hesitant
to place a lot of stock in what I am seeing in the hacked-in freeform
multi-window stuff on an Android N emulator. Freeform multi-window ���
a.k.a., ���Android on the desktop��� ��� bodes to be the biggest UI/UX
change in Android since the advent of the tablet. Even if Android does
an admirable job of covering most of the behavior without code changes,
we need time to work out patterns for edge cases, such as exported activities.



In the meantime, pay close attention to when Google announces official
freeform multi-window support, then budget the time necessary to ensure
that your users will get a quality experience in that mode.

 •  0 comments  •  flag
Share on Twitter
Published on April 19, 2016 05:00

April 13, 2016

Random Musings on the N Developer Preview 2

Each time Google releases a new developer preview, I try to
talk about the changes that Google isn���t talking about.



N Developer Preview 2 is an incremental change over N Developer
Preview 1. The
announcement blog post
does not mention all that much, spending the most screen space talking
about emoji. However, despite that, there are things that you really
should know about NDP2 compared to the previous NDP1, beyond what is
mentioned there. And, yes, beyond emoji.



Regressions��� Compared to Production Android

Google changed
the ���Behavior Changes��� page
without pointing out what
the actual changes were in NDP2 compared to NDP1. Of note:





Google admitted that the file: Uri scheme is defunct, as
we discovered the hard way in NDP1




In the same section of the docs,
Google now points out that MODE_WORLD_READABLE and MODE_WORLD_WRITEABLE,
beyond merely being deprecated, will crash with a SecurityException,
and that attempts to access COLUMN_LOCAL_FILENAME from
DownloadManager will also result in a SecurityException.




The StrictMode configuration for checking for network I/O on the
main application thread must have been focused on HTTP APIs or something.
Regardless, apparently you could open and write to a Socket
directly without triggering the dreaded NetworkOnMainThreadException.
This has been tightened up. Apps that had skated by with UI-thread
network I/O due to this hole now need to be patched.





Regresssions��� Compared to NDP1

Some symbols that you used in your NDP1 tests may have been revised
in NDP2, so be compared for some compilation errors.



For example, a number of things related to multi-window support
changed:





android:minimumSize now split into android:minimumWidth
and android:minimumHeight




inMultiWindow() and inPictureInPicture() were renamed
isInMultiWindowMode() and isInPictureInPictureMode()




Mode was also added in other related spots (e.g.,
onMultiWindowChanged() is now onMultiWindowModeChanged())





Minor Bits of Goodness

While I tend to focus on the problem areas, there are some less-known
good things that arose in NDP2.





Apparently, onSaveInstanceState() and various other methods that
involved IPC, if they resulted in a TransactionTooLargeException
(e.g., the state Bundle exceeding 1MB), would fail fairly quietly.
Now, such exceptions will be wrapped in some form of RuntimeException.
This should not result in new problems, but it may result in new
exceptions. While that may cause angst, the exception details will help
you clean up your code, since it was not working correctly previously
anyway.




Debug.startMethodTracing(), IIRC, used to write its output to the
root of external storage. Now, it will write to getExternalFilesDir()
or someplace around there. In a nutshell, you will not need
WRITE_EXTERNAL_STORAGE just to capture method traces.




PowerManager now has a SUSTAINED_PERFORMANCE_WAKE_LOCK, described
as ���used by Gaming and VR applications to ensure the device provides will
provide consistent performance over a large amount of time���. It is unclear
exactly what the behavior of this will be.




Long-time Android developers will remember that Activity used to
support onRetainNonConfigurationInstance() and
getLastNonConfigurationInstance(). These were deprecated back in API
Level 11, replaced by retained fragments. For some reason, they have
been un-deprecated (de-deprecated? dis-deprecated? anti-deprecated?!?)
in NDP2.




I reported in
the NDP1 ���random musings��� post
that Activity had a new onProvideKeyboardShortcuts() method, suggesting
a greater emphasis on physical keyboards. That was removed in NDP2, with
no obvious replacement. If it was removed because I pointed it out, I
wish to apologize to onProvideKeyboardShortcuts() and its next of kin.




There is a whole new android.os.health package, described as:






Applications running in the background are responsible for a significant amount of battery usage on a typical android device. There are several things that applications can do in order to reduce their impact��� This package provides more insight into what is going on behind the scenes when an application is running.




The API seems convoluted, at least on first glance, and it is largely
undocumented at this point. But, it appears
that we can access things like the number of times our _WAKEUP alarms
were invoked, how many times our services were started, how many ANRs
we generated, how much CPU time we have used, and so forth.



Bugs

Some of the bugs that I filed against NDP1 were fixed. Of note,
it appears that the multi-window minimal-size stuff works better
and the network security configuration is no longer sensitive to whitespace.



However, some bugs that I filed are still outstanding, such as
this RemoteInput documentation gap.
Plus, all three of my TileService bugs still seem to be outstanding:




https://code.google.com/p/android/issues/detail?id=205147
https://code.google.com/p/android/issues/detail?id=205154
https://code.google.com/p/android/issues/detail?id=205155


One bug is partially fixed, and it���s an interesting one. For many years,
the documentation has claimed that you can use a content: Uri to install an app.
This does not work on production versions of Android
and did not work on NDP1,
as there was simply no activity that could handle installing with
a content: Uri. On NDP2, the activity now exists. It doesn't work, at
least in my tests, and so once I have a fresh up-to-date sample, I will
be filing a fresh bug report to match. If you are implementing some
sort of app installer, or a self-upgrading app, having content: support
is very useful for security, which is why it was frustrating that Google
ignored this for years.





I am sure that many more things changed in NDP2 than I caught in the
past couple of hours. And most of what
I pointed out in NDP1
stil holds true.

 •  0 comments  •  flag
Share on Twitter
Published on April 13, 2016 13:02

April 11, 2016

AndGlobe: Yet Another Call For More Sites

I maintain a list of Android developer support sites
called AndGlobe. The
particular emphasis is on sites that are not in
English.



With some ~1.4 billion Android users around the world,
it is ridiculous to assume that English-language
developer support resources are adequate for the task.
Software development today requires too much English
knowledge as-is. Forcing people to have to resort to English
to ask Android development questions is unfortunate.
That is why I have AndGlobe: to try to help publicize
sites that can help others in all sorts of languages,
not just English.



If you operate, or know of, a site for asking
Android development questions and answers, that is not
listed on the AndGlobe site,
please let me know,
or follow the instructions on the GitHub repo
to contribute new sites that way. Conversely, if you know
that one of the sites on AndGlobe is no longer serving
a developer question-and-answer role, let me know. Note
that I am looking for sites with durable and searchable
results, so Slack channels and other chats do not count.



And, of course, please link to or otherwise promote
the AndGlobe site, so Android
developers know the wider range of Q&A sites that they
can use for getting their questions answered.



Thanks!

 •  0 comments  •  flag
Share on Twitter
Published on April 11, 2016 05:25

April 8, 2016

Why Can't I Edit My Manifest In Android Studio?

While working on an Android app, you go to run your project, and bam,
you get a build error related to something in your manifest. You already
closed that tab in Android Studio, so you double-click on the error,
which opens an editor on a manifest, pointing out the offending line.
You make the fix. Part of you wonders why Android Studio is showing
all sorts of legitimate stuff in the manifest as errors, but, hey,
it���s Android Studio ��� it acts oddly from time to time.



You go to run your project, and bam, you get a build error related
to something in your manifest. It turns out that it is the problem
you just fixed. So, you double-click on the error, and you notice
that your fix from a moment ago went away.



At this point, there are two possibilities:





You have found a glitch in the Matrix.




You are using Android Studio, at least through v2.0.0, and you
are encountering this bug
that I filed a report on 15 months ago.





What is happening is that double-clicking the error is opening up a tab
on a manifest. It is the wrong manifest. Rather than the
AndroidManifest.xml file from somewhere in src/, it is a generated
manifest from somewhere in build/. This generated manifest blends in
not only your module���s manifest, but entries from the manifests of
modules and other dependencies (such as
their <uses-permission> elements),
your module���s build.gradle file, and so on. Changes you make here will
be obliterated on your next build.



When editing a manifest, make sure that it is the right manifest.

 •  0 comments  •  flag
Share on Twitter
Published on April 08, 2016 06:11

April 5, 2016

PSA: Validate Your ACTION_SEND Inputs

Dominik Sch��rmann and Lars Wolf, in an excellent
blog post and
pre-pub paper,
points out a security flaw in many activities that have an ACTION_SEND
<intent-filter>.



Many ACTION_SEND implementations accept EXTRA_STREAM as input.
That is supposed to point to Uri representing a stream of stuff to be
sent somewhere. Email apps might send it as an attachment, for example.
So, you fire up a ContentResolver, call openInputStream() to get
at the content backed by that Uri (because
that���s how real developers do it),
and then do something with that content. You might not even really care
what the content is��� until that content is something from your own app. Like, say, your
user account database.



The problem outlined in Mr. Sch��rmann���s post and paper is that a malicious
party could provide you with a file: Uri
to your own internal storage.
While the third-party app cannot access your internal storage, you can.
So, in the case of an email app, the attacker asks you to email one of
your app���s own files to the attacker���s email address. The user may be
involved in this (e.g., having to actually click something to send
the email), but with
a bit of phishing or social engineering,
that problem can
be handled, at least some of the time. After all, courtesy of the intent:
scheme, some Web browsers and the like will allow a simple link click to trigger
the evil ACTION_SEND request.



To help with this, cketti (of K-9 Mail fame) wrote
a SafeContentResolver
that has its own openInputStream() method. However, this one will
fail if the Uri points to a file that your app owns. If you use this
instead of the openInputStream() on ContentResolver, your ACTION_SEND
implementation will be safer from this attack.



You might also think that this problem will fade away in the coming years. After
all, the Grim Reaper has a close eye on the file: scheme,
and so in the fullness of time, file: Uri values will be few and
far between.



Alas, the same problem can occur if the attacker sends you a content:
Uri to your own ContentProvider, such as a FileProvider. Even though
the provider may not be exported, your app has full access to its
own providers, just as your app has full access to its own internal storage.
I am working on updates to my StreamProvider,
and I���ll try to add some stuff in that will make this attack more difficult
to pull off.



More generally, if you accept input from outside parties, validate it.
Have rules for what sorts of Uri values you will and will not accept
for things like EXTRA_STREAM,
and provide runtime checks to confirm that the values you receive follow
the rules.

 •  0 comments  •  flag
Share on Twitter
Published on April 05, 2016 15:35

March 29, 2016

Beware the Bezel Swipe

In a tweet from a couple of weeks ago,
Cyril Mottier points out a problem with multi-window mode on Android N:
bezel (or edge) swipes.



In split-screen mode, in landscape, a bezel swipe from the edge where
the divider is between screens will be troublesome. Users may be aiming
for the bezel swipe and wind up grabbing and dragging the divider to
resize the two panes.



While I have yet to play with the freeform multi-window feature, I would
imagine that there will be similar problems there, particularly if users
are working with mice instead of fingers. Users might accidentally
wind up moving or resizing a window, rather than doing whatever your
edge swipe was supposed to do.



Frankly, bezel swipes have always made me nervous. Device manufacturers,
from Samsung to BlackBerry, have used bezel swipes for their own purposes,
conflicting with what apps might do. Apps themselves may overload
horizontal swiping gestures as well: does a swipe in from the left edge
open a navigation drawer, switch to a new page in a ViewPager, or
pan the content in the current page?



With multi-window, we are entering a world where the edges of the window
are not the edges of the device screen, increasing the chances that the
user will accidentally do the wrong thing for touch events near those
edges.



Make sure that anything in your app that depends upon an edge or bezel
swipe can be accomplished in some other way, such as the ���hamburger��� icon
for a navigation drawer. Then, consider disabling the bezel swipe option,
at least when you are running in multi-window mode.



Beyond that, my own personal ���style guide��� says that horizontal swipe
gestures should be consistent within a visually distinct area. So,
for example, a full-screen map inside a ViewPager in an activity with
a navigation drawer would violate this, as an edge swipe might trigger
three different things (pan the map, change the page, open the drawer).
Adding some margin around the map, so the ���change the page��� touch zone
lies outside the map boundaries, can help distinguish those roles for
horizontal swipes.

 •  0 comments  •  flag
Share on Twitter
Published on March 29, 2016 06:23

March 28, 2016

Upcoming Android Presentations

I am scheduled to deliver several presentations in the coming months.



First up, this Wednesday, I will be traveling to Philadelphia to
deliver a presentation at Android Alliance Philadelphia
about development anti-patterns. With luck, while in Philly, I
will not be attacked by wildcats.



On April 20, I will be appearing by remote at
Denver Droids��� meetup,
discussing doing periodic work in Android.



In May, I am scheduled to deliver a presentation that has not been
announced yet, so I cannot tell you where or when it is. However, if
experience is any guide,
if I can make it there, I���ll make it anywhere.



In August, I will be returning to Boston for AnDevCon after a one-year
hiatus, talking about how to secure the network access in your Android app.



I hope to see you there!

 •  0 comments  •  flag
Share on Twitter
Published on March 28, 2016 04:51

March 25, 2016

Watch Out For OpenJDK Differences on Android N

Android N is shipping with its java.* and javax.* classes
derived from the OpenJDK, rather than from Apache Harmony. Many of
the Harmony classes were modified in Android since Android 1.0, and
the JDK itself has gone through a couple of major releases. So,
while there are large test batteries designed to confirm that everything
is compatible, some changes in behavior are likely to slip through
the cracks.



For example, eagle-eyed developers have noted that
java.io.File path normalization has changed
and that
java.text.DecimalFormat has changed.
I have reproduced both of their test results and can confirm the
differences.



It is entirely possible that these will be altered to be compatible with
past versions of Android before Android N ships in final form. It is
theoretically possible that these are the only two such differences, but
that seems unlikely.



Hence, more so than with past developer previews, it is key for you to
be testing your code early and thoroughly, to see whether you trip over
similar sorts of JDK class differences. At minimum, you will have time
to find a workaround. Even better, file an issue, and see if the
incompatibilities can get fixed.

 •  0 comments  •  flag
Share on Twitter
Published on March 25, 2016 06:15

March 24, 2016

SYSTEM_ALERT_WINDOW: Now More Hidden Than Ever

SYSTEM_ALERT_WINDOW has been a long-standing concern of mine, due to
its relationship to tapjacking attacks. And, due to some changes that
Google has made, now apps can get that permission, without user knowledge.



SYSTEM_ALERT_WINDOW is the permission that allows apps to draw over top
of other apps from the background. It���s what powers things like
the Facebook ���chatheads���, for example.



For a long time, SYSTEM_ALERT_WINDOW was dangerous. The user would
be informed, at install time, that the app was requesting the ability to
draw over other apps. In Android 6.0, it was upgraded to
signature|system|appop, requiring the user to go into Settings and
manually grant this right to apps requesting it, if your targetSdkVersion
is 23 or higher ��� you could not
request it even using the new runtime permission system.



However, a few weeks ago, this Stack Overflow question appeared,
pointing out that apps like Evernote were getting SYSTEM_ALERT_WINDOW
without telling the user.



Mattia Maestrini responded
that Android 6.0.1 further modified SYSTEM_ALERT_WINDOW. Apps
with targetSdkVersion of 23 or higher that request SYSTEM_ALERT_WINDOW
get it without telling the user��� if the user installs
the app from the Play Store. If the user installs the app by other
means, the previous Android 6.0 rules apply, and the user has to
manually grant the right to draw over other apps.



Users of Android 6.0.1+ device should go into
Settings > Apps > (gear icon) > ���Draw over other apps��� and see what
all shows up. The answer may surprise you. You may want to revoke
that right for some apps.



I tossed together a ���SAW Monitor��� sample app
that watches app installs and upgrades and raises a Notification
if the app in question has requested SYSTEM_ALERT_WINDOW and is
not on a whitelist. I���ll keep that app on my
own device, so that at least I find out when some app decides to
obtain this permission behind my back, with Google���s approval.
Of course, where possible, I get my apps from
F-Droid, rather than the
Play Store.

 •  0 comments  •  flag
Share on Twitter
Published on March 24, 2016 05:09

March 23, 2016

Oops! Re-Download Version 7.2 APK/EPUB/MOBI

Due to a production mistake on my part, the APK, EPUB, and MOBI downloads
for Version 7.2 (released this past Monday) had Version 7.1 content.
The files have been updated for all subscribers, so a fresh download will
give you the proper material. The PDF edition was fine.



I sincerely apologize for this screwup, and I will take steps to prevent
it from happening again.

 •  0 comments  •  flag
Share on Twitter
Published on March 23, 2016 07:13