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