BackupRestoreConfirmation.java revision 75a99709accef8cf221fd436d646727e7c8dd1f1
1/* 2 * Copyright (C) 2011 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 17package com.android.backupconfirm; 18 19import android.app.Activity; 20import android.app.backup.FullBackup; 21import android.app.backup.IBackupManager; 22import android.app.backup.IFullBackupRestoreObserver; 23import android.content.Context; 24import android.content.Intent; 25import android.os.Bundle; 26import android.os.Handler; 27import android.os.Message; 28import android.os.RemoteException; 29import android.os.ServiceManager; 30import android.util.Slog; 31import android.view.View; 32import android.widget.Button; 33import android.widget.TextView; 34import android.widget.Toast; 35 36/** 37 * Confirm with the user that a requested full backup/restore operation is legitimate. 38 * Any attempt to perform a full backup/restore will launch this UI and wait for a 39 * designated timeout interval (nominally 30 seconds) for the user to confirm. If the 40 * user fails to respond within the timeout period, or explicitly refuses the operation 41 * within the UI presented here, no data will be transferred off the device. 42 * 43 * Note that the fully scoped name of this class is baked into the backup manager service. 44 * 45 * @hide 46 */ 47public class BackupRestoreConfirmation extends Activity { 48 static final String TAG = "BackupRestoreConfirmation"; 49 static final boolean DEBUG = true; 50 51 static final int MSG_START_BACKUP = 1; 52 static final int MSG_BACKUP_PACKAGE = 2; 53 static final int MSG_END_BACKUP = 3; 54 static final int MSG_START_RESTORE = 11; 55 static final int MSG_RESTORE_PACKAGE = 12; 56 static final int MSG_END_RESTORE = 13; 57 static final int MSG_TIMEOUT = 100; 58 59 Handler mHandler; 60 IBackupManager mBackupManager; 61 FullObserver mObserver; 62 int mToken; 63 64 TextView mStatusView; 65 Button mAllowButton; 66 Button mDenyButton; 67 68 // Handler for dealing with observer callbacks on the main thread 69 class ObserverHandler extends Handler { 70 Context mContext; 71 ObserverHandler(Context context) { 72 mContext = context; 73 } 74 75 @Override 76 public void handleMessage(Message msg) { 77 switch (msg.what) { 78 case MSG_START_BACKUP: { 79 Toast.makeText(mContext, "!!! Backup starting !!!", Toast.LENGTH_LONG).show(); 80 } 81 break; 82 83 case MSG_BACKUP_PACKAGE: { 84 String name = (String) msg.obj; 85 mStatusView.setText(name); 86 } 87 break; 88 89 case MSG_END_BACKUP: { 90 Toast.makeText(mContext, "!!! Backup ended !!!", Toast.LENGTH_SHORT).show(); 91 finish(); 92 } 93 break; 94 95 case MSG_START_RESTORE: { 96 Toast.makeText(mContext, "!!! Restore starting !!!", Toast.LENGTH_LONG).show(); 97 } 98 break; 99 100 case MSG_RESTORE_PACKAGE: { 101 String name = (String) msg.obj; 102 mStatusView.setText(name); 103 } 104 break; 105 106 case MSG_END_RESTORE: { 107 Toast.makeText(mContext, "!!! Restore ended !!!", Toast.LENGTH_SHORT).show(); 108 finish(); 109 } 110 break; 111 112 case MSG_TIMEOUT: { 113 Toast.makeText(mContext, "!!! TIMED OUT !!!", Toast.LENGTH_LONG).show(); 114 } 115 break; 116 } 117 } 118 } 119 120 @Override 121 public void onCreate(Bundle icicle) { 122 super.onCreate(icicle); 123 124 final Intent intent = getIntent(); 125 final String action = intent.getAction(); 126 127 int layoutId; 128 if (action.equals(FullBackup.FULL_BACKUP_INTENT_ACTION)) { 129 layoutId = R.layout.confirm_backup; 130 } else if (action.equals(FullBackup.FULL_RESTORE_INTENT_ACTION)) { 131 layoutId = R.layout.confirm_restore; 132 } else { 133 Slog.w(TAG, "Backup/restore confirmation activity launched with invalid action!"); 134 finish(); 135 return; 136 } 137 138 mToken = intent.getIntExtra(FullBackup.CONF_TOKEN_INTENT_EXTRA, -1); 139 if (mToken < 0) { 140 Slog.e(TAG, "Backup/restore confirmation requested but no token passed!"); 141 finish(); 142 return; 143 } 144 145 mBackupManager = IBackupManager.Stub.asInterface(ServiceManager.getService(Context.BACKUP_SERVICE)); 146 147 mHandler = new ObserverHandler(getApplicationContext()); 148 mObserver = new FullObserver(); 149 150 setContentView(layoutId); 151 152 // Same resource IDs for each layout variant (backup / restore) 153 mStatusView = (TextView) findViewById(R.id.package_name); 154 mAllowButton = (Button) findViewById(R.id.button_allow); 155 mDenyButton = (Button) findViewById(R.id.button_deny); 156 157 mAllowButton.setOnClickListener(new View.OnClickListener() { 158 @Override 159 public void onClick(View v) { 160 try { 161 mBackupManager.acknowledgeFullBackupOrRestore(mToken, true, mObserver); 162 } catch (RemoteException e) { 163 // TODO: bail gracefully if we can't contact the backup manager 164 } 165 mAllowButton.setEnabled(false); 166 mDenyButton.setEnabled(false); 167 } 168 }); 169 170 mDenyButton.setOnClickListener(new View.OnClickListener() { 171 @Override 172 public void onClick(View v) { 173 try { 174 mBackupManager.acknowledgeFullBackupOrRestore(mToken, false, mObserver); 175 } catch (RemoteException e) { 176 // TODO: bail gracefully if we can't contact the backup manager 177 } 178 mAllowButton.setEnabled(false); 179 mDenyButton.setEnabled(false); 180 } 181 }); 182 } 183 184 @Override 185 public void onStop() { 186 super.onStop(); 187 188 // We explicitly equate departure from the UI with refusal. This includes the 189 // implicit configuration-changed stop/restart cycle. 190 try { 191 mBackupManager.acknowledgeFullBackupOrRestore(mToken, false, null); 192 } catch (RemoteException e) { 193 // if this fails we'll still time out with no acknowledgment 194 } 195 finish(); 196 } 197 198 /** 199 * The observer binder for showing backup/restore progress. This binder just bounces 200 * the notifications onto the main thread. 201 */ 202 class FullObserver extends IFullBackupRestoreObserver.Stub { 203 // 204 // IFullBackupRestoreObserver implementation 205 // 206 @Override 207 public void onStartBackup() throws RemoteException { 208 mHandler.sendEmptyMessage(MSG_START_BACKUP); 209 } 210 211 @Override 212 public void onBackupPackage(String name) throws RemoteException { 213 mHandler.sendMessage(mHandler.obtainMessage(MSG_BACKUP_PACKAGE, name)); 214 } 215 216 @Override 217 public void onEndBackup() throws RemoteException { 218 mHandler.sendEmptyMessage(MSG_END_BACKUP); 219 } 220 221 @Override 222 public void onStartRestore() throws RemoteException { 223 mHandler.sendEmptyMessage(MSG_START_RESTORE); 224 } 225 226 @Override 227 public void onRestorePackage(String name) throws RemoteException { 228 mHandler.sendMessage(mHandler.obtainMessage(MSG_RESTORE_PACKAGE, name)); 229 } 230 231 @Override 232 public void onEndRestore() throws RemoteException { 233 mHandler.sendEmptyMessage(MSG_END_RESTORE); 234 } 235 236 @Override 237 public void onTimeout() throws RemoteException { 238 mHandler.sendEmptyMessage(MSG_TIMEOUT); 239 } 240 } 241} 242