Random Musings on Q Beta 4
Each time Google releases a new developer preview beta, I putter around
the API differences report
the high-level overviews,
and even the release blog post,
to see if there are things that developers should pay more attention to.
I try to emphasize mainstream features that any developer
might reasonably use, along with things that may not
get quite as much attention, because they are buried in the JavaDocs.
We are now up to Beta 4, so this extends upon my notes for
Beta 1,
Beta 2,
and Beta 3.
Q Beta 4 is supposed to have the final APIs. However, I
was surprised as to how much is different in Q Beta 4.
Hey, Can We Call It API Level 29 Now?
Yes, we can. We no longer have to dance around the API level. Build.VERSION_CODES.Q
has the proper value instead of the 10000 placeholder. And you are able to
publish apps with targetSdkVersion set to 29 if you so choose��� though you
may or may not be ready for that just yet.
So, What���s Up with Scoped Storage?
In a nutshell, it changed again, based on the description in the docs.
The sandboxes are gone. Instead, there is one unified external storage
location that all apps and the user sees. However, apps only see their
own files in external storage, in general. So, instead of scoped storage
being sandboxed, it is filtered instead.
From the user���s standpoint, this should be simpler. Now files that apps write
to external storage will be where they had been previously. This is really
important for legacy apps that are not being regularly updated and which might
never adapt to the Storage Access Framework. Yet, at the same time, apps should
still unable to manipulate other apps��� files through the filesystem, meaning that
users still get enhanced security.
Also, apps are still able to opt out of the filtered view, at least until next
year sometime, when targetSdkVersion 29 becomes required for the Play Store
and select other app distribution channels.
My biggest fear right now is that there have been so many changes over the past
three months that we are at risk of more bugs than we might otherwise have had.
Note that getExternalStorageDirectory() and getExternalStoragePublicDirectory()
on Environment
are now deprecated, to further steer developers towards using the Storage Access
Framework or MediaStore.
I will be ���kicking the tires��� on this stuff today and will write up more about
the current state of scoped storage tomorrow.
What Else Got Deprecated or Removed?
The biggest surprise ��� and a pleasant one ��� is that android:sharedUserId
is deprecated. Moreover, it is planned to be dropped entirely in some future
release. For device manufacturers, android:sharedUserId was a handy shortcut
for data sharing, but even there it really was not a particularly good practice.
For ordinary app developers, android:sharedUserId was a
footgun, one that I have been advising
against people using since the very beginning. Having an app suite is awesome,
but please use IPC for data sharing, not some sort of shared file that may or may
not be managed properly for simultaneous multi-process access.
DownloadManager deprecated some things, as a side effect of scoped storage:
addCompletedDownload()
allowScanningByMediaScanner() on DownloadManager.Request
setVisibleInDownloadsUi() on DownloadManager.Request
Items listed in the new MediaStore.Downloads collection will be what appears
in the Downloads UI now. So, if you have content that was not downloaded to the
Downloads/ directory by DownloadManager, and you want it to appear in the Downloads
UI, you need to write it to a Uri supplied by MediaStore.Downloads, I guess.
A bunch of fields from MediaStore.MediaColumns were removed, including ORIENTATION,
DURATION, and DATE_TAKEN. If your app has been querying on those columns, they
may no longer be available to you.
Also, MediaPlayer2 and related classes vanished without a trace.
They Didn���t Add Anything New, Did They?
Well, yes, they did, a lot more than I would expect at this late stage. Here are
a few things of note:
Activity now has onGetDirectActions() and onPerformDirectAction(). A
DirectAction is an opaque identifier of something that somebody can do with
or in the activity. The idea is that an activity can supply the available actions
in onGetDirectActions(), and a VoiceInteractor can let the user act upon
one. The chosen action then gets delivered to onPerformDirectAction(), for
the activity to go do something. Unfortunately, there isn���t a lot to go on
in terms of how all of this is supposed to work. Hopefully, more documentation
is forthcoming.
Intent now has getIdentifier() and setIdentifier(). The identifier
���is an arbitrary identity of the Intent to distinguish it from other Intents���.
My assumption is that this does not affect Intent routing and is basically a specific
���extra��� bit of data that gets passed along. It is unclear what the value of this
is over, well, extras.
Intent also adds CATEGORY_APP_FILES to identify file managers.
There are four new DisplayMetrics screen densities: 140, 180, 200, 220.
Those are the first new low-end densities we have had in years, and it is unclear
what hardware would have such screens. It���s possible this is tied to desktop mode,
if those are meant to be used for certain external displays. Regardless, most
developers will not need to worry about these, as Android will scale mdpi or
hdpi drawables for you. But, if you have other code that cares about these
DENSITY_ constants on DisplayMetrics, you have four more to deal with.
android:hasFragileUserData is a new manifest setting (I���m guessing on <application>).
���If true the user is prompted to keep the app���s data on uninstall���. This
seems ripe for abuse, but I can see where it might be useful for some apps.
What Was Renamed?
One common thing late in the beta sequence is to have classes and methods be renamed,
as somebody lost a fight in a code review or something. Of particular note:
isExternalStorageSandboxed() on Environment is now isExternalStorageLegacy()
ContentResolver.TypeInfo is now ContentResolver.MimeTypeInfo
They Must Be Done With Changes Now, Right?
Perhaps not.
There is still a reference to
RecoverableSecurityException being enabled in a future beta.
Certain types of I/O might throw that exception,
which contains a RemoteAction that you can use to bring up some UI to help
recover from that exception. In particular, if you do not have rights to modify
some media, you might get a RecoverableSecurityException, where the RemoteAction
would bring up UI to allow the user to grant you write access. It is unclear if
this might show up in a future Q beta, whether it already is in Beta 4 (without
the docs being changed), or what.
OK, So Where Do We Go From Here?
In theory, there should be few changes from here on out in terms of the API. There
may yet be bug fixes, which is good, as a bunch of the bugs that I filed are still
reproducible on Q Beta 4. But if you have been holding off testing your app with
Android Q, waiting for things to stabilize, you should not wait any longer. I
expect Android Q to ship in final form to end users in 2-4 months, and you will
want to make sure that your app will survive that upgrade.
As for me, I will update Elements of Android Q shortly to reflect some
of these changes and explore more dusty corners of this release, such as desktop
mode.


