1a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul/* 2a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul * Copyright (C) 2014 The Android Open Source Project 3a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul * 4a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul * Licensed under the Apache License, Version 2.0 (the "License"); 5a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul * you may not use this file except in compliance with the License. 6a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul * You may obtain a copy of the License at 7a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul * 8a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul * http://www.apache.org/licenses/LICENSE-2.0 9a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul * 10a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul * Unless required by applicable law or agreed to in writing, software 11a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul * distributed under the License is distributed on an "AS IS" BASIS, 12a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul * See the License for the specific language governing permissions and 14a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul * limitations under the License. 15a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul */ 16a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul 17a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paulpackage com.android.server.backup; 18a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul 19a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paulimport android.accounts.Account; 20a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paulimport android.accounts.AccountManager; 21a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paulimport android.app.backup.BackupDataInputStream; 22a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paulimport android.app.backup.BackupDataOutput; 23a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paulimport android.app.backup.BackupHelper; 24a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paulimport android.content.ContentResolver; 25a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paulimport android.content.Context; 26a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paulimport android.content.SyncAdapterType; 27ae0bcddc86752d2368ebcb73dab0b7d9133b3f67Ritesh Reddyimport android.os.Environment; 28a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paulimport android.os.ParcelFileDescriptor; 29a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paulimport android.util.Log; 30a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul 31ae0bcddc86752d2368ebcb73dab0b7d9133b3f67Ritesh Reddyimport org.json.JSONArray; 32ae0bcddc86752d2368ebcb73dab0b7d9133b3f67Ritesh Reddyimport org.json.JSONException; 33ae0bcddc86752d2368ebcb73dab0b7d9133b3f67Ritesh Reddyimport org.json.JSONObject; 34ae0bcddc86752d2368ebcb73dab0b7d9133b3f67Ritesh Reddy 35a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paulimport java.io.BufferedOutputStream; 36a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paulimport java.io.DataInputStream; 37a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paulimport java.io.DataOutputStream; 38a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paulimport java.io.EOFException; 39ae0bcddc86752d2368ebcb73dab0b7d9133b3f67Ritesh Reddyimport java.io.File; 40a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paulimport java.io.FileInputStream; 41ae0bcddc86752d2368ebcb73dab0b7d9133b3f67Ritesh Reddyimport java.io.FileNotFoundException; 42a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paulimport java.io.FileOutputStream; 43a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paulimport java.io.IOException; 44a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paulimport java.security.MessageDigest; 45a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paulimport java.security.NoSuchAlgorithmException; 46a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paulimport java.util.ArrayList; 47a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paulimport java.util.Arrays; 48a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paulimport java.util.HashMap; 49a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paulimport java.util.HashSet; 50a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paulimport java.util.List; 51a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul 52a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul/** 53a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul * Helper for backing up account sync settings (whether or not a service should be synced). The 54a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul * sync settings are backed up as a JSON object containing all the necessary information for 55a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul * restoring the sync settings later. 56a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul */ 57a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paulpublic class AccountSyncSettingsBackupHelper implements BackupHelper { 58a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul 59a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul private static final String TAG = "AccountSyncSettingsBackupHelper"; 60a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul private static final boolean DEBUG = false; 61a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul 62a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul private static final int STATE_VERSION = 1; 63a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul private static final int MD5_BYTE_SIZE = 16; 64a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul private static final int SYNC_REQUEST_LATCH_TIMEOUT_SECONDS = 1; 65a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul 66a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul private static final String JSON_FORMAT_HEADER_KEY = "account_data"; 67a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul private static final String JSON_FORMAT_ENCODING = "UTF-8"; 68a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul private static final int JSON_FORMAT_VERSION = 1; 69a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul 70a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul private static final String KEY_VERSION = "version"; 71a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul private static final String KEY_MASTER_SYNC_ENABLED = "masterSyncEnabled"; 72a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul private static final String KEY_ACCOUNTS = "accounts"; 73a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul private static final String KEY_ACCOUNT_NAME = "name"; 74a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul private static final String KEY_ACCOUNT_TYPE = "type"; 75a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul private static final String KEY_ACCOUNT_AUTHORITIES = "authorities"; 76a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul private static final String KEY_AUTHORITY_NAME = "name"; 77a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul private static final String KEY_AUTHORITY_SYNC_STATE = "syncState"; 78a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul private static final String KEY_AUTHORITY_SYNC_ENABLED = "syncEnabled"; 79ae0bcddc86752d2368ebcb73dab0b7d9133b3f67Ritesh Reddy private static final String STASH_FILE = Environment.getDataDirectory() 80ae0bcddc86752d2368ebcb73dab0b7d9133b3f67Ritesh Reddy + "/backup/unadded_account_syncsettings.json"; 81a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul 82a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul private Context mContext; 83a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul private AccountManager mAccountManager; 84a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul 85a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul public AccountSyncSettingsBackupHelper(Context context) { 86a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul mContext = context; 87a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul mAccountManager = AccountManager.get(mContext); 88a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul } 89a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul 90a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul /** 91a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul * Take a snapshot of the current account sync settings and write them to the given output. 92a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul */ 93a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul @Override 94a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul public void performBackup(ParcelFileDescriptor oldState, BackupDataOutput output, 95a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul ParcelFileDescriptor newState) { 96a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul try { 97a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul JSONObject dataJSON = serializeAccountSyncSettingsToJSON(); 98a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul 99a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul if (DEBUG) { 100a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul Log.d(TAG, "Account sync settings JSON: " + dataJSON); 101a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul } 102a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul 103a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul // Encode JSON data to bytes. 104a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul byte[] dataBytes = dataJSON.toString().getBytes(JSON_FORMAT_ENCODING); 105a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul byte[] oldMd5Checksum = readOldMd5Checksum(oldState); 106a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul byte[] newMd5Checksum = generateMd5Checksum(dataBytes); 107a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul if (!Arrays.equals(oldMd5Checksum, newMd5Checksum)) { 108a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul int dataSize = dataBytes.length; 109a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul output.writeEntityHeader(JSON_FORMAT_HEADER_KEY, dataSize); 110a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul output.writeEntityData(dataBytes, dataSize); 111a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul 112a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul Log.i(TAG, "Backup successful."); 113a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul } else { 114a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul Log.i(TAG, "Old and new MD5 checksums match. Skipping backup."); 115a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul } 116a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul 117a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul writeNewMd5Checksum(newState, newMd5Checksum); 118a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul } catch (JSONException | IOException | NoSuchAlgorithmException e) { 119a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul Log.e(TAG, "Couldn't backup account sync settings\n" + e); 120a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul } 121a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul } 122a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul 123a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul /** 124a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul * Fetch and serialize Account and authority information as a JSON Array. 125a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul */ 126a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul private JSONObject serializeAccountSyncSettingsToJSON() throws JSONException { 127a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul Account[] accounts = mAccountManager.getAccounts(); 128a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul SyncAdapterType[] syncAdapters = ContentResolver.getSyncAdapterTypesAsUser( 129a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul mContext.getUserId()); 130a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul 131a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul // Create a map of Account types to authorities. Later this will make it easier for us to 132a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul // generate our JSON. 133a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul HashMap<String, List<String>> accountTypeToAuthorities = new HashMap<String, 134a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul List<String>>(); 135a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul for (SyncAdapterType syncAdapter : syncAdapters) { 136a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul // Skip adapters that aren’t visible to the user. 137a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul if (!syncAdapter.isUserVisible()) { 138a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul continue; 139a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul } 140a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul if (!accountTypeToAuthorities.containsKey(syncAdapter.accountType)) { 141a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul accountTypeToAuthorities.put(syncAdapter.accountType, new ArrayList<String>()); 142a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul } 143a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul accountTypeToAuthorities.get(syncAdapter.accountType).add(syncAdapter.authority); 144a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul } 145a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul 146a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul // Generate JSON. 147a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul JSONObject backupJSON = new JSONObject(); 148a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul backupJSON.put(KEY_VERSION, JSON_FORMAT_VERSION); 149a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul backupJSON.put(KEY_MASTER_SYNC_ENABLED, ContentResolver.getMasterSyncAutomatically()); 150a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul 151a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul JSONArray accountJSONArray = new JSONArray(); 152a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul for (Account account : accounts) { 153a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul List<String> authorities = accountTypeToAuthorities.get(account.type); 154a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul 155a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul // We ignore Accounts that don't have any authorities because there would be no sync 156a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul // settings for us to restore. 157a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul if (authorities == null || authorities.isEmpty()) { 158a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul continue; 159a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul } 160a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul 161a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul JSONObject accountJSON = new JSONObject(); 162a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul accountJSON.put(KEY_ACCOUNT_NAME, account.name); 163a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul accountJSON.put(KEY_ACCOUNT_TYPE, account.type); 164a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul 165a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul // Add authorities for this Account type and check whether or not sync is enabled. 166a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul JSONArray authoritiesJSONArray = new JSONArray(); 167a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul for (String authority : authorities) { 168a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul int syncState = ContentResolver.getIsSyncable(account, authority); 169a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul boolean syncEnabled = ContentResolver.getSyncAutomatically(account, authority); 170a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul 171a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul JSONObject authorityJSON = new JSONObject(); 172a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul authorityJSON.put(KEY_AUTHORITY_NAME, authority); 173a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul authorityJSON.put(KEY_AUTHORITY_SYNC_STATE, syncState); 174a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul authorityJSON.put(KEY_AUTHORITY_SYNC_ENABLED, syncEnabled); 175a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul authoritiesJSONArray.put(authorityJSON); 176a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul } 177a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul accountJSON.put(KEY_ACCOUNT_AUTHORITIES, authoritiesJSONArray); 178a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul 179a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul accountJSONArray.put(accountJSON); 180a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul } 181a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul backupJSON.put(KEY_ACCOUNTS, accountJSONArray); 182a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul 183a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul return backupJSON; 184a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul } 185a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul 186a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul /** 187a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul * Read the MD5 checksum from the old state. 188a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul * 189a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul * @return the old MD5 checksum 190a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul */ 191a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul private byte[] readOldMd5Checksum(ParcelFileDescriptor oldState) throws IOException { 192a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul DataInputStream dataInput = new DataInputStream( 193a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul new FileInputStream(oldState.getFileDescriptor())); 194a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul 195a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul byte[] oldMd5Checksum = new byte[MD5_BYTE_SIZE]; 196a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul try { 197a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul int stateVersion = dataInput.readInt(); 198a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul if (stateVersion <= STATE_VERSION) { 199a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul // If the state version is a version we can understand then read the MD5 sum, 200a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul // otherwise we return an empty byte array for the MD5 sum which will force a 201a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul // backup. 202a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul for (int i = 0; i < MD5_BYTE_SIZE; i++) { 203a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul oldMd5Checksum[i] = dataInput.readByte(); 204a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul } 205a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul } else { 206a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul Log.i(TAG, "Backup state version is: " + stateVersion 207a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul + " (support only up to version " + STATE_VERSION + ")"); 208a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul } 209a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul } catch (EOFException eof) { 210a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul // Initial state may be empty. 211a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul } 21235f94d02ed59f311ab014e5686156a9d7bf1ea14Ritesh Reddy // We explicitly don't close 'dataInput' because we must not close the backing fd. 213a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul return oldMd5Checksum; 214a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul } 215a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul 216a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul /** 217a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul * Write the given checksum to the file descriptor. 218a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul */ 219a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul private void writeNewMd5Checksum(ParcelFileDescriptor newState, byte[] md5Checksum) 220a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul throws IOException { 221a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul DataOutputStream dataOutput = new DataOutputStream( 222a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul new BufferedOutputStream(new FileOutputStream(newState.getFileDescriptor()))); 223a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul 224a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul dataOutput.writeInt(STATE_VERSION); 225a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul dataOutput.write(md5Checksum); 22635f94d02ed59f311ab014e5686156a9d7bf1ea14Ritesh Reddy 22735f94d02ed59f311ab014e5686156a9d7bf1ea14Ritesh Reddy // We explicitly don't close 'dataOutput' because we must not close the backing fd. 22835f94d02ed59f311ab014e5686156a9d7bf1ea14Ritesh Reddy // The FileOutputStream will not close it implicitly. 22935f94d02ed59f311ab014e5686156a9d7bf1ea14Ritesh Reddy 230a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul } 231a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul 232a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul private byte[] generateMd5Checksum(byte[] data) throws NoSuchAlgorithmException { 233a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul if (data == null) { 234a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul return null; 235a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul } 236a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul 237a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul MessageDigest md5 = MessageDigest.getInstance("MD5"); 238a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul return md5.digest(data); 239a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul } 240a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul 241a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul /** 242a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul * Restore account sync settings from the given data input stream. 243a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul */ 244a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul @Override 245a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul public void restoreEntity(BackupDataInputStream data) { 246a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul byte[] dataBytes = new byte[data.size()]; 247a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul try { 248a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul // Read the data and convert it to a String. 249a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul data.read(dataBytes); 250a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul String dataString = new String(dataBytes, JSON_FORMAT_ENCODING); 251a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul 252a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul // Convert data to a JSON object. 253a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul JSONObject dataJSON = new JSONObject(dataString); 254a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul boolean masterSyncEnabled = dataJSON.getBoolean(KEY_MASTER_SYNC_ENABLED); 255a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul JSONArray accountJSONArray = dataJSON.getJSONArray(KEY_ACCOUNTS); 256a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul 257a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul boolean currentMasterSyncEnabled = ContentResolver.getMasterSyncAutomatically(); 258a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul if (currentMasterSyncEnabled) { 259a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul // Disable master sync to prevent any syncs from running. 260a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul ContentResolver.setMasterSyncAutomatically(false); 261a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul } 262a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul 263a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul try { 264ae0bcddc86752d2368ebcb73dab0b7d9133b3f67Ritesh Reddy restoreFromJsonArray(accountJSONArray); 265a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul } finally { 266a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul // Set the master sync preference to the value from the backup set. 267a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul ContentResolver.setMasterSyncAutomatically(masterSyncEnabled); 268a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul } 269a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul Log.i(TAG, "Restore successful."); 270a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul } catch (IOException | JSONException e) { 271a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul Log.e(TAG, "Couldn't restore account sync settings\n" + e); 272a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul } 273a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul } 274a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul 275ae0bcddc86752d2368ebcb73dab0b7d9133b3f67Ritesh Reddy private void restoreFromJsonArray(JSONArray accountJSONArray) 276ae0bcddc86752d2368ebcb73dab0b7d9133b3f67Ritesh Reddy throws JSONException { 277ae0bcddc86752d2368ebcb73dab0b7d9133b3f67Ritesh Reddy HashSet<Account> currentAccounts = getAccounts(); 278ae0bcddc86752d2368ebcb73dab0b7d9133b3f67Ritesh Reddy JSONArray unaddedAccountsJSONArray = new JSONArray(); 279ae0bcddc86752d2368ebcb73dab0b7d9133b3f67Ritesh Reddy for (int i = 0; i < accountJSONArray.length(); i++) { 280ae0bcddc86752d2368ebcb73dab0b7d9133b3f67Ritesh Reddy JSONObject accountJSON = (JSONObject) accountJSONArray.get(i); 281ae0bcddc86752d2368ebcb73dab0b7d9133b3f67Ritesh Reddy String accountName = accountJSON.getString(KEY_ACCOUNT_NAME); 282ae0bcddc86752d2368ebcb73dab0b7d9133b3f67Ritesh Reddy String accountType = accountJSON.getString(KEY_ACCOUNT_TYPE); 283ae0bcddc86752d2368ebcb73dab0b7d9133b3f67Ritesh Reddy 284ae0bcddc86752d2368ebcb73dab0b7d9133b3f67Ritesh Reddy Account account = null; 285ae0bcddc86752d2368ebcb73dab0b7d9133b3f67Ritesh Reddy try { 286ae0bcddc86752d2368ebcb73dab0b7d9133b3f67Ritesh Reddy account = new Account(accountName, accountType); 287ae0bcddc86752d2368ebcb73dab0b7d9133b3f67Ritesh Reddy } catch (IllegalArgumentException iae) { 288ae0bcddc86752d2368ebcb73dab0b7d9133b3f67Ritesh Reddy continue; 289ae0bcddc86752d2368ebcb73dab0b7d9133b3f67Ritesh Reddy } 290ae0bcddc86752d2368ebcb73dab0b7d9133b3f67Ritesh Reddy 291ae0bcddc86752d2368ebcb73dab0b7d9133b3f67Ritesh Reddy // Check if the account already exists. Accounts that don't exist on the device 292ae0bcddc86752d2368ebcb73dab0b7d9133b3f67Ritesh Reddy // yet won't be restored. 293ae0bcddc86752d2368ebcb73dab0b7d9133b3f67Ritesh Reddy if (currentAccounts.contains(account)) { 294ae0bcddc86752d2368ebcb73dab0b7d9133b3f67Ritesh Reddy if (DEBUG) Log.i(TAG, "Restoring Sync Settings for" + accountName); 295ae0bcddc86752d2368ebcb73dab0b7d9133b3f67Ritesh Reddy restoreExistingAccountSyncSettingsFromJSON(accountJSON); 296ae0bcddc86752d2368ebcb73dab0b7d9133b3f67Ritesh Reddy } else { 297ae0bcddc86752d2368ebcb73dab0b7d9133b3f67Ritesh Reddy unaddedAccountsJSONArray.put(accountJSON); 298ae0bcddc86752d2368ebcb73dab0b7d9133b3f67Ritesh Reddy } 299ae0bcddc86752d2368ebcb73dab0b7d9133b3f67Ritesh Reddy } 300ae0bcddc86752d2368ebcb73dab0b7d9133b3f67Ritesh Reddy 301ae0bcddc86752d2368ebcb73dab0b7d9133b3f67Ritesh Reddy if (unaddedAccountsJSONArray.length() > 0) { 302ae0bcddc86752d2368ebcb73dab0b7d9133b3f67Ritesh Reddy try (FileOutputStream fOutput = new FileOutputStream(STASH_FILE)) { 303ae0bcddc86752d2368ebcb73dab0b7d9133b3f67Ritesh Reddy String jsonString = unaddedAccountsJSONArray.toString(); 304ae0bcddc86752d2368ebcb73dab0b7d9133b3f67Ritesh Reddy DataOutputStream out = new DataOutputStream(fOutput); 305ae0bcddc86752d2368ebcb73dab0b7d9133b3f67Ritesh Reddy out.writeUTF(jsonString); 306ae0bcddc86752d2368ebcb73dab0b7d9133b3f67Ritesh Reddy } catch (IOException ioe) { 307ae0bcddc86752d2368ebcb73dab0b7d9133b3f67Ritesh Reddy // Error in writing to stash file 308ae0bcddc86752d2368ebcb73dab0b7d9133b3f67Ritesh Reddy Log.e(TAG, "unable to write the sync settings to the stash file", ioe); 309ae0bcddc86752d2368ebcb73dab0b7d9133b3f67Ritesh Reddy } 310ae0bcddc86752d2368ebcb73dab0b7d9133b3f67Ritesh Reddy } else { 311ae0bcddc86752d2368ebcb73dab0b7d9133b3f67Ritesh Reddy File stashFile = new File(STASH_FILE); 312ae0bcddc86752d2368ebcb73dab0b7d9133b3f67Ritesh Reddy if (stashFile.exists()) stashFile.delete(); 313ae0bcddc86752d2368ebcb73dab0b7d9133b3f67Ritesh Reddy } 314ae0bcddc86752d2368ebcb73dab0b7d9133b3f67Ritesh Reddy } 315ae0bcddc86752d2368ebcb73dab0b7d9133b3f67Ritesh Reddy 316ae0bcddc86752d2368ebcb73dab0b7d9133b3f67Ritesh Reddy /** 317ae0bcddc86752d2368ebcb73dab0b7d9133b3f67Ritesh Reddy * Restore SyncSettings for all existing accounts from a stashed backup-set 318ae0bcddc86752d2368ebcb73dab0b7d9133b3f67Ritesh Reddy */ 319ae0bcddc86752d2368ebcb73dab0b7d9133b3f67Ritesh Reddy private void accountAddedInternal() { 320ae0bcddc86752d2368ebcb73dab0b7d9133b3f67Ritesh Reddy String jsonString; 321ae0bcddc86752d2368ebcb73dab0b7d9133b3f67Ritesh Reddy 322ae0bcddc86752d2368ebcb73dab0b7d9133b3f67Ritesh Reddy try (FileInputStream fIn = new FileInputStream(new File(STASH_FILE))) { 323ae0bcddc86752d2368ebcb73dab0b7d9133b3f67Ritesh Reddy DataInputStream in = new DataInputStream(fIn); 324ae0bcddc86752d2368ebcb73dab0b7d9133b3f67Ritesh Reddy jsonString = in.readUTF(); 325ae0bcddc86752d2368ebcb73dab0b7d9133b3f67Ritesh Reddy } catch (FileNotFoundException fnfe) { 326ae0bcddc86752d2368ebcb73dab0b7d9133b3f67Ritesh Reddy // This is expected to happen when there is no accounts info stashed 327ae0bcddc86752d2368ebcb73dab0b7d9133b3f67Ritesh Reddy if (DEBUG) Log.d(TAG, "unable to find the stash file", fnfe); 328ae0bcddc86752d2368ebcb73dab0b7d9133b3f67Ritesh Reddy return; 329ae0bcddc86752d2368ebcb73dab0b7d9133b3f67Ritesh Reddy } catch (IOException ioe) { 330ae0bcddc86752d2368ebcb73dab0b7d9133b3f67Ritesh Reddy if (DEBUG) Log.d(TAG, "could not read sync settings from stash file", ioe); 331ae0bcddc86752d2368ebcb73dab0b7d9133b3f67Ritesh Reddy return; 332ae0bcddc86752d2368ebcb73dab0b7d9133b3f67Ritesh Reddy } 333ae0bcddc86752d2368ebcb73dab0b7d9133b3f67Ritesh Reddy 334ae0bcddc86752d2368ebcb73dab0b7d9133b3f67Ritesh Reddy try { 335ae0bcddc86752d2368ebcb73dab0b7d9133b3f67Ritesh Reddy JSONArray unaddedAccountsJSONArray = new JSONArray(jsonString); 336ae0bcddc86752d2368ebcb73dab0b7d9133b3f67Ritesh Reddy restoreFromJsonArray(unaddedAccountsJSONArray); 337ae0bcddc86752d2368ebcb73dab0b7d9133b3f67Ritesh Reddy } catch (JSONException jse) { 338ae0bcddc86752d2368ebcb73dab0b7d9133b3f67Ritesh Reddy // Malformed jsonString 339ae0bcddc86752d2368ebcb73dab0b7d9133b3f67Ritesh Reddy Log.e(TAG, "there was an error with the stashed sync settings", jse); 340ae0bcddc86752d2368ebcb73dab0b7d9133b3f67Ritesh Reddy } 341ae0bcddc86752d2368ebcb73dab0b7d9133b3f67Ritesh Reddy } 342ae0bcddc86752d2368ebcb73dab0b7d9133b3f67Ritesh Reddy 343ae0bcddc86752d2368ebcb73dab0b7d9133b3f67Ritesh Reddy /** 344ae0bcddc86752d2368ebcb73dab0b7d9133b3f67Ritesh Reddy * Restore SyncSettings for all existing accounts from a stashed backup-set 345ae0bcddc86752d2368ebcb73dab0b7d9133b3f67Ritesh Reddy */ 346ae0bcddc86752d2368ebcb73dab0b7d9133b3f67Ritesh Reddy public static void accountAdded(Context context) { 347ae0bcddc86752d2368ebcb73dab0b7d9133b3f67Ritesh Reddy AccountSyncSettingsBackupHelper helper = new AccountSyncSettingsBackupHelper(context); 348ae0bcddc86752d2368ebcb73dab0b7d9133b3f67Ritesh Reddy helper.accountAddedInternal(); 349ae0bcddc86752d2368ebcb73dab0b7d9133b3f67Ritesh Reddy } 350ae0bcddc86752d2368ebcb73dab0b7d9133b3f67Ritesh Reddy 351a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul /** 352a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul * Helper method - fetch accounts and return them as a HashSet. 353a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul * 354a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul * @return Accounts in a HashSet. 355a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul */ 356ae0bcddc86752d2368ebcb73dab0b7d9133b3f67Ritesh Reddy private HashSet<Account> getAccounts() { 357a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul Account[] accounts = mAccountManager.getAccounts(); 358a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul HashSet<Account> accountHashSet = new HashSet<Account>(); 359a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul for (Account account : accounts) { 360a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul accountHashSet.add(account); 361a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul } 362a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul return accountHashSet; 363a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul } 364a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul 365a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul /** 366a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul * Restore account sync settings using the given JSON. This function won't work if the account 367a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul * doesn't exist yet. 36853abfdb86c2bf834777dbda61fc46083a93a4a83Matthew Williams * This function will only be called during Setup Wizard, where we are guaranteed that there 36953abfdb86c2bf834777dbda61fc46083a93a4a83Matthew Williams * are no active syncs. 37053abfdb86c2bf834777dbda61fc46083a93a4a83Matthew Williams * There are 2 pieces of data to restore - 37153abfdb86c2bf834777dbda61fc46083a93a4a83Matthew Williams * isSyncable (corresponds to {@link ContentResolver#getIsSyncable(Account, String)} 37253abfdb86c2bf834777dbda61fc46083a93a4a83Matthew Williams * syncEnabled (corresponds to {@link ContentResolver#getSyncAutomatically(Account, String)} 37353abfdb86c2bf834777dbda61fc46083a93a4a83Matthew Williams * <strong>The restore favours adapters that were enabled on the old device, and doesn't care 37453abfdb86c2bf834777dbda61fc46083a93a4a83Matthew Williams * about adapters that were disabled.</strong> 37553abfdb86c2bf834777dbda61fc46083a93a4a83Matthew Williams * 37653abfdb86c2bf834777dbda61fc46083a93a4a83Matthew Williams * syncEnabled=true in restore data. 37753abfdb86c2bf834777dbda61fc46083a93a4a83Matthew Williams * syncEnabled will be true on this device. isSyncable will be left as the default in order to 37853abfdb86c2bf834777dbda61fc46083a93a4a83Matthew Williams * give the enabled adapter the chance to run an initialization sync. 37953abfdb86c2bf834777dbda61fc46083a93a4a83Matthew Williams * 38053abfdb86c2bf834777dbda61fc46083a93a4a83Matthew Williams * syncEnabled=false in restore data. 38153abfdb86c2bf834777dbda61fc46083a93a4a83Matthew Williams * syncEnabled will be false on this device. isSyncable will be set to 2, unless it was 0 on the 38253abfdb86c2bf834777dbda61fc46083a93a4a83Matthew Williams * old device in which case it will be set to 0 on this device. This is because isSyncable=0 is 38353abfdb86c2bf834777dbda61fc46083a93a4a83Matthew Williams * a rare state and was probably set to 0 for good reason (historically isSyncable is a way by 38453abfdb86c2bf834777dbda61fc46083a93a4a83Matthew Williams * which adapters control their own sync state independently of sync settings which is 38553abfdb86c2bf834777dbda61fc46083a93a4a83Matthew Williams * toggleable by the user). 38653abfdb86c2bf834777dbda61fc46083a93a4a83Matthew Williams * isSyncable=2 is a new isSyncable state we introduced specifically to allow adapters that are 38753abfdb86c2bf834777dbda61fc46083a93a4a83Matthew Williams * disabled after a restore to run initialization logic when the adapter is later enabled. 38853abfdb86c2bf834777dbda61fc46083a93a4a83Matthew Williams * See com.android.server.content.SyncStorageEngine#setSyncAutomatically 38953abfdb86c2bf834777dbda61fc46083a93a4a83Matthew Williams * 39053abfdb86c2bf834777dbda61fc46083a93a4a83Matthew Williams * The end result is that an adapter that the user had on will be turned on and get an 39153abfdb86c2bf834777dbda61fc46083a93a4a83Matthew Williams * initialization sync, while an adapter that the user had off will be off until the user 39253abfdb86c2bf834777dbda61fc46083a93a4a83Matthew Williams * enables it on this device at which point it will get an initialization sync. 393a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul */ 394a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul private void restoreExistingAccountSyncSettingsFromJSON(JSONObject accountJSON) 395a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul throws JSONException { 396a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul // Restore authorities. 397a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul JSONArray authorities = accountJSON.getJSONArray(KEY_ACCOUNT_AUTHORITIES); 398a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul String accountName = accountJSON.getString(KEY_ACCOUNT_NAME); 399a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul String accountType = accountJSON.getString(KEY_ACCOUNT_TYPE); 40053abfdb86c2bf834777dbda61fc46083a93a4a83Matthew Williams 401a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul final Account account = new Account(accountName, accountType); 402a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul for (int i = 0; i < authorities.length(); i++) { 403a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul JSONObject authority = (JSONObject) authorities.get(i); 404a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul final String authorityName = authority.getString(KEY_AUTHORITY_NAME); 40553abfdb86c2bf834777dbda61fc46083a93a4a83Matthew Williams boolean wasSyncEnabled = authority.getBoolean(KEY_AUTHORITY_SYNC_ENABLED); 40653abfdb86c2bf834777dbda61fc46083a93a4a83Matthew Williams int wasSyncable = authority.getInt(KEY_AUTHORITY_SYNC_STATE); 40753abfdb86c2bf834777dbda61fc46083a93a4a83Matthew Williams 40853abfdb86c2bf834777dbda61fc46083a93a4a83Matthew Williams ContentResolver.setSyncAutomaticallyAsUser( 40953abfdb86c2bf834777dbda61fc46083a93a4a83Matthew Williams account, authorityName, wasSyncEnabled, 0 /* user Id */); 41053abfdb86c2bf834777dbda61fc46083a93a4a83Matthew Williams 41153abfdb86c2bf834777dbda61fc46083a93a4a83Matthew Williams if (!wasSyncEnabled) { 41253abfdb86c2bf834777dbda61fc46083a93a4a83Matthew Williams ContentResolver.setIsSyncable( 41353abfdb86c2bf834777dbda61fc46083a93a4a83Matthew Williams account, 41453abfdb86c2bf834777dbda61fc46083a93a4a83Matthew Williams authorityName, 41553abfdb86c2bf834777dbda61fc46083a93a4a83Matthew Williams wasSyncable == 0 ? 41653abfdb86c2bf834777dbda61fc46083a93a4a83Matthew Williams 0 /* not syncable */ : 2 /* syncable but needs initialization */); 417a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul } 418a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul } 419a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul } 420a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul 421a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul @Override 422a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul public void writeNewStateDescription(ParcelFileDescriptor newState) { 423a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul 424a6533256ac1de9d0860688ca743aa7a2468470ccMarvin Paul } 425ae0bcddc86752d2368ebcb73dab0b7d9133b3f67Ritesh Reddy}