1 /* 2 * Copyright (C) 2014 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.tv.settings.device.privacy; 18 19 import com.android.tv.settings.ActionBehavior; 20 import com.android.tv.settings.ActionKey; 21 import com.android.tv.settings.R; 22 import com.android.tv.settings.dialog.old.Action; 23 import com.android.tv.settings.dialog.old.ActionAdapter; 24 import com.android.tv.settings.dialog.old.ActionFragment; 25 import com.android.tv.settings.dialog.old.ContentFragment; 26 import com.android.tv.settings.dialog.old.DialogActivity; 27 import com.android.tv.settings.util.IntentUtils; 28 29 import android.app.ActivityManager; 30 import android.app.AlertDialog; 31 import android.app.Dialog; 32 import android.app.backup.IBackupManager; 33 import android.app.Fragment; 34 import android.app.admin.DevicePolicyManager; 35 import android.content.ComponentName; 36 import android.content.Context; 37 import android.content.DialogInterface; 38 import android.content.Intent; 39 import android.content.res.Resources; 40 import android.os.Bundle; 41 import android.os.RemoteException; 42 import android.os.ServiceManager; 43 import android.provider.Settings; 44 45 import java.util.ArrayList; 46 import java.util.Collections; 47 import java.util.HashMap; 48 import java.util.Map; 49 50 /** 51 * Activity that allows enabling and disabling of backup and restore functions. 52 */ 53 public class PrivacyActivity extends DialogActivity 54 implements ActionAdapter.Listener, DialogInterface.OnClickListener { 55 56 private static final int DIALOG_ERASE_BACKUP = 2; 57 58 /** 59 * Support for shutdown-after-reset. If our launch intent has a true value for 60 * the boolean extra under the following key, then include it in the intent we 61 * use to trigger a factory reset. This will cause us to shut down instead of 62 * restart after the reset. 63 */ 64 private static final String SHUTDOWN_INTENT_EXTRA = "shutdown"; 65 66 private IBackupManager mBackupManager; 67 private ContentFragment mContentFragment; 68 private ActionFragment mActionFragment; 69 private Dialog mConfirmDialog; 70 private int mDialogType; 71 72 @Override 73 protected void onCreate(Bundle savedInstanceState) { 74 super.onCreate(savedInstanceState); 75 76 mBackupManager = IBackupManager.Stub.asInterface( 77 ServiceManager.getService(Context.BACKUP_SERVICE)); 78 79 // TODO implement backup and restore (b/10414565), then: 80 // NOTE1: Don't disable backups in SetupCompletedFragment under 81 // SetupWraith. 82 // NOTE2: Do no call finish() in onFactoryReset() upon CANCEL. 83 // NOTE3: Set breadcrumb to R.string.device_backup_restore for 84 // createFactoryResetContentFragment(). 85 // NOTE4: Below call 86 // createMainMenuContentFragment() and getMainActions() 87 // instead of 88 // createFactoryResetContentFragment() and getFactoryResetActions(). 89 // NOTE5: Change the backup_restore preference under res/xml/device to 90 // device_backup_restore. 91 mContentFragment = createFactoryResetContentFragment(); 92 mActionFragment = ActionFragment.newInstance(getFactoryResetActions()); 93 setContentAndActionFragments(mContentFragment, mActionFragment); 94 } 95 96 @Override 97 public void onStop() { 98 if (mConfirmDialog != null && mConfirmDialog.isShowing()) { 99 mConfirmDialog.dismiss(); 100 } 101 mConfirmDialog = null; 102 mDialogType = 0; 103 super.onStop(); 104 } 105 106 @Override 107 public void onClick(DialogInterface dialog, int which) { 108 if (which == DialogInterface.BUTTON_POSITIVE) { 109 if (mDialogType == DIALOG_ERASE_BACKUP) { 110 try { 111 mBackupManager.setBackupEnabled(false); 112 } catch (RemoteException e) { 113 // ignore. 114 } 115 goToMainScreen(); 116 } 117 } 118 mDialogType = 0; 119 } 120 121 @Override 122 public void onActionClicked(Action action) { 123 ActionKey<ActionType, ActionBehavior> actionKey = new ActionKey<ActionType, ActionBehavior>( 124 ActionType.class, ActionBehavior.class, action.getKey()); 125 ActionType type = actionKey.getType(); 126 ActionBehavior behaviour = actionKey.getBehavior(); 127 switch (actionKey.getType()) { 128 case BACKUP_DATA: 129 onBackupData(behaviour); 130 break; 131 case BACKUP_ACCOUNT: 132 onBackupAccount(behaviour); 133 break; 134 case AUTOMATIC_RESTORE: 135 onAutomaticRestore(behaviour); 136 break; 137 case FACTORY_RESET: 138 onFactoryReset(behaviour); 139 break; 140 case FACTORY_RESET_CONFIRM: 141 onFactoryResetConfirm(behaviour); 142 break; 143 default: 144 break; 145 } 146 } 147 148 private void onFactoryReset(ActionBehavior behaviour) { 149 switch (behaviour) { 150 case INIT: 151 setContentAndActionFragments(createFactoryResetContentFragment(), 152 ActionFragment.newInstance(getFactoryResetActions())); 153 break; 154 case CANCEL: 155 // TODO pop from backstack to go back to main menu after backups 156 // are implemented (b/10414565). 157 finish(); 158 break; 159 default: 160 break; 161 } 162 } 163 164 private void onFactoryResetConfirm(ActionBehavior behaviour) { 165 switch (behaviour) { 166 case INIT: 167 setContentAndActionFragments(ContentFragment.newInstance( 168 ActionType.FACTORY_RESET_CONFIRM.getTitle(getResources()), 169 getString(R.string.device_reset), 170 getString(R.string.confirm_factory_reset_description), 171 R.drawable.ic_settings_backuprestore, 172 getResources().getColor(R.color.icon_background)), 173 ActionFragment.newInstance(getFactoryResetConfirmActions())); 174 break; 175 case OK: 176 if (!ActivityManager.isUserAMonkey()) { 177 Intent resetIntent = new Intent("android.intent.action.MASTER_CLEAR"); 178 if (getIntent().getBooleanExtra(SHUTDOWN_INTENT_EXTRA, false)) { 179 resetIntent.putExtra(SHUTDOWN_INTENT_EXTRA, true); 180 } 181 sendBroadcast(resetIntent); 182 } 183 break; 184 case CANCEL: 185 getFragmentManager().popBackStack(null, 0); 186 getFragmentManager().popBackStack(null, 0); 187 break; 188 default: 189 break; 190 } 191 } 192 193 private ArrayList<Action> getFactoryResetActions() { 194 ArrayList<Action> actions = new ArrayList<Action>(); 195 actions.add(new Action.Builder() 196 .key(new ActionKey<ActionType, ActionBehavior>(ActionType.FACTORY_RESET_CONFIRM, 197 ActionBehavior.INIT).getKey()) 198 .title(getString(R.string.factory_reset_device)) 199 .build()); 200 actions.add(new Action.Builder() 201 .key(new ActionKey<ActionType, ActionBehavior>(ActionType.FACTORY_RESET, 202 ActionBehavior.CANCEL).getKey()) 203 .title(getString(R.string.settings_cancel)) 204 .build()); 205 return actions; 206 } 207 208 private ArrayList<Action> getFactoryResetConfirmActions() { 209 ArrayList<Action> actions = new ArrayList<Action>(); 210 actions.add(new Action.Builder() 211 .key(new ActionKey<ActionType, ActionBehavior>(ActionType.FACTORY_RESET_CONFIRM, 212 ActionBehavior.OK).getKey()) 213 .title(getString(R.string.confirm_factory_reset_device)) 214 .build()); 215 actions.add(new Action.Builder() 216 .key(new ActionKey<ActionType, ActionBehavior>(ActionType.FACTORY_RESET_CONFIRM, 217 ActionBehavior.CANCEL).getKey()) 218 .title(getString(R.string.settings_cancel)) 219 .build()); 220 return actions; 221 } 222 223 private void onBackupData(ActionBehavior behaviour) { 224 try { 225 boolean isOn = mBackupManager.isBackupEnabled(); 226 switch (behaviour) { 227 case INIT: 228 ArrayList<Action> actions = new ArrayList<Action>(); 229 actions.add(ActionBehavior.ON.toAction(new ActionKey< 230 ActionType, ActionBehavior>( 231 ActionType.BACKUP_DATA, ActionBehavior.ON).getKey(), 232 getResources(), isOn)); 233 actions.add(ActionBehavior.OFF.toAction(new ActionKey< 234 ActionType, ActionBehavior>( 235 ActionType.BACKUP_DATA, ActionBehavior.OFF).getKey(), 236 getResources(), !isOn)); 237 setContentAndActionFragments( 238 createSubMenuContentFragment(ActionType.BACKUP_DATA), 239 ActionFragment.newInstance(actions)); 240 break; 241 case ON: 242 if (!isOn) { 243 try { 244 mBackupManager.setBackupEnabled(true); 245 } catch (RemoteException e) { 246 // ignore. 247 } 248 } 249 goToMainScreen(); 250 break; 251 case OFF: 252 if (isOn) { 253 mDialogType = DIALOG_ERASE_BACKUP; 254 CharSequence msg = getResources() 255 .getText(R.string.backup_erase_dialog_message); 256 // TODO: DialogFragment? 257 mConfirmDialog = new AlertDialog.Builder(this).setMessage(msg) 258 .setTitle(R.string.backup_erase_dialog_title) 259 .setIconAttribute(android.R.attr.alertDialogIcon) 260 .setPositiveButton(android.R.string.ok, this) 261 .setNegativeButton(android.R.string.cancel, this).show(); 262 } 263 goToMainScreen(); 264 break; 265 default: 266 break; 267 } 268 } catch (RemoteException e) { 269 // ignore. 270 } 271 } 272 273 private void onBackupAccount(ActionBehavior behaviour) { 274 try { 275 String transport = mBackupManager.getCurrentTransport(); 276 Intent configIntent = mBackupManager.getConfigurationIntent(transport); 277 if (configIntent != null) { 278 IntentUtils.startActivity(this, configIntent); 279 } 280 } catch (RemoteException e) { 281 // ignore. 282 } 283 } 284 285 private void onAutomaticRestore(ActionBehavior behaviour) { 286 boolean isOn = isAutoRestoreEnabled(); 287 switch (behaviour) { 288 case INIT: 289 ArrayList<Action> actions = new ArrayList<Action>(); 290 actions.add(ActionBehavior.ON.toAction(new ActionKey<ActionType, ActionBehavior>( 291 ActionType.AUTOMATIC_RESTORE, ActionBehavior.ON).getKey(), getResources(), 292 isOn)); 293 actions.add(ActionBehavior.OFF.toAction(new ActionKey<ActionType, ActionBehavior>( 294 ActionType.AUTOMATIC_RESTORE, ActionBehavior.OFF).getKey(), getResources(), 295 !isOn)); 296 setContentAndActionFragments( 297 createSubMenuContentFragment(ActionType.AUTOMATIC_RESTORE), 298 ActionFragment.newInstance(actions)); 299 break; 300 case ON: 301 if (!isOn) { 302 try { 303 mBackupManager.setAutoRestore(true); 304 } catch (RemoteException e) { 305 // ignore. 306 } 307 } 308 goToMainScreen(); 309 break; 310 case OFF: 311 if (isOn) { 312 try { 313 mBackupManager.setAutoRestore(false); 314 } catch (RemoteException e) { 315 // ignore. 316 } 317 } 318 goToMainScreen(); 319 break; 320 default: 321 break; 322 } 323 } 324 325 private boolean isAutoRestoreEnabled() { 326 return Settings.Secure.getInt(getContentResolver(), Settings.Secure.BACKUP_AUTO_RESTORE, 1) 327 == 1; 328 } 329 330 private void goToMainScreen() { 331 updateMainScreen(); 332 getFragmentManager().popBackStack(null, 0); 333 } 334 335 private ArrayList<Action> getMainActions() { 336 ArrayList<Action> actions = new ArrayList<Action>(); 337 338 try { 339 boolean isBackupEnabled = mBackupManager.isBackupEnabled(); 340 String transport = mBackupManager.getCurrentTransport(); 341 Intent configIntent = mBackupManager.getConfigurationIntent(transport); 342 String configSummary = mBackupManager.getDestinationString(transport); 343 344 actions.add(ActionType.BACKUP_DATA.toAction(getResources(), 345 mBackupManager.isBackupEnabled() ? getString(R.string.settings_on) 346 : getString(R.string.settings_off))); 347 if (isBackupEnabled && configIntent != null) { 348 actions.add(ActionType.BACKUP_ACCOUNT.toAction( 349 getResources(), configSummary == null ? getString( 350 R.string.backup_configure_account_default_summary) 351 : configSummary)); 352 } 353 if (isBackupEnabled) { 354 actions.add(ActionType.AUTOMATIC_RESTORE.toAction( 355 getResources(), isAutoRestoreEnabled() ? getString(R.string.settings_on) 356 : getString(R.string.settings_off))); 357 } 358 359 } catch (RemoteException re) { 360 // no backup manager means no actions. 361 } 362 363 actions.add(ActionType.FACTORY_RESET.toAction(getResources(), null)); 364 365 return actions; 366 } 367 368 private Fragment createSubMenuContentFragment(ActionType type) { 369 return ContentFragment.newInstance(type.getTitle(getResources()), 370 getString(R.string.device_backup_restore), null, 371 R.drawable.ic_settings_backuprestore, 372 getResources().getColor(R.color.icon_background)); 373 } 374 375 private ContentFragment createMainMenuContentFragment() { 376 return ContentFragment.newInstance(getString(R.string.device_backup_restore), 377 getString(R.string.header_category_device), 378 null, R.drawable.ic_settings_backuprestore, 379 getResources().getColor(R.color.icon_background)); 380 } 381 382 private ContentFragment createFactoryResetContentFragment() { 383 // TODO Set breadcrumb to R.string.device_backup_restore b/10414565 384 return ContentFragment.newInstance( 385 ActionType.FACTORY_RESET.getTitle(getResources()), 386 getString(R.string.header_category_device), 387 getString(R.string.factory_reset_description), 388 R.drawable.ic_settings_backuprestore, 389 getResources().getColor(R.color.icon_background)); 390 } 391 392 private void updateMainScreen() { 393 ((ActionAdapter) mActionFragment.getAdapter()).setActions(getMainActions()); 394 } 395 } 396