1 /* 2 * Copyright (C) 2009 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.settings; 18 19 import android.app.AlertDialog; 20 import android.app.Dialog; 21 import android.app.backup.IBackupManager; 22 import android.content.ContentResolver; 23 import android.content.Context; 24 import android.content.DialogInterface; 25 import android.content.Intent; 26 import android.os.Bundle; 27 import android.os.Process; 28 import android.os.RemoteException; 29 import android.os.ServiceManager; 30 import android.os.UserHandle; 31 import android.os.UserManager; 32 import android.preference.Preference; 33 import android.preference.PreferenceCategory; 34 import android.preference.Preference.OnPreferenceChangeListener; 35 import android.preference.PreferenceScreen; 36 import android.preference.SwitchPreference; 37 import android.provider.SearchIndexableResource; 38 import android.provider.Settings; 39 import android.util.Log; 40 41 import com.android.settings.search.BaseSearchIndexProvider; 42 import com.android.settings.search.Indexable; 43 import com.android.settings.search.Indexable.SearchIndexProvider; 44 45 import java.util.ArrayList; 46 import java.util.List; 47 48 /** 49 * Gesture lock pattern settings. 50 */ 51 public class PrivacySettings extends SettingsPreferenceFragment implements 52 DialogInterface.OnClickListener, Indexable { 53 54 // Vendor specific 55 private static final String GSETTINGS_PROVIDER = "com.google.settings"; 56 private static final String BACKUP_CATEGORY = "backup_category"; 57 private static final String BACKUP_DATA = "backup_data"; 58 private static final String AUTO_RESTORE = "auto_restore"; 59 private static final String CONFIGURE_ACCOUNT = "configure_account"; 60 private static final String BACKUP_INACTIVE = "backup_inactive"; 61 private static final String PERSONAL_DATA_CATEGORY = "personal_data_category"; 62 private static final String TAG = "PrivacySettings"; 63 private IBackupManager mBackupManager; 64 private SwitchPreference mBackup; 65 private SwitchPreference mAutoRestore; 66 private Dialog mConfirmDialog; 67 private PreferenceScreen mConfigure; 68 private boolean mEnabled; 69 70 private static final int DIALOG_ERASE_BACKUP = 2; 71 private int mDialogType; 72 73 @Override onCreate(Bundle savedInstanceState)74 public void onCreate(Bundle savedInstanceState) { 75 super.onCreate(savedInstanceState); 76 // Don't allow any access if this is a secondary user 77 mEnabled = Process.myUserHandle().isOwner(); 78 if (!mEnabled) { 79 return; 80 } 81 82 addPreferencesFromResource(R.xml.privacy_settings); 83 final PreferenceScreen screen = getPreferenceScreen(); 84 mBackupManager = IBackupManager.Stub.asInterface( 85 ServiceManager.getService(Context.BACKUP_SERVICE)); 86 87 mBackup = (SwitchPreference) screen.findPreference(BACKUP_DATA); 88 mBackup.setOnPreferenceChangeListener(preferenceChangeListener); 89 90 mAutoRestore = (SwitchPreference) screen.findPreference(AUTO_RESTORE); 91 mAutoRestore.setOnPreferenceChangeListener(preferenceChangeListener); 92 93 mConfigure = (PreferenceScreen) screen.findPreference(CONFIGURE_ACCOUNT); 94 95 ArrayList<String> keysToRemove = getNonVisibleKeys(getActivity()); 96 final int screenPreferenceCount = screen.getPreferenceCount(); 97 for (int i = screenPreferenceCount - 1; i >= 0; --i) { 98 Preference preference = screen.getPreference(i); 99 if (keysToRemove.contains(preference.getKey())) { 100 screen.removePreference(preference); 101 } 102 } 103 PreferenceCategory backupCategory = (PreferenceCategory) findPreference(BACKUP_CATEGORY); 104 if (backupCategory != null) { 105 final int backupCategoryPreferenceCount = backupCategory.getPreferenceCount(); 106 for (int i = backupCategoryPreferenceCount - 1; i >= 0; --i) { 107 Preference preference = backupCategory.getPreference(i); 108 if (keysToRemove.contains(preference.getKey())) { 109 backupCategory.removePreference(preference); 110 } 111 } 112 } 113 updateToggles(); 114 } 115 116 @Override onResume()117 public void onResume() { 118 super.onResume(); 119 120 // Refresh UI 121 if (mEnabled) { 122 updateToggles(); 123 } 124 } 125 126 @Override onStop()127 public void onStop() { 128 if (mConfirmDialog != null && mConfirmDialog.isShowing()) { 129 mConfirmDialog.dismiss(); 130 } 131 mConfirmDialog = null; 132 mDialogType = 0; 133 super.onStop(); 134 } 135 136 private OnPreferenceChangeListener preferenceChangeListener = new OnPreferenceChangeListener() { 137 @Override 138 public boolean onPreferenceChange(Preference preference, Object newValue) { 139 if (!(preference instanceof SwitchPreference)) { 140 return true; 141 } 142 boolean nextValue = (Boolean) newValue; 143 boolean result = false; 144 if (preference == mBackup) { 145 if (nextValue == false) { 146 // Don't change Switch status until user makes choice in dialog 147 // so return false here. 148 showEraseBackupDialog(); 149 } else { 150 setBackupEnabled(true); 151 result = true; 152 } 153 } else if (preference == mAutoRestore) { 154 try { 155 mBackupManager.setAutoRestore(nextValue); 156 result = true; 157 } catch (RemoteException e) { 158 mAutoRestore.setChecked(!nextValue); 159 } 160 } 161 return result; 162 } 163 }; 164 showEraseBackupDialog()165 private void showEraseBackupDialog() { 166 mDialogType = DIALOG_ERASE_BACKUP; 167 CharSequence msg = getResources().getText(R.string.backup_erase_dialog_message); 168 // TODO: DialogFragment? 169 mConfirmDialog = new AlertDialog.Builder(getActivity()).setMessage(msg) 170 .setTitle(R.string.backup_erase_dialog_title) 171 .setPositiveButton(android.R.string.ok, this) 172 .setNegativeButton(android.R.string.cancel, this) 173 .show(); 174 } 175 176 /* 177 * Creates toggles for each available location provider 178 */ updateToggles()179 private void updateToggles() { 180 ContentResolver res = getContentResolver(); 181 182 boolean backupEnabled = false; 183 Intent configIntent = null; 184 String configSummary = null; 185 try { 186 backupEnabled = mBackupManager.isBackupEnabled(); 187 String transport = mBackupManager.getCurrentTransport(); 188 configIntent = mBackupManager.getConfigurationIntent(transport); 189 configSummary = mBackupManager.getDestinationString(transport); 190 } catch (RemoteException e) { 191 // leave it 'false' and disable the UI; there's no backup manager 192 mBackup.setEnabled(false); 193 } 194 mBackup.setChecked(backupEnabled); 195 196 mAutoRestore.setChecked(Settings.Secure.getInt(res, 197 Settings.Secure.BACKUP_AUTO_RESTORE, 1) == 1); 198 mAutoRestore.setEnabled(backupEnabled); 199 200 final boolean configureEnabled = (configIntent != null) && backupEnabled; 201 mConfigure.setEnabled(configureEnabled); 202 mConfigure.setIntent(configIntent); 203 setConfigureSummary(configSummary); 204 } 205 setConfigureSummary(String summary)206 private void setConfigureSummary(String summary) { 207 if (summary != null) { 208 mConfigure.setSummary(summary); 209 } else { 210 mConfigure.setSummary(R.string.backup_configure_account_default_summary); 211 } 212 } 213 updateConfigureSummary()214 private void updateConfigureSummary() { 215 try { 216 String transport = mBackupManager.getCurrentTransport(); 217 String summary = mBackupManager.getDestinationString(transport); 218 setConfigureSummary(summary); 219 } catch (RemoteException e) { 220 // Not much we can do here 221 } 222 } 223 224 @Override onClick(DialogInterface dialog, int which)225 public void onClick(DialogInterface dialog, int which) { 226 // Dialog is triggered before Switch status change, that means marking the Switch to 227 // true in showEraseBackupDialog() method will be override by following status change. 228 // So we do manual switching here due to users' response. 229 if (mDialogType == DIALOG_ERASE_BACKUP) { 230 // Accept turning off backup 231 if (which == DialogInterface.BUTTON_POSITIVE) { 232 setBackupEnabled(false); 233 } else if (which == DialogInterface.BUTTON_NEGATIVE) { 234 // Reject turning off backup 235 setBackupEnabled(true); 236 } 237 updateConfigureSummary(); 238 } 239 mDialogType = 0; 240 } 241 242 /** 243 * Informs the BackupManager of a change in backup state - if backup is disabled, 244 * the data on the server will be erased. 245 * @param enable whether to enable backup 246 */ setBackupEnabled(boolean enable)247 private void setBackupEnabled(boolean enable) { 248 if (mBackupManager != null) { 249 try { 250 mBackupManager.setBackupEnabled(enable); 251 } catch (RemoteException e) { 252 mBackup.setChecked(!enable); 253 mAutoRestore.setEnabled(!enable); 254 return; 255 } 256 } 257 mBackup.setChecked(enable); 258 mAutoRestore.setEnabled(enable); 259 mConfigure.setEnabled(enable); 260 } 261 262 @Override getHelpResource()263 protected int getHelpResource() { 264 return R.string.help_url_backup_reset; 265 } 266 267 /** 268 * For Search. 269 */ 270 public static final SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = 271 new PrivacySearchIndexProvider(); 272 273 private static class PrivacySearchIndexProvider extends BaseSearchIndexProvider { 274 275 boolean mIsPrimary; 276 PrivacySearchIndexProvider()277 public PrivacySearchIndexProvider() { 278 super(); 279 280 mIsPrimary = UserHandle.myUserId() == UserHandle.USER_OWNER; 281 } 282 283 @Override getXmlResourcesToIndex( Context context, boolean enabled)284 public List<SearchIndexableResource> getXmlResourcesToIndex( 285 Context context, boolean enabled) { 286 287 List<SearchIndexableResource> result = new ArrayList<SearchIndexableResource>(); 288 289 // For non-primary user, no backup or reset is available 290 if (!mIsPrimary) { 291 return result; 292 } 293 294 SearchIndexableResource sir = new SearchIndexableResource(context); 295 sir.xmlResId = R.xml.privacy_settings; 296 result.add(sir); 297 298 return result; 299 } 300 301 @Override getNonIndexableKeys(Context context)302 public List<String> getNonIndexableKeys(Context context) { 303 return getNonVisibleKeys(context); 304 } 305 } 306 getNonVisibleKeys(Context context)307 private static ArrayList<String> getNonVisibleKeys(Context context) { 308 final ArrayList<String> nonVisibleKeys = new ArrayList<String>(); 309 final IBackupManager backupManager = IBackupManager.Stub.asInterface( 310 ServiceManager.getService(Context.BACKUP_SERVICE)); 311 boolean isServiceActive = false; 312 try { 313 isServiceActive = backupManager.isBackupServiceActive(UserHandle.myUserId()); 314 } catch (RemoteException e) { 315 Log.w(TAG, "Failed querying backup manager service activity status. " + 316 "Assuming it is inactive."); 317 } 318 if (isServiceActive) { 319 nonVisibleKeys.add(BACKUP_INACTIVE); 320 } else { 321 nonVisibleKeys.add(AUTO_RESTORE); 322 nonVisibleKeys.add(CONFIGURE_ACCOUNT); 323 nonVisibleKeys.add(BACKUP_DATA); 324 } 325 if (UserManager.get(context).hasUserRestriction( 326 UserManager.DISALLOW_FACTORY_RESET)) { 327 nonVisibleKeys.add(PERSONAL_DATA_CATEGORY); 328 } 329 // Vendor specific 330 if (context.getPackageManager(). 331 resolveContentProvider(GSETTINGS_PROVIDER, 0) == null) { 332 nonVisibleKeys.add(BACKUP_CATEGORY); 333 } 334 return nonVisibleKeys; 335 } 336 } 337