The CommonsBlog


Getting Ready for ChromeOS

A bit over two weeks ago, I delivered an “Android on the Desktop” presentation to the NYC Android Developer Meetup.

A couple of weeks before that, I blogged about the signs that Android apps were coming to Chrome OS.

A year prior to that, I blogged about the new option for distributing Android apps to Chrome OS.

So, when last week’s announcement on this came out, while I don’t mean to say “I told you so”… but I told you so.

Admittedly, it is not happening quite as I expected. Reading between the lines of the announcements, the Ars Technica article, and the VentureBeat article, it appears that Google jettisoned the ARC approach. Instead, it seems as though our apps are going to be running in a beefed-up edition of the Android SDK emulator, one with some platform-specific hooks (e.g., integrated window management with Chrome OS-native windows). And they feel confident enough about this approach that your app will, indeed, wind up shipping to Chrome OS unless you take steps to block it.

So, now what? In particular, if you want to support Chrome OS, what should you do?

First, try to get your hands on compatible hardware. At least here in the US, two of the three near-term test devices are relatively inexpensive, in the $200-300 range. These devices should get the Android app support in June. Note that all three have touchscreens.

You will then want to review your <uses-feature> elements, along with any implied <uses-feature> elements coming from your <uses-permission> elements. Ideally, you have few of these, and those that you have are set for android:required="false". The more that you require, the less likely it is that your app will work on Chrome OS. In particular, pay attention to hardware features that may not be on Chrome OS devices, remembering that not all Chrome OS devices are notebook equivalents. Some are desktop replacements (e.g., Chromebox). So, while many Chrome OS devices will have a camera, some will not. Also, since your app cannot supply Chrome OS with an input method editor, app widgets, live wallpaper, or a replacement home screen, their corresponding <uses-feature> elements should be set to not be required.

Next, confirm whether your app can work without a touchscreen. For example, you might hook up a Bluetooth keyboard and mouse to a test tablet, then try using your app. If you determine that your app can be used successfully without a touchscreen, add the following to your manifest, as a child element of the root <manifest> element:

<uses-feature android:name="android.hardware.touchscreen" required="false" />

This will allow your app to be used on Chrome OS devices that lack a touchscreen, when such devices start getting Android apps later this year.

Once your test Chromebook gets Android app capability, look for instructions for how to test your app on it. Ideally, it will work with our development tools the same way that devices and emulators do, but that is not assured. Note that this is supposed to arrive in M53 on the developer channel to these devices, so you may need to make some changes to your test Chromebook to pull in from the dev channel instead of the standard public channel.

If you decide that you do not want to deal with Chrome OS at all, you will need to decide how you want to block such distribution. Presumably, you will be able to do this via the Play Developer Console, but it might not be that easy, if you have to block distribution on a device-by-device basis. You might cheat and add in a <uses-feature> element that should be supported by mobile devices but would not be supported by Chrome OS (e.g., <uses-feature android:name="android.software.app_widget" />), even if your app does not actually implement such a feature, just to tide you over until you add Chrome OS support later.

And you will want to add Chrome OS support later. Chrome OS is interesting, but at its estimated install base, it is roughly equivalent to Froyo (0.1% of Android devices). On its own, therefore, it is not worth a lot of effort. However, it seems rather unlikely that Google will stop here. In the next couple of years, I expect Google to replicate this same approach on Windows, Mac, and Linux. That audience is substantially larger and therefore more compelling. Use Chrome OS as an extended test run for eventually supporting classic desktop operating systems in the future.

You can read more about all of this:

I will be updating my book to reflect these changes as they roll out over the next several months, so subscribers can keep up with how to support Chrome OS.

May 25, 2016


Random Musings on the N Developer Preview 3

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

N Developer Preview 3 (NDP3) represents another incremental change over N Developer Previews 1 and 2. Google did not bother with an announcement blog post, AFAICT, though there are some release notes.

This post outlines some things that have caught my eye in NDP3.

Regressions and Changes… Compared to Production Android

View offers post() and postDelayed() methods, as does Handler. On the whole, I have been steering developers to use the ones on View, as you pretty much always have a widget available, so there is little sense in creating a Handler instance just for post() and postDelayed(). However, NDP3 makes a slight change here:

If an app posts Runnable tasks to a View, and the View is not attached to a window, the system queues the Runnable task with the View; the Runnable task does not execute until the View is attached to a window.

For a lot of uses of post(), this will not be a problem. postDelayed() might get more interesting, particularly if you are using a “postDelayed() loop” (postDelayed() invoking a Runnable that calls postDelayed() to schedule itself again). That loop will only work so long as the View you are using is attached to a Window. If you are concerned about this, beyond testing your existing implementation, you might consider switching to a Handler instance for postDelayed().

Also:

  • The week number feature on CalendarView is now deprecated
  • The embedded CalendarView in DatePicker is now deprecated and is “not supported by Material-style calendar mode”.

Regresssions and Changes… Compared to NDP2

The ShortcutsManager added in NDP2 still exists in NDP3, but the release notes indicate that it will be retired in a future developer preview. I would not recommend investing further time in it.

Other Stuff in NDP3

There are other curiosities tucked into the API differences report, above and beyond the items called out in the release notes:

  • There is now an ACTION_SHOW_APP_INFO Intent action, to “launch an activity showing the app information”. This appears to be tied to the Play Store and other app installation channels, suggesting that you can use this to display information about apps that are not yet installed.

  • If you create an ACTION_CHOOSER Intent directly (rather than via the createChooser() helper method), you can add EXTRA_EXCLUDE_COMPONENTS to list particular components that should be excluded from the list of choices. This is very handy for cases where you have your own activity that handles some implicit Intent, but you specifically want to open some Uri in any other activity handling that type of content. For example, perhaps you are having difficulty rendering the content, and you want to allow the user to try viewing that content in a third-party app.

  • There is a new MessagingStyle for Notification, which is a “helper class for generating large-format notifications that include multiple back-and-forth messages of varying types between any number of people”. I have not tried this yet to determine whether it is something that might be specific to certain form factors (e.g., Wear) or whether it is available across the board.

  • Some options that we have on JobScheduler, such as “only while charging”, and “only while idle”, are now available on DownloadManager via methods on DownloadManager.Request.

  • stopForeground() is being migrated from taking a boolean (whether or not to remove the Notification) to an int, with STOP_FOREGROUND_REMOVE and STOP_FOREGROUND_DETACH options.

  • NDP1 added addTriggerContentUri() to JobScheduler, to allow us to monitor a ContentProvider for changes without having an always-running service. NDP3 adds setTriggerContentUpdateDelay(), to postpone running the job until the content has stabilized, so jobs do not run multiple times for a series of minor changes to the content. setTriggerContextMaxDelay() sets a cap on that delay. Between those two, you can have a modicum of control over how frequently your content-related jobs are invoked.

  • A new android.view.PixelCopy method allows you to asynchronously(?) copy the contents of a Surface to a Bitmap, with a callback when that work is completed.

Bugs in NDP3

Some of the bugs that I filed against NDP1 and NDP2 were fixed, particularly ones related to quick-settings tiles.

However, some bugs that I filed are still outstanding, such as:

I also have not yet confirmed whether the FLAG_LAUNCH_ADJACENT bug that I filed has been fixed… as I cannot get FLAG_LAUNCH_ADJACENT to work at all anymore. I am still investigating this.


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

May 24, 2016


SAFFAQ: The Storage Access Framework FAQ

Given the impending demise of file: Uri values, you have two primary means of getting access to documents that your app wishes to use:

  • Have other apps push content: Uri values to you, via activities in your app with <intent-filter> elements for common operations, such as ACTION_VIEW or ACTION_EDIT

  • You pull content: Uri values into your app – akin to using “file open” or “file save” dialogs – via the Storage Access Framework

With that in mind, here are some fictionally-asked questions about using the Storage Access Framework.

How Do I Ask the User for a Document?

On API Level 19+ devices, create an Intent for ACTION_OPEN_DOCUMENT, with a MIME type indicating what sort of document you want, and CATEGORY_OPENABLE as a category. Start that with startActivityForResult(). If you get RESULT_OK in onActivityResult(), the Uri in the delivered Intent will point to the document in question. Then, you can use ContentResolver, DocumentFile, and kin to work with the document, as I outlined in an earlier blog post.

That’s It?

That’s it.

Why Do People Seem All Angst-y About This, Then?

Well, there are issues.

First is the API Level 19+ requirement. Some developers are already up to a minSdkVersion of 19 or higher, but plenty of others are not. The fallback mechanism is ACTION_GET_CONTENT and a MIME type.

Google, in its infinite wisdom, thinks that the UI presented by the Storage Access Framework should be optimized for things like Google Drive. As a result, the user has to know to do a bunch of clicks to actually get to where their files are (what we call external storage, what the user calls internal storage).

If you need long-term access to the document, beyond just your current process, you need to use takePersistableUriPermission() to try to get that long-term access. However, you may not get it, because it may not be offered. At the same time, though, you may lose access to the document for other reasons (e.g., the user deleted it), so this should not be a huge impediment.

What If I Want a Wide Range of Possible MIME Types?

Add EXTRA_MIME_TYPES on the Intent, as a String[] of concrete or wildcard MIME types.

What If I Want a Bunch of Documents at Once?

Add EXTRA_ALLOW_MULTIPLE to the ACTION_OPEN_DOCUMENT Intent, with a value of true. Now, instead of getting a single Uri back, you may get back several Uri values. You access these through the ClipData object you get by calling getClipData() on the Intent delivered to onActivityResult(). getItemCount() on the ClipData tells you how many documents the user opened, and getItemAt(i).getUri() (for a value of i) gives you the Uri for that position i.

What If I Want to Create a Document?

Use ACTION_CREATE_DOCUMENT instead of ACTION_OPEN_DOCUMENT, and make sure that you use a concrete MIME type (e.g., text/plain, not text/*). Otherwise, it works the same as with ACTION_OPEN_DOCUMENT: you get a Uri back representing the newly-created document, and you can use ContentResolver to get an OutputStream onto which you can write your data.

What If I Want to Create a Bunch of Documents?

If the “bunch of documents” can (or should) reside in one directory, use ACTION_OPEN_DOCUMENT_TREE on API Level 21+ devices. This amounts to a “directory picker”. You get a Uri back representing a tree of documents, and you can use methods on DocumentFile to create new documents in that directory.

What If I Want to Create a Bunch of Documents on Older Devices?

Ummm… call ACTION_CREATE_DOCUMENT several times, on API Level 19+ devices.

What If I Want to Create a Bunch of Documents on Seriously Old Devices?

There is no great way that I can think of to accomplish this through standard Intents and such.

How Do I Delete a Document?

Call delete() on a DocumentFile for the document. That, in turn, calls the static deleteDocument() method on DocumentsContract.

How Do I Delete a Directory?

Ummm… try delete() on the DocumentFile. I do not know if this is supported, but it is worth a shot.

Why Do We Have to BLEEEEEEEEEEEEEEEP With All This?

Partly, the reason is security. Privacy advocates have been complaining for years about how apps can run around and mess with everything on external storage, causing various issues. For example, apps with read access to external storage can examine photos for geotags; coupled with the photo’s timestamp, you now know where the user was at the time that the photo was taken. Hence, over the years, Google has been progressively tightening down Android with respect to file access.

Partly, the reason is that the documents the user wants may not necessarily be on external storage, and so developers who fixate on local files will harm the broader Android ecosystem.

For example, if Android on Chrome OS continues to expand, external storage for ARC apps is not the Chromebook’s hard drive. Rather, it is more like the external storage for an emulator, accessible only by apps and through development tools. Worse, the current ARC environment has each app walled off in its own AVD-style container, so one app cannot access another app’s external storage. Presumably, the vision is for apps to be using the Storage Access Framework, where the ARC environment can bridge between the Android app and the Chrome OS file areas that Chromebook users are used to working with.

Similarly, if we start seeing Android more in desktop-style settings, desktops in an organization often rely upon a file server, such as a Windows SMB server. Android can offer access to that via the Storage Access Framework, as an SMB server is not significantly different than is Google Drive from the standpoint of Android. However, once again, this requires developers to start thinking in terms of documents identified by content: Uri values, more so than thinking purely about local files.

May 03, 2016


The Busy Coder's Guide to Android Development Version 7.3 Released

Subscribers now have access to the latest release of The Busy Coder’s Guide to Android Development, known as Version 7.3, in all formats. Just log into your Warescription page and download away, or set up an account and subscribe!

In terms of content, this update:

  • Updated the book for Android Studio 2.1, including a much larger chapter on using the emulator, covering many of the new emulator features

  • Expanded the appendix on the N Developer Preview, updating it to the N Developer Preview 2 and adding material on TileService and network security configuration

  • Expanded the coverage of consuming documents through the Storage Access Framework, including covering ACTION_OPEN_DOCUMENT_TREE and Android N’s StorageVolume option

  • Expanded coverage of Android N multi-window, both in the Android N appendix and in the Storage Access Framework chapter, the latter adding a multi-tab/multi-window text editor example

  • Merged the JUnit and JUnit4 chapters into one, with related fixes to the other major chapters on testing and updates based on Android Studio 2.1

  • Updated coverage of Notification to improve the material on progress notifications and custom views, coverage of Android N’s quick-reply working on the lockscreen, and the use of FileProvider over file: Uri values

  • Added an improved ACTION_IMAGE_CAPTURE sample to the chapter on working with the camera, using a FileProvider instead of File objects, to deal with Android N

  • Expanded the coverage of preferences to include MultiSelectListPreferences and ListPreferences with dynamic contents (generated in Java on the fly, not hard-coded as resources)

  • Added more material on StreamProvider, as an alternative to FileProvider

  • Retired the tapjacking chapter, migrating the relevant portions of that material to the chapter on miscellaneous security techniques

  • Deleted obsolete chapters on ActionBarSherlock and non-Android Wear wrist wearables

  • Removed material on ViewPagerIndicator

The APK edition of the book has a few more appinars in the Community Theater, including:

  • Doing Periodic Work
  • Consuming Content from a Uri
  • Notification Basics
  • Lockscreen Notifications

Version 7.4 is tentatively slated for early June and will include material on whatever fun stuff Google will announce at Google I|O later this month.

May 02, 2016


Your App May Be Getting on the ARC

Ars Technica is reporting that it appears that a recent Chrome OS update has the underpinnings of making the Play Store and its contents available to users.

It was just over a year ago that I blogged about the App Runtime for Chrome, or ARC. This was nascent technology from Google that would allow you to package your app as a Chrome extension and run it on Chrome OS (and, for testing purposes, on Chrome for traditional desktop operating systems). When I spent some more time with it earlier this year, to see what Google may have improved with ARC, my sense was that it was merely an experiment, nothing more.

Ars’ reporting turns that on its head. The language that they and various Redditors uncovered suggests that a substantial chunk of the Play Store catalog will be available to Chrome OS users. There is absolutely no chance that the developers of “over a million apps and games on Google Play” have manually tested their wares on ARC. This would indicate that Google is taking an opt-out approach: your app will be available on Chrome OS unless you do something (in the app or in the Play Developer Console) to block it.

The ARC environment is a strange world for an Android app. Your app runs in an SDK-style emulator, but where the AVD contains no other apps, including few of the standard system apps that you see when you create an AVD through the AVD Manager. Each app is in its own silo, so even if the Chrome OS user has three apps installed, each app is isolated from the others.

Now, the details of how ARC works may shift as part of this rollout, and I think there is a decent chance that we will learn more at Google I|O in a few weeks.

What does this mean for you, as an Android app developer?

  • Pay close attention to discussion about ARC in and around Google I|O. If it looks like what Ars is describing is coming true, pay very close attention to whether your app will automatically be distributed to Chrome OS devices. If it will be, either nab a Chromebook and test your app, or follow whatever instructions they provide to block your app from Chrome OS until you are in position to do such testing. FWIW, my book has a chapter on ARC and what it means for your app.

  • Pay further attention to where Android apps can run with ARC. If the answer is “just” Chrome OS, that audience probably is on par, roughly, with the number of people using Android 2.x today. If, on the other hand, Google makes this available to all Chrome users, that would be a massive audience. My guess is that they will do this in two stages, with Chrome OS first, followed by desktop Chrome support in 2017 or beyond, but that is just a guess. You may not care enough about Chrome OS users to spend much time tuning your app for ARC, but you really should care about all Chrome users.

  • This would seem to be independent of Android N’s multi-window feature. Freeform multi-window seems specifically aimed at an Android-based environment that has several windows. Perhaps I am misinterpreting what we are being told. However, if I am correct, it would seem that Google may be preparing a multi-prong dive into competing with traditional desktop operating systems, with a more desktop-y Android to go along with an expanded Chrome OS.

  • An opt-out ARC, along with opt-out multiwindow support (to the extent that opting-out even works), suggests that Google is tired of the modest developer adoption of Android TV, Android Wear, and Android Auto. Where they think that they can get away with it, Google may aim to make the Play Store catalog available in toto to new environments, much as they did with tablets back in 2011.

I cannot say that I find Ars’ reporting to be surprising, considering that my book’s chapter on desktop Android suggested that an expanded ARC would be one of Google’s moves. However, this puts added emphasis on paying close attention to what is announced at Google I|O, to any updated developer previews or support libraries released at I|O, and so on.

Apr 25, 2016


Older Posts