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; 21b1a7ffef3a0007b6991b8338460f6aac8cbb11e8Joe Onoratoimport android.os.ParcelFileDescriptor; 2206290a4bb9b280fa14a2bbeb2d3ceb09396a78c3Joe Onoratoimport android.util.Log; 23b1a7ffef3a0007b6991b8338460f6aac8cbb11e8Joe Onorato 2406290a4bb9b280fa14a2bbeb2d3ceb09396a78c3Joe Onoratoimport java.io.File; 25b1a7ffef3a0007b6991b8338460f6aac8cbb11e8Joe Onorato 26e28290e21f908b4e917099ff2aa41e3aab9310c2Christopher Tate/** 27d17da43c82c4edb97514d6138bc208eeba321636Scott Main * A helper class that can be used in conjunction with 28cc84c69726507a85116f5664e20e2ebfac76edbeChristopher Tate * {@link android.app.backup.BackupAgentHelper} to manage the backup of 29d17da43c82c4edb97514d6138bc208eeba321636Scott Main * {@link android.content.SharedPreferences}. Whenever a backup is performed, it 30d17da43c82c4edb97514d6138bc208eeba321636Scott Main * will back up all named shared preferences that have changed since the last 314e14a829129feee14ebe453f61a124784c870610Christopher Tate * backup operation. 325a20ea16d7e5b70dc7bad8700f54170e4f220d12Kenny Root * <p> 33d17da43c82c4edb97514d6138bc208eeba321636Scott Main * To use this class, the application's backup agent class should extend 344e14a829129feee14ebe453f61a124784c870610Christopher Tate * {@link android.app.backup.BackupAgentHelper}. Then, in the agent's 354e14a829129feee14ebe453f61a124784c870610Christopher Tate * {@link BackupAgent#onCreate()} method, an instance of this class should be 364e14a829129feee14ebe453f61a124784c870610Christopher Tate * allocated and installed as a backup/restore handler within the BackupAgentHelper 37d17da43c82c4edb97514d6138bc208eeba321636Scott Main * framework. For example, an agent supporting backup and restore for 38d17da43c82c4edb97514d6138bc208eeba321636Scott Main * an application with two groups of {@link android.content.SharedPreferences} 394e14a829129feee14ebe453f61a124784c870610Christopher Tate * data might look something like this: 404e14a829129feee14ebe453f61a124784c870610Christopher Tate * <pre> 414e14a829129feee14ebe453f61a124784c870610Christopher Tate * import android.app.backup.BackupAgentHelper; 424e14a829129feee14ebe453f61a124784c870610Christopher Tate * import android.app.backup.SharedPreferencesBackupHelper; 434e14a829129feee14ebe453f61a124784c870610Christopher Tate * 444e14a829129feee14ebe453f61a124784c870610Christopher Tate * public class MyBackupAgent extends BackupAgentHelper { 454e14a829129feee14ebe453f61a124784c870610Christopher Tate * // The names of the SharedPreferences groups that the application maintains. These 464e14a829129feee14ebe453f61a124784c870610Christopher Tate * // are the same strings that are passed to {@link Context#getSharedPreferences(String, int)}. 474e14a829129feee14ebe453f61a124784c870610Christopher Tate * static final String PREFS_DISPLAY = "displayprefs"; 484e14a829129feee14ebe453f61a124784c870610Christopher Tate * static final String PREFS_SCORES = "highscores"; 494e14a829129feee14ebe453f61a124784c870610Christopher Tate * 504e14a829129feee14ebe453f61a124784c870610Christopher Tate * // An arbitrary string used within the BackupAgentHelper implementation to 514e14a829129feee14ebe453f61a124784c870610Christopher Tate * // identify the SharedPreferenceBackupHelper's data. 524e14a829129feee14ebe453f61a124784c870610Christopher Tate * static final String MY_PREFS_BACKUP_KEY = "myprefs"; 534e14a829129feee14ebe453f61a124784c870610Christopher Tate * 544e14a829129feee14ebe453f61a124784c870610Christopher Tate * // Simply allocate a helper and install it 554e14a829129feee14ebe453f61a124784c870610Christopher Tate * void onCreate() { 564e14a829129feee14ebe453f61a124784c870610Christopher Tate * SharedPreferencesBackupHelper helper = 574e14a829129feee14ebe453f61a124784c870610Christopher Tate * new SharedPreferencesBackupHelper(this, PREFS_DISPLAY, PREFS_SCORES); 584e14a829129feee14ebe453f61a124784c870610Christopher Tate * addHelper(MY_PREFS_BACKUP_KEY, helper); 594e14a829129feee14ebe453f61a124784c870610Christopher Tate * } 604e14a829129feee14ebe453f61a124784c870610Christopher Tate * }</pre> 614e14a829129feee14ebe453f61a124784c870610Christopher Tate * <p> 62d17da43c82c4edb97514d6138bc208eeba321636Scott Main * No further implementation is needed; the {@link BackupAgentHelper} mechanism automatically 634e14a829129feee14ebe453f61a124784c870610Christopher Tate * dispatches the 644e14a829129feee14ebe453f61a124784c870610Christopher Tate * {@link BackupAgent#onBackup(android.os.ParcelFileDescriptor, BackupDataOutput, android.os.ParcelFileDescriptor) BackupAgent.onBackup()} 654e14a829129feee14ebe453f61a124784c870610Christopher Tate * and 664e14a829129feee14ebe453f61a124784c870610Christopher Tate * {@link BackupAgent#onRestore(BackupDataInput, int, android.os.ParcelFileDescriptor) BackupAgent.onRestore()} 67d17da43c82c4edb97514d6138bc208eeba321636Scott Main * callbacks to the SharedPreferencesBackupHelper as appropriate. 68e28290e21f908b4e917099ff2aa41e3aab9310c2Christopher Tate */ 6906290a4bb9b280fa14a2bbeb2d3ceb09396a78c3Joe Onoratopublic class SharedPreferencesBackupHelper extends FileBackupHelperBase implements BackupHelper { 7006290a4bb9b280fa14a2bbeb2d3ceb09396a78c3Joe Onorato private static final String TAG = "SharedPreferencesBackupHelper"; 71436344ae12c819f58306ceb94241a266141e1218Christopher Tate private static final boolean DEBUG = false; 7206290a4bb9b280fa14a2bbeb2d3ceb09396a78c3Joe Onorato 731cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato private Context mContext; 7406290a4bb9b280fa14a2bbeb2d3ceb09396a78c3Joe Onorato private String[] mPrefGroups; 751cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato 76e28290e21f908b4e917099ff2aa41e3aab9310c2Christopher Tate /** 77e28290e21f908b4e917099ff2aa41e3aab9310c2Christopher Tate * Construct a helper for backing up and restoring the 78e28290e21f908b4e917099ff2aa41e3aab9310c2Christopher Tate * {@link android.content.SharedPreferences} under the given names. 79e28290e21f908b4e917099ff2aa41e3aab9310c2Christopher Tate * 80d17da43c82c4edb97514d6138bc208eeba321636Scott Main * @param context The application {@link android.content.Context} 81d17da43c82c4edb97514d6138bc208eeba321636Scott Main * @param prefGroups The names of each {@link android.content.SharedPreferences} file to 82d17da43c82c4edb97514d6138bc208eeba321636Scott Main * back up 83e28290e21f908b4e917099ff2aa41e3aab9310c2Christopher Tate */ 84dc355a90a3d9d34f66316928a53f61ac35ab4781Joe Onorato public SharedPreferencesBackupHelper(Context context, String... prefGroups) { 8506290a4bb9b280fa14a2bbeb2d3ceb09396a78c3Joe Onorato super(context); 861cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato 871cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato mContext = context; 8806290a4bb9b280fa14a2bbeb2d3ceb09396a78c3Joe Onorato mPrefGroups = prefGroups; 891cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato } 9006290a4bb9b280fa14a2bbeb2d3ceb09396a78c3Joe Onorato 91e28290e21f908b4e917099ff2aa41e3aab9310c2Christopher Tate /** 92d17da43c82c4edb97514d6138bc208eeba321636Scott Main * Backs up the configured {@link android.content.SharedPreferences} groups. 93e28290e21f908b4e917099ff2aa41e3aab9310c2Christopher Tate */ 9406290a4bb9b280fa14a2bbeb2d3ceb09396a78c3Joe Onorato public void performBackup(ParcelFileDescriptor oldState, BackupDataOutput data, 9506290a4bb9b280fa14a2bbeb2d3ceb09396a78c3Joe Onorato ParcelFileDescriptor newState) { 961cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato Context context = mContext; 976f9d58ac62366b13a1eac00d58ebc84f03cea3f2Brad Fitzpatrick 986f9d58ac62366b13a1eac00d58ebc84f03cea3f2Brad Fitzpatrick // If a SharedPreference has an outstanding write in flight, 996f9d58ac62366b13a1eac00d58ebc84f03cea3f2Brad Fitzpatrick // wait for it to finish flushing to disk. 1006f9d58ac62366b13a1eac00d58ebc84f03cea3f2Brad Fitzpatrick QueuedWork.waitToFinish(); 1016f9d58ac62366b13a1eac00d58ebc84f03cea3f2Brad Fitzpatrick 102b1a7ffef3a0007b6991b8338460f6aac8cbb11e8Joe Onorato // make filenames for the prefGroups 10306290a4bb9b280fa14a2bbeb2d3ceb09396a78c3Joe Onorato String[] prefGroups = mPrefGroups; 104b1a7ffef3a0007b6991b8338460f6aac8cbb11e8Joe Onorato final int N = prefGroups.length; 105b1a7ffef3a0007b6991b8338460f6aac8cbb11e8Joe Onorato String[] files = new String[N]; 106b1a7ffef3a0007b6991b8338460f6aac8cbb11e8Joe Onorato for (int i=0; i<N; i++) { 1071cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato files[i] = context.getSharedPrefsFile(prefGroups[i]).getAbsolutePath(); 108b1a7ffef3a0007b6991b8338460f6aac8cbb11e8Joe Onorato } 109b1a7ffef3a0007b6991b8338460f6aac8cbb11e8Joe Onorato 1101cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato // go 11106290a4bb9b280fa14a2bbeb2d3ceb09396a78c3Joe Onorato performBackup_checked(oldState, data, newState, files, prefGroups); 11206290a4bb9b280fa14a2bbeb2d3ceb09396a78c3Joe Onorato } 11306290a4bb9b280fa14a2bbeb2d3ceb09396a78c3Joe Onorato 114e28290e21f908b4e917099ff2aa41e3aab9310c2Christopher Tate /** 115e28290e21f908b4e917099ff2aa41e3aab9310c2Christopher Tate * Restores one entity from the restore data stream to its proper shared 116e28290e21f908b4e917099ff2aa41e3aab9310c2Christopher Tate * preferences file store. 117e28290e21f908b4e917099ff2aa41e3aab9310c2Christopher Tate */ 11806290a4bb9b280fa14a2bbeb2d3ceb09396a78c3Joe Onorato public void restoreEntity(BackupDataInputStream data) { 11906290a4bb9b280fa14a2bbeb2d3ceb09396a78c3Joe Onorato Context context = mContext; 12006290a4bb9b280fa14a2bbeb2d3ceb09396a78c3Joe Onorato 12106290a4bb9b280fa14a2bbeb2d3ceb09396a78c3Joe Onorato String key = data.getKey(); 122436344ae12c819f58306ceb94241a266141e1218Christopher Tate if (DEBUG) Log.d(TAG, "got entity '" + key + "' size=" + data.size()); 123436344ae12c819f58306ceb94241a266141e1218Christopher Tate 12406290a4bb9b280fa14a2bbeb2d3ceb09396a78c3Joe Onorato if (isKeyInList(key, mPrefGroups)) { 12506290a4bb9b280fa14a2bbeb2d3ceb09396a78c3Joe Onorato File f = context.getSharedPrefsFile(key).getAbsoluteFile(); 12606290a4bb9b280fa14a2bbeb2d3ceb09396a78c3Joe Onorato writeFile(f, data); 12706290a4bb9b280fa14a2bbeb2d3ceb09396a78c3Joe Onorato } 128b1a7ffef3a0007b6991b8338460f6aac8cbb11e8Joe Onorato } 129b1a7ffef3a0007b6991b8338460f6aac8cbb11e8Joe Onorato} 130