1/*
2 * Copyright (C) 2010 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 android.app.backup;
18
19import android.annotation.SystemApi;
20import android.app.backup.RestoreObserver;
21import android.app.backup.RestoreSet;
22import android.app.backup.IRestoreObserver;
23import android.app.backup.IRestoreSession;
24import android.content.Context;
25import android.os.Bundle;
26import android.os.Handler;
27import android.os.Message;
28import android.os.RemoteException;
29import android.util.Log;
30
31/**
32 * Interface for managing a restore session.
33 * @hide
34 */
35@SystemApi
36public class RestoreSession {
37    static final String TAG = "RestoreSession";
38
39    final Context mContext;
40    IRestoreSession mBinder;
41    RestoreObserverWrapper mObserver = null;
42
43    /**
44     * Ask the current transport what the available restore sets are.
45     *
46     * @param observer a RestoreObserver object whose restoreSetsAvailable() method will
47     *   be called on the application's main thread in order to supply the results of
48     *   the restore set lookup by the backup transport.  This parameter must not be
49     *   null.
50     * @param monitor a BackupManagerMonitor object will supply data about important events.
51     * @return Zero on success, nonzero on error.  The observer's restoreSetsAvailable()
52     *   method will only be called if this method returned zero.
53     */
54    public int getAvailableRestoreSets(RestoreObserver observer, BackupManagerMonitor monitor) {
55        int err = -1;
56        RestoreObserverWrapper obsWrapper = new RestoreObserverWrapper(mContext, observer);
57        BackupManagerMonitorWrapper monitorWrapper = monitor == null
58                ? null
59                : new BackupManagerMonitorWrapper(monitor);
60        try {
61            err = mBinder.getAvailableRestoreSets(obsWrapper, monitorWrapper);
62        } catch (RemoteException e) {
63            Log.d(TAG, "Can't contact server to get available sets");
64        }
65        return err;
66    }
67
68    /**
69     * Ask the current transport what the available restore sets are.
70     *
71     * @param observer a RestoreObserver object whose restoreSetsAvailable() method will
72     *   be called on the application's main thread in order to supply the results of
73     *   the restore set lookup by the backup transport.  This parameter must not be
74     *   null.
75     * @return Zero on success, nonzero on error.  The observer's restoreSetsAvailable()
76     *   method will only be called if this method returned zero.
77     */
78    public int getAvailableRestoreSets(RestoreObserver observer) {
79        return getAvailableRestoreSets(observer, null);
80    }
81
82    /**
83     * Restore the given set onto the device, replacing the current data of any app
84     * contained in the restore set with the data previously backed up.
85     *
86     * <p>Callers must hold the android.permission.BACKUP permission to use this method.
87     *
88     * @return Zero on success; nonzero on error.  The observer will only receive
89     *   progress callbacks if this method returned zero.
90     * @param token The token from {@link #getAvailableRestoreSets()} corresponding to
91     *   the restore set that should be used.
92     * @param observer If non-null, this binder points to an object that will receive
93     *   progress callbacks during the restore operation.
94     * @param monitor If non-null, this binder points to an object that will receive
95     *   progress callbacks during the restore operation.
96     */
97    public int restoreAll(long token, RestoreObserver observer, BackupManagerMonitor monitor) {
98        int err = -1;
99        if (mObserver != null) {
100            Log.d(TAG, "restoreAll() called during active restore");
101            return -1;
102        }
103        mObserver = new RestoreObserverWrapper(mContext, observer);
104        BackupManagerMonitorWrapper monitorWrapper = monitor == null
105                ? null
106                : new BackupManagerMonitorWrapper(monitor);
107        try {
108            err = mBinder.restoreAll(token, mObserver, monitorWrapper);
109        } catch (RemoteException e) {
110            Log.d(TAG, "Can't contact server to restore");
111        }
112        return err;
113    }
114
115    /**
116     * Restore the given set onto the device, replacing the current data of any app
117     * contained in the restore set with the data previously backed up.
118     *
119     * <p>Callers must hold the android.permission.BACKUP permission to use this method.
120     *
121     * @return Zero on success; nonzero on error.  The observer will only receive
122     *   progress callbacks if this method returned zero.
123     * @param token The token from {@link #getAvailableRestoreSets()} corresponding to
124     *   the restore set that should be used.
125     * @param observer If non-null, this binder points to an object that will receive
126     *   progress callbacks during the restore operation.
127     */
128    public int restoreAll(long token, RestoreObserver observer) {
129        return restoreAll(token, observer, null);
130    }
131
132    /**
133     * Restore select packages from the given set onto the device, replacing the
134     * current data of any app contained in the set with the data previously
135     * backed up.
136     *
137     * <p>Callers must hold the android.permission.BACKUP permission to use this method.
138     *
139     * @return Zero on success, nonzero on error. The observer will only receive
140     *   progress callbacks if this method returned zero.
141     * @param token The token from {@link getAvailableRestoreSets()} corresponding to
142     *   the restore set that should be used.
143     * @param observer If non-null, this binder points to an object that will receive
144     *   progress callbacks during the restore operation.
145     * @param monitor If non-null, this binder points to an object that will receive
146     *   progress callbacks during the restore operation.
147     * @param packages The set of packages for which to attempt a restore.  Regardless of
148     *   the contents of the actual back-end dataset named by {@code token}, only
149     *   applications mentioned in this list will have their data restored.
150     *
151     * @hide
152     */
153    public int restoreSome(long token, RestoreObserver observer, BackupManagerMonitor monitor,
154            String[] packages) {
155        int err = -1;
156        if (mObserver != null) {
157            Log.d(TAG, "restoreAll() called during active restore");
158            return -1;
159        }
160        mObserver = new RestoreObserverWrapper(mContext, observer);
161        BackupManagerMonitorWrapper monitorWrapper = monitor == null
162                ? null
163                : new BackupManagerMonitorWrapper(monitor);
164        try {
165            err = mBinder.restoreSome(token, mObserver, monitorWrapper, packages);
166        } catch (RemoteException e) {
167            Log.d(TAG, "Can't contact server to restore packages");
168        }
169        return err;
170    }
171
172    /**
173     * Restore select packages from the given set onto the device, replacing the
174     * current data of any app contained in the set with the data previously
175     * backed up.
176     *
177     * <p>Callers must hold the android.permission.BACKUP permission to use this method.
178     *
179     * @return Zero on success, nonzero on error. The observer will only receive
180     *   progress callbacks if this method returned zero.
181     * @param token The token from {@link getAvailableRestoreSets()} corresponding to
182     *   the restore set that should be used.
183     * @param observer If non-null, this binder points to an object that will receive
184     *   progress callbacks during the restore operation.
185     * @param packages The set of packages for which to attempt a restore.  Regardless of
186     *   the contents of the actual back-end dataset named by {@code token}, only
187     *   applications mentioned in this list will have their data restored.
188     *
189     * @hide
190     */
191    public int restoreSome(long token, RestoreObserver observer, String[] packages) {
192        return restoreSome(token, observer, null, packages);
193    }
194
195    /**
196     * Restore a single application from backup.  The data will be restored from the
197     * current backup dataset if the given package has stored data there, or from
198     * the dataset used during the last full device setup operation if the current
199     * backup dataset has no matching data.  If no backup data exists for this package
200     * in either source, a nonzero value will be returned.
201     *
202     * @return Zero on success; nonzero on error.  The observer will only receive
203     *   progress callbacks if this method returned zero.
204     * @param packageName The name of the package whose data to restore.  If this is
205     *   not the name of the caller's own package, then the android.permission.BACKUP
206     *   permission must be held.
207     * @param observer If non-null, this binder points to an object that will receive
208     *   progress callbacks during the restore operation.
209     *
210     * @param monitor If non-null, this binder points to an object that will receive
211     *   event callbacks during the restore operation.
212     */
213    public int restorePackage(String packageName, RestoreObserver observer,
214            BackupManagerMonitor monitor) {
215        int err = -1;
216        if (mObserver != null) {
217            Log.d(TAG, "restorePackage() called during active restore");
218            return -1;
219        }
220        mObserver = new RestoreObserverWrapper(mContext, observer);
221        BackupManagerMonitorWrapper monitorWrapper = monitor == null
222                ? null
223                : new BackupManagerMonitorWrapper(monitor);
224        try {
225            err = mBinder.restorePackage(packageName, mObserver, monitorWrapper);
226        } catch (RemoteException e) {
227            Log.d(TAG, "Can't contact server to restore package");
228        }
229        return err;
230    }
231
232
233    /**
234     * Restore a single application from backup.  The data will be restored from the
235     * current backup dataset if the given package has stored data there, or from
236     * the dataset used during the last full device setup operation if the current
237     * backup dataset has no matching data.  If no backup data exists for this package
238     * in either source, a nonzero value will be returned.
239     *
240     * @return Zero on success; nonzero on error.  The observer will only receive
241     *   progress callbacks if this method returned zero.
242     * @param packageName The name of the package whose data to restore.  If this is
243     *   not the name of the caller's own package, then the android.permission.BACKUP
244     *   permission must be held.
245     * @param observer If non-null, this binder points to an object that will receive
246     *   progress callbacks during the restore operation.
247     */
248    public int restorePackage(String packageName, RestoreObserver observer) {
249        return restorePackage(packageName, observer, null);
250    }
251
252    /**
253     * End this restore session.  After this method is called, the RestoreSession
254     * object is no longer valid.
255     *
256     * <p><b>Note:</b> The caller <i>must</i> invoke this method to end the restore session,
257     *   even if {@link #restorePackage(String, RestoreObserver)} failed.
258     */
259    public void endRestoreSession() {
260        try {
261            mBinder.endRestoreSession();
262        } catch (RemoteException e) {
263            Log.d(TAG, "Can't contact server to get available sets");
264        } finally {
265            mBinder = null;
266        }
267    }
268
269    /*
270     * Nonpublic implementation here
271     */
272
273    RestoreSession(Context context, IRestoreSession binder) {
274        mContext = context;
275        mBinder = binder;
276    }
277
278    /*
279     * We wrap incoming binder calls with a private class implementation that
280     * redirects them into main-thread actions.  This serializes the restore
281     * progress callbacks nicely within the usual main-thread lifecycle pattern.
282     */
283    private class RestoreObserverWrapper extends IRestoreObserver.Stub {
284        final Handler mHandler;
285        final RestoreObserver mAppObserver;
286
287        static final int MSG_RESTORE_STARTING = 1;
288        static final int MSG_UPDATE = 2;
289        static final int MSG_RESTORE_FINISHED = 3;
290        static final int MSG_RESTORE_SETS_AVAILABLE = 4;
291
292        RestoreObserverWrapper(Context context, RestoreObserver appObserver) {
293            mHandler = new Handler(context.getMainLooper()) {
294                @Override
295                public void handleMessage(Message msg) {
296                    switch (msg.what) {
297                    case MSG_RESTORE_STARTING:
298                        mAppObserver.restoreStarting(msg.arg1);
299                        break;
300                    case MSG_UPDATE:
301                        mAppObserver.onUpdate(msg.arg1, (String)msg.obj);
302                        break;
303                    case MSG_RESTORE_FINISHED:
304                        mAppObserver.restoreFinished(msg.arg1);
305                        break;
306                    case MSG_RESTORE_SETS_AVAILABLE:
307                        mAppObserver.restoreSetsAvailable((RestoreSet[])msg.obj);
308                        break;
309                    }
310                }
311            };
312            mAppObserver = appObserver;
313        }
314
315        // Binder calls into this object just enqueue on the main-thread handler
316        public void restoreSetsAvailable(RestoreSet[] result) {
317            mHandler.sendMessage(
318                    mHandler.obtainMessage(MSG_RESTORE_SETS_AVAILABLE, result));
319        }
320
321        public void restoreStarting(int numPackages) {
322            mHandler.sendMessage(
323                    mHandler.obtainMessage(MSG_RESTORE_STARTING, numPackages, 0));
324        }
325
326        public void onUpdate(int nowBeingRestored, String currentPackage) {
327            mHandler.sendMessage(
328                    mHandler.obtainMessage(MSG_UPDATE, nowBeingRestored, 0, currentPackage));
329        }
330
331        public void restoreFinished(int error) {
332            mHandler.sendMessage(
333                    mHandler.obtainMessage(MSG_RESTORE_FINISHED, error, 0));
334        }
335    }
336
337    private class BackupManagerMonitorWrapper extends IBackupManagerMonitor.Stub {
338        final BackupManagerMonitor mMonitor;
339
340        BackupManagerMonitorWrapper(BackupManagerMonitor monitor) {
341            mMonitor = monitor;
342        }
343
344        @Override
345        public void onEvent(final Bundle event) throws RemoteException {
346            mMonitor.onEvent(event);
347        }
348    }
349}
350