1b1a7ffef3a0007b6991b8338460f6aac8cbb11e8Joe Onorato/*
2b1a7ffef3a0007b6991b8338460f6aac8cbb11e8Joe Onorato * Copyright (C) 2009 The Android Open Source Project
3b1a7ffef3a0007b6991b8338460f6aac8cbb11e8Joe Onorato *
4b1a7ffef3a0007b6991b8338460f6aac8cbb11e8Joe Onorato * Licensed under the Apache License, Version 2.0 (the "License");
5b1a7ffef3a0007b6991b8338460f6aac8cbb11e8Joe Onorato * you may not use this file except in compliance with the License.
6b1a7ffef3a0007b6991b8338460f6aac8cbb11e8Joe Onorato * You may obtain a copy of the License at
7b1a7ffef3a0007b6991b8338460f6aac8cbb11e8Joe Onorato *
8b1a7ffef3a0007b6991b8338460f6aac8cbb11e8Joe Onorato *      http://www.apache.org/licenses/LICENSE-2.0
9b1a7ffef3a0007b6991b8338460f6aac8cbb11e8Joe Onorato *
10b1a7ffef3a0007b6991b8338460f6aac8cbb11e8Joe Onorato * Unless required by applicable law or agreed to in writing, software
11b1a7ffef3a0007b6991b8338460f6aac8cbb11e8Joe Onorato * distributed under the License is distributed on an "AS IS" BASIS,
12b1a7ffef3a0007b6991b8338460f6aac8cbb11e8Joe Onorato * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13b1a7ffef3a0007b6991b8338460f6aac8cbb11e8Joe Onorato * See the License for the specific language governing permissions and
14b1a7ffef3a0007b6991b8338460f6aac8cbb11e8Joe Onorato * limitations under the License.
15b1a7ffef3a0007b6991b8338460f6aac8cbb11e8Joe Onorato */
16b1a7ffef3a0007b6991b8338460f6aac8cbb11e8Joe Onorato
174528186e0d65fc68ef0dd1941aa2ac8aefcd55a3Christopher Tatepackage android.app.backup;
18b1a7ffef3a0007b6991b8338460f6aac8cbb11e8Joe Onorato
196f9d58ac62366b13a1eac00d58ebc84f03cea3f2Brad Fitzpatrickimport android.app.QueuedWork;
20b1a7ffef3a0007b6991b8338460f6aac8cbb11e8Joe Onoratoimport android.content.Context;
215a20ea16d7e5b70dc7bad8700f54170e4f220d12Kenny Rootimport android.content.SharedPreferences;
22b1a7ffef3a0007b6991b8338460f6aac8cbb11e8Joe Onoratoimport android.os.ParcelFileDescriptor;
2306290a4bb9b280fa14a2bbeb2d3ceb09396a78c3Joe Onoratoimport android.util.Log;
24b1a7ffef3a0007b6991b8338460f6aac8cbb11e8Joe Onorato
2506290a4bb9b280fa14a2bbeb2d3ceb09396a78c3Joe Onoratoimport java.io.File;
26b1a7ffef3a0007b6991b8338460f6aac8cbb11e8Joe Onorato
27e28290e21f908b4e917099ff2aa41e3aab9310c2Christopher Tate/**
28d17da43c82c4edb97514d6138bc208eeba321636Scott Main * A helper class that can be used in conjunction with
29cc84c69726507a85116f5664e20e2ebfac76edbeChristopher Tate * {@link android.app.backup.BackupAgentHelper} to manage the backup of
30d17da43c82c4edb97514d6138bc208eeba321636Scott Main * {@link android.content.SharedPreferences}. Whenever a backup is performed, it
31d17da43c82c4edb97514d6138bc208eeba321636Scott Main * will back up all named shared preferences that have changed since the last
324e14a829129feee14ebe453f61a124784c870610Christopher Tate * backup operation.
335a20ea16d7e5b70dc7bad8700f54170e4f220d12Kenny Root * <p>
34d17da43c82c4edb97514d6138bc208eeba321636Scott Main * To use this class, the application's backup agent class should extend
354e14a829129feee14ebe453f61a124784c870610Christopher Tate * {@link android.app.backup.BackupAgentHelper}.  Then, in the agent's
364e14a829129feee14ebe453f61a124784c870610Christopher Tate * {@link BackupAgent#onCreate()} method, an instance of this class should be
374e14a829129feee14ebe453f61a124784c870610Christopher Tate * allocated and installed as a backup/restore handler within the BackupAgentHelper
38d17da43c82c4edb97514d6138bc208eeba321636Scott Main * framework.  For example, an agent supporting backup and restore for
39d17da43c82c4edb97514d6138bc208eeba321636Scott Main * an application with two groups of {@link android.content.SharedPreferences}
404e14a829129feee14ebe453f61a124784c870610Christopher Tate * data might look something like this:
414e14a829129feee14ebe453f61a124784c870610Christopher Tate * <pre>
424e14a829129feee14ebe453f61a124784c870610Christopher Tate * import android.app.backup.BackupAgentHelper;
434e14a829129feee14ebe453f61a124784c870610Christopher Tate * import android.app.backup.SharedPreferencesBackupHelper;
444e14a829129feee14ebe453f61a124784c870610Christopher Tate *
454e14a829129feee14ebe453f61a124784c870610Christopher Tate * public class MyBackupAgent extends BackupAgentHelper {
464e14a829129feee14ebe453f61a124784c870610Christopher Tate *     // The names of the SharedPreferences groups that the application maintains.  These
474e14a829129feee14ebe453f61a124784c870610Christopher Tate *     // are the same strings that are passed to {@link Context#getSharedPreferences(String, int)}.
484e14a829129feee14ebe453f61a124784c870610Christopher Tate *     static final String PREFS_DISPLAY = "displayprefs";
494e14a829129feee14ebe453f61a124784c870610Christopher Tate *     static final String PREFS_SCORES = "highscores";
504e14a829129feee14ebe453f61a124784c870610Christopher Tate *
514e14a829129feee14ebe453f61a124784c870610Christopher Tate *     // An arbitrary string used within the BackupAgentHelper implementation to
524e14a829129feee14ebe453f61a124784c870610Christopher Tate *     // identify the SharedPreferenceBackupHelper's data.
534e14a829129feee14ebe453f61a124784c870610Christopher Tate *     static final String MY_PREFS_BACKUP_KEY = "myprefs";
544e14a829129feee14ebe453f61a124784c870610Christopher Tate *
554e14a829129feee14ebe453f61a124784c870610Christopher Tate *     // Simply allocate a helper and install it
564e14a829129feee14ebe453f61a124784c870610Christopher Tate *     void onCreate() {
574e14a829129feee14ebe453f61a124784c870610Christopher Tate *         SharedPreferencesBackupHelper helper =
584e14a829129feee14ebe453f61a124784c870610Christopher Tate *                 new SharedPreferencesBackupHelper(this, PREFS_DISPLAY, PREFS_SCORES);
594e14a829129feee14ebe453f61a124784c870610Christopher Tate *         addHelper(MY_PREFS_BACKUP_KEY, helper);
604e14a829129feee14ebe453f61a124784c870610Christopher Tate *     }
614e14a829129feee14ebe453f61a124784c870610Christopher Tate * }</pre>
624e14a829129feee14ebe453f61a124784c870610Christopher Tate * <p>
63d17da43c82c4edb97514d6138bc208eeba321636Scott Main * No further implementation is needed; the {@link BackupAgentHelper} mechanism automatically
644e14a829129feee14ebe453f61a124784c870610Christopher Tate * dispatches the
654e14a829129feee14ebe453f61a124784c870610Christopher Tate * {@link BackupAgent#onBackup(android.os.ParcelFileDescriptor, BackupDataOutput, android.os.ParcelFileDescriptor) BackupAgent.onBackup()}
664e14a829129feee14ebe453f61a124784c870610Christopher Tate * and
674e14a829129feee14ebe453f61a124784c870610Christopher Tate * {@link BackupAgent#onRestore(BackupDataInput, int, android.os.ParcelFileDescriptor) BackupAgent.onRestore()}
68d17da43c82c4edb97514d6138bc208eeba321636Scott Main * callbacks to the SharedPreferencesBackupHelper as appropriate.
69e28290e21f908b4e917099ff2aa41e3aab9310c2Christopher Tate */
7006290a4bb9b280fa14a2bbeb2d3ceb09396a78c3Joe Onoratopublic class SharedPreferencesBackupHelper extends FileBackupHelperBase implements BackupHelper {
7106290a4bb9b280fa14a2bbeb2d3ceb09396a78c3Joe Onorato    private static final String TAG = "SharedPreferencesBackupHelper";
72436344ae12c819f58306ceb94241a266141e1218Christopher Tate    private static final boolean DEBUG = false;
7306290a4bb9b280fa14a2bbeb2d3ceb09396a78c3Joe Onorato
741cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato    private Context mContext;
7506290a4bb9b280fa14a2bbeb2d3ceb09396a78c3Joe Onorato    private String[] mPrefGroups;
761cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato
77e28290e21f908b4e917099ff2aa41e3aab9310c2Christopher Tate    /**
78e28290e21f908b4e917099ff2aa41e3aab9310c2Christopher Tate     * Construct a helper for backing up and restoring the
79e28290e21f908b4e917099ff2aa41e3aab9310c2Christopher Tate     * {@link android.content.SharedPreferences} under the given names.
80e28290e21f908b4e917099ff2aa41e3aab9310c2Christopher Tate     *
81d17da43c82c4edb97514d6138bc208eeba321636Scott Main     * @param context The application {@link android.content.Context}
82d17da43c82c4edb97514d6138bc208eeba321636Scott Main     * @param prefGroups The names of each {@link android.content.SharedPreferences} file to
83d17da43c82c4edb97514d6138bc208eeba321636Scott Main     * back up
84e28290e21f908b4e917099ff2aa41e3aab9310c2Christopher Tate     */
85dc355a90a3d9d34f66316928a53f61ac35ab4781Joe Onorato    public SharedPreferencesBackupHelper(Context context, String... prefGroups) {
8606290a4bb9b280fa14a2bbeb2d3ceb09396a78c3Joe Onorato        super(context);
871cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato
881cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato        mContext = context;
8906290a4bb9b280fa14a2bbeb2d3ceb09396a78c3Joe Onorato        mPrefGroups = prefGroups;
901cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato    }
9106290a4bb9b280fa14a2bbeb2d3ceb09396a78c3Joe Onorato
92e28290e21f908b4e917099ff2aa41e3aab9310c2Christopher Tate    /**
93d17da43c82c4edb97514d6138bc208eeba321636Scott Main     * Backs up the configured {@link android.content.SharedPreferences} groups.
94e28290e21f908b4e917099ff2aa41e3aab9310c2Christopher Tate     */
9506290a4bb9b280fa14a2bbeb2d3ceb09396a78c3Joe Onorato    public void performBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
9606290a4bb9b280fa14a2bbeb2d3ceb09396a78c3Joe Onorato            ParcelFileDescriptor newState) {
971cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato        Context context = mContext;
986f9d58ac62366b13a1eac00d58ebc84f03cea3f2Brad Fitzpatrick
996f9d58ac62366b13a1eac00d58ebc84f03cea3f2Brad Fitzpatrick        // If a SharedPreference has an outstanding write in flight,
1006f9d58ac62366b13a1eac00d58ebc84f03cea3f2Brad Fitzpatrick        // wait for it to finish flushing to disk.
1016f9d58ac62366b13a1eac00d58ebc84f03cea3f2Brad Fitzpatrick        QueuedWork.waitToFinish();
1026f9d58ac62366b13a1eac00d58ebc84f03cea3f2Brad Fitzpatrick
103b1a7ffef3a0007b6991b8338460f6aac8cbb11e8Joe Onorato        // make filenames for the prefGroups
10406290a4bb9b280fa14a2bbeb2d3ceb09396a78c3Joe Onorato        String[] prefGroups = mPrefGroups;
105b1a7ffef3a0007b6991b8338460f6aac8cbb11e8Joe Onorato        final int N = prefGroups.length;
106b1a7ffef3a0007b6991b8338460f6aac8cbb11e8Joe Onorato        String[] files = new String[N];
107b1a7ffef3a0007b6991b8338460f6aac8cbb11e8Joe Onorato        for (int i=0; i<N; i++) {
1081cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato            files[i] = context.getSharedPrefsFile(prefGroups[i]).getAbsolutePath();
109b1a7ffef3a0007b6991b8338460f6aac8cbb11e8Joe Onorato        }
110b1a7ffef3a0007b6991b8338460f6aac8cbb11e8Joe Onorato
1111cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato        // go
11206290a4bb9b280fa14a2bbeb2d3ceb09396a78c3Joe Onorato        performBackup_checked(oldState, data, newState, files, prefGroups);
11306290a4bb9b280fa14a2bbeb2d3ceb09396a78c3Joe Onorato    }
11406290a4bb9b280fa14a2bbeb2d3ceb09396a78c3Joe Onorato
115e28290e21f908b4e917099ff2aa41e3aab9310c2Christopher Tate    /**
116e28290e21f908b4e917099ff2aa41e3aab9310c2Christopher Tate     * Restores one entity from the restore data stream to its proper shared
117e28290e21f908b4e917099ff2aa41e3aab9310c2Christopher Tate     * preferences file store.
118e28290e21f908b4e917099ff2aa41e3aab9310c2Christopher Tate     */
11906290a4bb9b280fa14a2bbeb2d3ceb09396a78c3Joe Onorato    public void restoreEntity(BackupDataInputStream data) {
12006290a4bb9b280fa14a2bbeb2d3ceb09396a78c3Joe Onorato        Context context = mContext;
12106290a4bb9b280fa14a2bbeb2d3ceb09396a78c3Joe Onorato
12206290a4bb9b280fa14a2bbeb2d3ceb09396a78c3Joe Onorato        String key = data.getKey();
123436344ae12c819f58306ceb94241a266141e1218Christopher Tate        if (DEBUG) Log.d(TAG, "got entity '" + key + "' size=" + data.size());
124436344ae12c819f58306ceb94241a266141e1218Christopher Tate
12506290a4bb9b280fa14a2bbeb2d3ceb09396a78c3Joe Onorato        if (isKeyInList(key, mPrefGroups)) {
12606290a4bb9b280fa14a2bbeb2d3ceb09396a78c3Joe Onorato            File f = context.getSharedPrefsFile(key).getAbsoluteFile();
12706290a4bb9b280fa14a2bbeb2d3ceb09396a78c3Joe Onorato            writeFile(f, data);
12806290a4bb9b280fa14a2bbeb2d3ceb09396a78c3Joe Onorato        }
129b1a7ffef3a0007b6991b8338460f6aac8cbb11e8Joe Onorato    }
130b1a7ffef3a0007b6991b8338460f6aac8cbb11e8Joe Onorato}
131