28. Managing User Accounts and Synchronizing User Data

Android is cloud friendly. Android applications can integrate tightly with remote services, helping users transition seamlessly. Android applications can synchronize data with remote cloud-based (Internet) services using sync adapters. Developers can also take advantage of Android’s cloud-based backup service to protect and migrate application data safely and effectively. In this chapter, you will learn about the account and synchronization features used to sync data to built-in applications and how to protect application data using the backup and restore features available in Android.

Managing Accounts with the Account Manager

From a user perspective, the Android 2.0 platform introduced many exciting new device features. For instance, the user can register and use multiple accounts for email and contact management. This feature was provided through a combination of new synchronization and account services that are also available to developers. Although you can use the account and synchronization packages with any kind of data, the intention seems to be to provide a way for developers and companies to integrate their business services with the system that synchronizes data to the built-in Android applications.

Android user accounts are manipulated using the classes available in the android.accounts package. This functionality is primarily designed for accounts with services that contain contact, email, or other such information. A good example of this type of online service is a social networking application that contains friends’ contact information, as well as other relevant information such as their statuses. This information is often delivered and used on an Android device using the synchronization service (we talk more about synchronization later in the chapter).

First, we talk about accounts. Accounts registered with the Android account manager should provide access to the same sort of information—contact information, for the most part. Different accounts can be registered for a given user using the Android AccountManager class. Each account contains authentication information for a service, usually credentials for a server account somewhere online. Android services, such as the synchronization services built into the platform, can access these accounts, mining them for the appropriate types of information (again, primarily contact details, but also other bits of data such as social networking status).

Let’s look at how using account information provided via the AccountManager and Account classes works. An application that needs to access the server can request a list of accounts from the system. If one of the accounts contains credentials for the server, the application can request an authentication token (auth token, for short) for the account. The application would then use this token as a way to log in to the remote server to access its services. This keeps the user credentials secure and private while also providing a convenience to users in that they need to provide their credentials only once, regardless of how many applications use the information. All these tasks are achieved using the AccountManager class. A call to the getAccountByType() method retrieves a list of accounts, and then a call to the getAuthToken() method retrieves the token associated with a specific account, which the application can use to communicate with a password-protected resource, such as a web service.

On the other side of this process, authenticating credentials against the back-end server are the account providers, that is, the services that provide users with accounts and with which user information is authenticated so the applications can get the auth tokens. In order to do all of this (handle system requests to authenticate an Account object against the remote server), the account provider must implement an account authenticator. Through the authenticator, the account provider requests appropriate credentials and then confirms them with whatever account authentication operations are necessary—usually an online server. To implement an account authenticator, you need to make several modifications to your application. Begin by implementing the AbstractAccountAuthenticator class. You also need to update the application’s Android manifest file, provide an authenticator configuration file (XML), and provide an authenticator preference screen configuration in order to make the authentication experience as seamless as possible for the user.


Image Tip

Learn more about creating system-wide accounts in the Android SDK documentation for the AbstractAccountAuthenticator class. Learn more about using accounts in the Android SDK documentation for the AccountManager class. Also see the Google Play services documentation on “Authorization” (http://d.android.com/google/play-services/auth.html).


Multiple Users, Restricted Profiles, and Accounts

Android 4.2 (API Level 17) added the ability to create multiple user spaces on Android devices. This allows each user of a particular device to have his or her own separate area where applications, accounts, data, and other information are stored. There are no changes to make within your application for managing accounts when working with multiple users.

In addition to multiple users, Android 4.3 (API Level 18) introduced what is known as restricted profiles for tablets. A restricted profile is a configurable profile based on the primary user of the device, allowing for setting restrictions such as limiting access to certain applications, or even more fine-grained control such as restricting certain features within a particular application. If your application requires access to accounts, keep the following in mind:

Image If you would like to access the primary user’s account from within a restricted profile, add the android:restrictedAccountType attribute to the <application> tag in the Android manifest. Understand that this setting grants access to the primary user’s accounts from the restricted profile, so care must be taken not to expose personally identifiable information in cases where a restricted profile may be for a user other than the primary user.

Image If you are not able to access any existing accounts on the device or are unable to create your own account for the restricted profile, make sure to disable features within your application that require account access; that way other features of your application will still be available to the restricted profile.

Image If you are not able to access private accounts on the device, add the android: requiredAccountType attribute to the <application> tag in the Android manifest. Understand that this will prevent your application from being available to restricted profiles.

Synchronizing Data with Sync Adapters

The synchronization feature available in the Android SDK requires the use of the accounts classes we talked about earlier. This service is principally designed to enable syncing of contact, email, and calendar data to the built-in applications from a back-end data store—you’re “adapting” back-end server data to the existing content providers. In other words, the service is not generally used for syncing data specific to your typical Android application. In theory, applications can use this service to keep generic data in sync, but they might be better served by implementing synchronization internally. You can do this using the AlarmManager class to schedule systematic data synchronization via the network, perhaps using an Android Service.

If, however, you are working with data that is well suited to syncing to the internal applications, such as contacts or calendar information that you want to put in the built-in applications and content providers, implementing a sync adapter makes sense. This enables the Android system to manage synchronization activities.

The account service must provide the sync adapter by extending the AbstractThreadedSyncAdapter class. When the sync occurs, the onPerformSync() method of the sync adapter is called. The parameters to this method tell the adapter what account (as defined by the Account parameter) is being used, thus providing necessary auth tokens for accessing protected resources without having to ask the user for credentials. The adapter is also told which content provider to write the data to and to which authority, in the content provider sense, the data belongs.

In this way, synchronization operations are performed on their own thread at a time requested by the system. During the sync, the adapter gets updated information from the server and synchronizes it to the given content provider. The implementation details for this are flexible and up to the developer.


Image Tip

Learn more about creating sync adapters by checking out the “Creating a Sync Adapter” Training guide on the Android developer website: http://d.android.com/training/sync-adapters/creating-sync-adapter.html.


Using Backup Services

Android backup services were introduced in Android 2.2 (API Level 8). Applications can use the backup system service to request that application data such as shared preferences and files be backed up or restored. The backup service handles things from there, sending the appropriate backup archives to a remote backup service or retrieving them from the service.

Backup services should not be used for syncing application content. Backup and restore operations do not occur on demand. Use a synchronization strategy such as the sync adapter discussed earlier in this chapter in this case. Use Android backup services only to back up important application data.


Image Tip

Many of the code examples provided in this section are taken from the SimpleBackup application. The source code for this application is provided for download on the book’s website. Also, you need to use the adb bmgr command to force backups and restores to occur. For more information on adb, see Appendix A, “Quick-Start Guide: Android Debug Bridge.”


Choosing a Remote Backup Service

One of the most important decisions when it comes to backing up application data is where to back it up to. The remote backup service you choose should be secure, reliable, and always available. Many developers will likely choose the solution provided by Google: Android Backup Service.


Image Note

Other third-party remote backup services might be available. If you want complete control over the backup process, you might want to consider creating your own. However, that is beyond the scope of this book.


For your application to use Android Backup Service, you must register your application with Google and acquire a unique backup service key for use within the application’s manifest file. You can sign up for Google’s backup service at the Android Backup Service website: https://developer.android.com/google/backup/signup.html.


Image Warning

Backup services are available on most, but not all, Android devices running Android 2.2 and higher. The underlying implementation might vary. Also, different remote backup services might impose additional limitations on the devices supported. Test your specific target devices and backup solution thoroughly to determine that backup services function properly with your application.


Registering with Android Backup Service

After you have chosen a remote backup service, you might need to jump through a few more hoops. With Google’s Android Backup Service, you need to register for a special key to use. After you’ve acquired this key, you can use it in your application’s manifest file using the <meta-data> tag in the <application> block, like this:

<meta-data android:name="com.google.android.backup.api_key"
    android:value="KEY HERE" />

Implementing a Backup Agent

The backup system service relies on an application’s backup agent to determine what application data should be archived for backup and restore purposes.

Providing a Backup Agent Implementation

Now it’s time to implement the backup agent for your particular application. The backup agent determines what application data to send to the backup service. If you want to back up only shared preference data and application files, you can simply use the BackupAgentHelper class.


Image Tip

If you need to customize how your application backs up its data, you need to extend the BackupAgent class, which requires you to implement two callback methods. The onBackup() method is called when your application requests a backup and provides the backup service with the appropriate application data to back up. The onRestore() method is called when a restore is requested. The backup service supplies the archived data, and the onRestore() method handles restoring the application data.


Here is a sample implementation of a backup agent class:

public class SimpleBackupAgent extends BackupAgentHelper {
    @Override
    public void onCreate() {
        // Register helpers here
    }
}

Your application’s backup agent needs to include a backup helper for each type of data it wants to back up.

Implementing a Backup Helper for Shared Preferences

To back up shared preferences files, you need to use the SharedPreferencesBackupHelper class. Adding support for shared preferences is straightforward. Simply update the backup agent’s onCreate() method, create a valid SharedPreferencesBackupHelper object, and use the addHelper() method to add it to the agent:

SharedPreferencesBackupHelper prefshelper =
        new SharedPreferencesBackupHelper(this,
PREFERENCE_FILENAME);
addHelper(BACKUP_PREFERENCE_KEY, prefshelper);

This particular helper backs up all shared preferences by name. In this case, the addHelper() method takes two parameters:

Image A unique name for this helper (in this case, the backup key is stored as a String variable called BACKUP_PREFERENCE_KEY)

Image A valid SharedPreferencesBackupHelper object configured to control backups and restores on a specific set of shared preferences by name (in this case, the preference filename is stored in a String variable called PREFERENCE_FILENAME)

That’s it. In fact, if your application is backing up only shared preferences, you don’t even need to implement the onBackup() and onRestore() methods of your backup agent class.


Image Tip

Got more than one set of preferences? No problem. The constructor for SharedPreferencesBackupHelper can take any number of preference filenames. You still need only one unique name key for the helper.


Implementing a Backup Helper for Files

To back up application files, use the FileBackupHelper class. Files are a bit trickier to handle than shared preferences because they are not thread-safe. Begin by updating the backup agent’s onCreate() method, create a valid FileBackupHelper object, and use the addHelper() method to add it to the agent:

FileBackupHelper filehelper = new FileBackupHelper(this, APP_FILE_NAME);
addHelper(BACKUP_FILE_KEY, filehelper);

The file helper backs up specific files by name. In this case, the addHelper() method takes two parameters:

Image A unique name for this helper (in this case, the backup key is stored as a String variable called BACKUP_FILE_KEY)

Image A valid FileBackupHelper object configured to control backups and restores on a specific file by name (in this case, the filename is stored in a String variable called APP_FILE_NAME)


Image Tip

Got more than one file to back up? No problem. The constructor for FileBackupHelper can take any number of filenames. You still need only one unique name key for the helper. The services were designed to back up configuration data, not necessarily all files or media. There are currently no guidelines for the size of the data that can be backed up. For instance, a book reader application might back up book titles and reading states, but not the book contents. Then, after a restore, the data can be used to download the book contents again. To the user, the state appears the same. This type of backup is intended for state and configuration files, not large data files, though.


You also need to make sure that all file operations in your application are thread-safe as it’s possible a backup will be requested while a file is being accessed. The Android website suggests the following method for defining a lock from a simple Object array within an Activity:

static final Object[] fileLock = new Object[0];

Use this lock each and every time you perform file operations, either in your application logic or in the backup agent. For example:

synchronized(fileLock){
    // Do app logic file operations here
}

Finally, you need to override the onBackup() and onRestore() methods of your backup agent, if only to make sure all file operations are synchronized using your lock for thread-safe access. Here we have the full implementation of a backup agent that backs up one set of shared preferences called AppPrefs and a file named appfile.txt:

public class SimpleBackupAgent extends BackupAgentHelper {
    private static final String PREFERENCE_FILENAME = "AppPrefs";
    private static final String APP_FILE_NAME = "appfile.txt";
    static final String BACKUP_PREFERENCE_KEY = "BackupAppPrefs";
    static final String BACKUP_FILE_KEY = "BackupFile";

    @Override
    public void onCreate() {
        SharedPreferencesBackupHelper prefshelper = new
            SharedPreferencesBackupHelper(this,
            PREFERENCE_FILENAME);
        addHelper(BACKUP_PREFERENCE_KEY, prefshelper);
        FileBackupHelper filehelper =
            new FileBackupHelper(this, APP_FILE_NAME);
        addHelper(BACKUP_FILE_KEY, filehelper);
    }
    @Override
    public void onBackup(ParcelFileDescriptor oldState,
        BackupDataOutput data, ParcelFileDescriptor newState)
        throws IOException {
            synchronized (SimpleBackupActivity.fileLock) {
                super.onBackup(oldState, data, newState);
            }
    }
    @Override
    public void onRestore(BackupDataInput data, int appVersionCode,
        ParcelFileDescriptor newState) throws IOException {
            synchronized (SimpleBackupActivity.fileLock) {
                super.onRestore(data, appVersionCode, newState);
            }
    }
}

To make the onBackup() and onRestore() methods thread-safe, we simply wrapped the superclass call with a synchronized block using a file lock.

Registering the Backup Agent in the Application Manifest File

Finally, you need to register your backup agent class in your application’s manifest file using the android:backupAgent attribute of the <application> tab. For example, if your backup agent class is called SimpleBackupAgent, you register it using its fully qualified path name as follows:

<application
    android:icon="@drawable/icon"
    android:label="@string/app_name"
    android:backupAgent=
        "com.advancedandroidbook.simplebackup.SimpleBackupAgent">

Backing Up and Restoring Application Data

The BackupManager system service manages backup and restore requests. This service works in the background, on its own schedule. Applications that implement a backup agent can request a backup or restore, but the operations might not happen immediately. To get an instance of the BackupManager, simply create one in your Activity class, as follows:

BackupManager mBackupManager = new BackupManager(this);

Requesting a Backup

An application can request a backup using the dataChanged() method. Generally, this method should be called any time application data that is to be archived changes. It can be called any number of times, but when it’s time to back up, the backup takes place only one time, regardless of how many times dataChanged() was called before the backup.

mBackupManager.dataChanged();

Normally, the user does not initiate a backup. Instead, whenever important application data changes, the dataChanged() method should be called as part of the data-saving process. At some point in the future, a backup is performed “behind the scenes” by the backup manager.


Image Warning

Avoid backing up sensitive data to remote servers. Ultimately, you, the developer, are responsible for securing user data, not the backup service you employ. Although some services might encrypt data for you, if the data is sensitive to you or your users, you can always add a layer of encryption yourself.


Requesting a Restore

Restore operations occur automatically when a user resets his or her device or upgrades after “accidentally” dropping the old one in a hot tub or running it through the washing machine (it happens more often than you’d think). When a restore occurs, the user’s data is fetched from the remote backup service, and the application’s backup agent refreshes the data used by the application, overwriting any data that was there.

An application can directly request a restore using the requestRestore() method as well. The requestRestore() method takes one parameter: a RestoreObserver object. The following code illustrates how to request a restore:

RestoreObserver obs = new RestoreObserver(){
    @Override
    public void onUpdate(int nowBeingRestored, String currentPackage) {
        Log.i(DEBUG_TAG, "RESTORING: " + currentPackage);
    }

    @Override
    public void restoreFinished(int error) {
        Log.i(DEBUG_TAG, "RESTORE FINISHED! (" + error +")");
    }

    @Override
    public void restoreStarting(int numPackages) {
        Log.i(DEBUG_TAG, "RESTORE STARTING...");
    }
};

try {
    mBackupManager.requestRestore(obs);
} catch (Exception e) {
    Log.i(DEBUG_TAG,
        "Failed to request restore. Try adb bmgr restore...");
}


Image Tip

Testing of backup services is best done on a device running Android 2.2 or later, in conjunction with the adb bmgr command, which can force an immediate backup or restore to occur.


Summary

Android applications do not exist in a vacuum. Users demand that their data be accessible (securely, of course) across any and all technologies they use regularly. Phones fall into hot tubs (more often than you’d think), and users upgrade to newer devices. The Android platform provides services for keeping local application data synchronized with remote cloud services and for protecting application data using remote backup and restore services.

Quiz Questions

1. True or false: Use the AccountManager class to register different accounts for a given user.

2. What Android manifest <application> tag attribute do you need to include to disable your application from accessing the primary user account?

3. What class do you extend for implementing a sync adapter?

4. What methods do you need to override for implementing a BackupAgentHelper class?

5. True or false: You must define the android:backupAgent attribute in the <activity> tag of your application’s manifest file.

Exercises

1. Create an application that creates a user account for the device.

2. Create an application that supports accounts in a restricted profile environment following the considerations recommended in this chapter.

3. Read the Android documentation to determine how you would override the aborting of a restore operation when an application version is detected that is newer than what was originally backed up.

References and More Information

Wikipedia on cloud computing:

http://en.wikipedia.org/wiki/Cloud_computing

Android Reference documentation on the AccountManager class:

http://d.android.com/reference/android/accounts/AccountManager.html

Android Google Services: “Authorization”:

http://d.android.com/google/play-services/auth.html

Android Training: “Creating a Sync Adapter”:

http://d.android.com/training/sync-adapters/creating-sync-adapter.html

Android Training: “Running a Sync Adapter”:

http://d.android.com/training/sync-adapters/running-sync-adapter.html

Android Training: “Using the Backup API”:

http://d.android.com/training/cloudsync/backupapi.html

Android API Guides: “Data Backup”:

http://d.android.com/guide/topics/data/backup.html

Android Google Services: “Android Backup Service”:

http://d.android.com/google/backup/index.html

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.191.125.109