The following is the first few sections of a chapter from The Busy Coder's Guide to Android Development, plus headings for the remaining major sections, to give you an idea about the content of the chapter.
If you have been diligent about reading this book (versus having
randomly jumped to this chapter), you will already have done a fair
number of things with
In this chapter, we continue looking at things the manifest offers you, starting with a discussion of controlling where your application gets installed on a device, and wrapping up with a bit of information about activity aliases.
Understanding this chapter requires that you have read the core chapters of this book.
On October 22, 2008, the HTC Dream was released, under the moniker of “T-Mobile G1”, as the first production Android device.
Complaints about the lack of available storage space for applications probably started on October 23rd.
The Dream, while a solid first Android device, offered only 70MB of on-board flash for application storage. This storage had to include:
It would not take long for a user to fill up 70MB of space, then have to start removing some applications to be able to try others.
Users and developers alike could not quite understand why the Dream had so little space compared to the available iPhone models, and they begged to at least allow applications to install to the SD card, where there would be more room. This, however, was not easy to implement in a secure fashion, and it took until Android 2.2 for the feature to become officially available.
If your app’s
android:minSdkVersion is 11 or higher, you can
probably ignore all of this. At that time, what the Android SDK
refers to as “internal storage” and “external storage” were moved to
be part of one filesystem partition, and so there is no artificial
division of space between the two.
But, if you are still supporting Android 2.2 and 2.3, you may wish to consider supporting having your app be installed to, or moved to, external storage.
Indicating to Android that your application can reside on the SD card is easy… and necessary, if you want the feature. If you do not tell Android this is allowed, Android will not install your application to the SD card, nor allow the user to move the application to the SD card.
All you need to do is add an
android:installLocation attribute to
<manifest> element of your
There are three possible values for this attribute:
internalOnly, the default, meaning that the application cannot be installed to the SD card
preferExternal, meaning the application would like to be installed on the SD card
auto, meaning the application can be installed in either location
If you use
preferExternal, then your application will be initially
installed on the SD card in most cases. Android reserves the right to
still install your application on internal storage in cases where
that makes too much sense, such as there not being an SD card
installed at the time.
If you use
auto, then Android will make the decision as to the
installation location, based on a variety of factors. In effect, this
preferExternal are functionally very similar
– all you are doing with
preferExternal is giving Android a
hint as to your desired installation destination.
Because Android decides where your application is initially
installed, and because the user has the option to move your
application between the SD card and on-board flash, you cannot assume
any given installation spot. The exception is if you choose
internalOnly, in which case Android will honor your request, at the
potential cost of not allowing the installation at all if there is no
more room in on-board flash.
For example, here is the manifest from the
profiled in another chapter, showing the use of
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.commonsware.android.sms.sender" android:installLocation="preferExternal" android:versionCode="1" android:versionName="1.0"> <uses-permission android:name="android.permission.READ_CONTACTS"/> <uses-permission android:name="android.permission.SEND_SMS"/> <uses-sdk android:minSdkVersion="7" android:targetSdkVersion="11"/> <supports-screens android:largeScreens="true" android:normalScreens="true" android:smallScreens="false"/> <application android:icon="@drawable/ic_launcher" android:label="@string/app_name"> <activity android:name="Sender" android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.MAIN"/> <category android:name="android.intent.category.LAUNCHER"/> </intent-filter> </activity> </application> </manifest>
Since this feature only became available in Android 2.2, to support
older versions of Android, just have your build tools target API
level 8 (e.g.,
compileSdkVersion of 8 or higher in
Android Studio users) while having your
in the manifest state the lowest Android version your application
supports overall. Older versions of Android will ignore the
android:installLocation attribute. So, for example, in the above
Sender application supports API level 4 and above
(Android 1.6 and newer), but still can use
android:installLocation="preferExternal", because the build tools
are targeting API level 8.
On newer devices, such as those running Android 4.2, the user will see nothing different. That is because internal and external storage share a common pool of space, and therefore there is no advantage in having your application installed to external storage.
However, on, say, Android 2.3, you will see a difference in behavior.
For an application that wound up on external storage, courtesy of your
auto, the user will have an option to
move it to the phone’s internal storage. This can be done by choosing
the application in the Manage Applications list in the Settings
application, then clicking the “Move to phone” button.
Conversely, if your application is installed in on-board flash, and it is movable to external storage, they will be given that option with a “Move to SD card” button.
Ideally, the pirate sees nothing at all.
One of the major concerns with installing applications to the SD card
is that the SD card is usually formatted FAT32 (
vfat), offering no
protection from prying eyes. The concern was that pirates could then
just pluck the APK file off external storage and distribute it, even for
paid apps from the Play Store.
Apparently, they solved this problem.
To quote the Android developer documentation:
The unique container in which your application is stored is encrypted with a randomly generated key that can be decrypted only by the device that originally installed it. Thus, an application installed on an SD card works for only one device.
Moreover, this “unique container” is not normally mounted when the
user mounts external storage on their host machine. The user mounts
/mnt/sdcard; the “unique container” is
So far, this has all seemed great for users and developers. Developers need to add a single attribute to the manifest, and Android 2.2+ users gain the flexibility of where the app gets stored.
Alas, there is a problem, and it is a big one: on Android 1.x and 2.x,
either the host PC or
the device can have access to the SD card, but not both. As a result,
if the user makes the SD card available to the host PC, by plugging
in the USB cable and mounting the SD card as a drive via a
Notification or other means, that SD card becomes unavailable for
So, what happens?
onDestroy(), and instance state saved via
AlarmManageralarms will be canceled, and so on.
The upshot: if your application is simply a collection of activities, otherwise not terribly connected to Android, the impact on your application is no different than if the user reboots the phone, kills your process via a so-called “task killer” application, etc. If, however, you are doing more than that, the impacts may be more dramatic.
Perhaps the most dramatic impact, from a user’s standpoint, will be if your application implements app widgets. If the user has your app widget on her home screen, that app widget will be removed when the SD card becomes unavailable to the phone. Worse, your app widget cannot be re-added to the home screen until the phone is rebooted (a limitation that hopefully will be lifted sometime after Android 2.2).
The user is warned about this happening, at least in general:
Figure 886: Warning when unmounting the SD card
Two broadcast Intents are sent out related to this:
ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE, when the SD card (and applications installed upon it) become unavailable
ACTION_EXTERNAL_APPLICATIONS_AVAILABLE, when the SD card and its applications return to normal
Note that the documentation is unclear as to whether your own
application, that had been on the SD card, can receive
ACTION_EXTERNAL_APPLICATIONS_AVAILABLE once the SD card is back in
Also note that all of these problems hold true for longer if the user physically removes the SD card from the device. If, for example, they replace the card with a different one — such as one with more space — your application will be largely lost. They will see a note in their applications list for your application, but the icon will indicate it is on external storage, and the only thing they can do is uninstall it:
Figure 887: The Manage Applications list, with an application shown from a removed SD card
Given the huge problem from the previous section, the question of whether or not your application should support external storage is far from clear.
As the Android developer documentation states:
Large games are more commonly the types of applications that should allow installation on external storage, because games don’t typically provide additional services when inactive. When external storage becomes unavailable and a game process is killed, there should be no visible effect when the storage becomes available again and the user restarts the game (assuming that the game properly saved its state during the normal Activity lifecycle).
Conversely, if your application implements any of the following features, it may be best to not support external storage:
But, as noted earlier, this is not even usually necessary on API Level 11+ devices. Hence, even if your app would otherwise qualify for being installed to external storage, you may not wish to bother. If few devices (Android 2.2 and Android 2.3) might need the capability, it may not be worth the extra testing burden.
When Android 3.0 did away with the required separate partitions for
internal storage and external storage, the
option fell out of use, as there was no particular value in having
the apps on external storage. For single-partition devices — meaning,
for most devices — users did not even have the option for moving their
apps to external storage.
android:installLocation is returning to relevance, once again
courtesy of removable media.
On Android 6.0+, users with removable storage options, such as micro SD card slots,
have the option of “adopting” those as an extension of
the device’s internal storage. Once done, apps set with
android:installLocation can be
moved to the removable media. However, there appears to be one
key difference: not only is the APK on the removable media, but so
is all of that app’s portion of internal storage. The removable
media is encrypted, so the material copied to the removable media
should remain fairly inaccessible.
From the user’s standpoint, for low-end devices with minimal on-board flash, they have additional storage space that they can use for apps.
Notificationtelling them to put it back:
Figure 888: Android 6.0, Ejected Adopted Removable Media Notification
The user does have an “Erase & Format” option that will reformat the removable media and allow it to be permanently removed from the device. It does not appear that this will automatically move any apps back to internal storage. The users would need to move those apps back to internal storage by means of the Apps list in Settings.
Normally, it appears this system will be limited to internal card
slots for things like micro SD cards. While USB On-The-Go (OTG) allows
Android devices to access thumb drives, those are likely to be accidentally
removed by the user (not to mention they usually tie up the charging
port). However, for development testing purposes, you can run the
adb shell sm set-force-adoptable true command to allow the
device to adopt USB OTG drives. Note though that once you do this, the
drive is more or less owned by that Android device until you “Erase & Format”
it, and you will lose everything on the drive as part of this whole
The preview of this section is in the process of being translated from its native Klingon.
The preview of this section was traded for a bag of magic beans.