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