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