BackupRestoreConfirmation.java revision dc92c82b4180e8067f1acd00a7db7935afce00ff
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                }
102                break;
103
104                case MSG_END_RESTORE: {
105                    Toast.makeText(mContext, "!!! Restore ended !!!", Toast.LENGTH_SHORT).show();
106                    finish();
107                }
108                break;
109
110                case MSG_TIMEOUT: {
111                    Toast.makeText(mContext, "!!! TIMED OUT !!!", Toast.LENGTH_LONG).show();
112                }
113                break;
114            }
115        }
116    }
117
118    @Override
119    public void onCreate(Bundle icicle) {
120        super.onCreate(icicle);
121
122        final Intent intent = getIntent();
123        final String action = intent.getAction();
124
125        int layoutId;
126        if (action.equals(FullBackup.FULL_BACKUP_INTENT_ACTION)) {
127            layoutId = R.layout.confirm_backup;
128        } else if (action.equals(FullBackup.FULL_RESTORE_INTENT_ACTION)) {
129            layoutId = R.layout.confirm_restore;
130        } else {
131            Slog.w(TAG, "Backup/restore confirmation activity launched with invalid action!");
132            finish();
133            return;
134        }
135
136        mToken = intent.getIntExtra(FullBackup.CONF_TOKEN_INTENT_EXTRA, -1);
137        if (mToken < 0) {
138            Slog.e(TAG, "Backup/restore confirmation requested but no token passed!");
139            finish();
140            return;
141        }
142
143        mBackupManager = IBackupManager.Stub.asInterface(ServiceManager.getService(Context.BACKUP_SERVICE));
144
145        mHandler = new ObserverHandler(getApplicationContext());
146        mObserver = new FullObserver();
147
148        setContentView(layoutId);
149
150        // Same resource IDs for each layout variant (backup / restore)
151        mStatusView = (TextView) findViewById(R.id.package_name);
152        mAllowButton = (Button) findViewById(R.id.button_allow);
153        mDenyButton = (Button) findViewById(R.id.button_deny);
154
155        mAllowButton.setOnClickListener(new View.OnClickListener() {
156            @Override
157            public void onClick(View v) {
158                try {
159                    mBackupManager.acknowledgeFullBackupOrRestore(mToken, true, mObserver);
160                } catch (RemoteException e) {
161                    // TODO: bail gracefully if we can't contact the backup manager
162                }
163                mAllowButton.setEnabled(false);
164                mDenyButton.setEnabled(false);
165            }
166        });
167
168        mDenyButton.setOnClickListener(new View.OnClickListener() {
169            @Override
170            public void onClick(View v) {
171                try {
172                    mBackupManager.acknowledgeFullBackupOrRestore(mToken, false, mObserver);
173                } catch (RemoteException e) {
174                    // TODO: bail gracefully if we can't contact the backup manager
175                }
176                mAllowButton.setEnabled(false);
177                mDenyButton.setEnabled(false);
178            }
179        });
180    }
181
182    @Override
183    public void onStop() {
184        super.onStop();
185
186        // We explicitly equate departure from the UI with refusal.  This includes the
187        // implicit configuration-changed stop/restart cycle.
188        try {
189            mBackupManager.acknowledgeFullBackupOrRestore(mToken, false, null);
190        } catch (RemoteException e) {
191            // if this fails we'll still time out with no acknowledgment
192        }
193        finish();
194    }
195
196    /**
197     * The observer binder for showing backup/restore progress.  This binder just bounces
198     * the notifications onto the main thread.
199     */
200    class FullObserver extends IFullBackupRestoreObserver.Stub {
201        //
202        // IFullBackupRestoreObserver implementation
203        //
204        @Override
205        public void onStartBackup() throws RemoteException {
206            mHandler.sendEmptyMessage(MSG_START_BACKUP);
207        }
208
209        @Override
210        public void onBackupPackage(String name) throws RemoteException {
211            mHandler.sendMessage(mHandler.obtainMessage(MSG_BACKUP_PACKAGE, name));
212        }
213
214        @Override
215        public void onEndBackup() throws RemoteException {
216            mHandler.sendEmptyMessage(MSG_END_BACKUP);
217        }
218
219        @Override
220        public void onStartRestore() throws RemoteException {
221            mHandler.sendEmptyMessage(MSG_START_RESTORE);
222        }
223
224        @Override
225        public void onRestorePackage(String name) throws RemoteException {
226            mHandler.sendMessage(mHandler.obtainMessage(MSG_RESTORE_PACKAGE, name));
227        }
228
229        @Override
230        public void onEndRestore() throws RemoteException {
231            mHandler.sendEmptyMessage(MSG_END_RESTORE);
232        }
233
234        @Override
235        public void onTimeout() throws RemoteException {
236            mHandler.sendEmptyMessage(MSG_TIMEOUT);
237        }
238    }
239}
240