RestoreSession.java revision 9c3cee9824026764275e4d84ba9b5d9fdc5da690
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.app.backup.RestoreObserver;
20import android.app.backup.RestoreSet;
21import android.app.backup.IRestoreObserver;
22import android.app.backup.IRestoreSession;
23import android.content.Context;
24import android.os.Handler;
25import android.os.Message;
26import android.os.RemoteException;
27import android.util.Log;
28
29/**
30 * Interface for managing a restore session.
31 * @hide
32 */
33public class RestoreSession {
34    static final String TAG = "RestoreSession";
35
36    final Context mContext;
37    IRestoreSession mBinder;
38    RestoreObserverWrapper mObserver = null;
39
40    /**
41     * Ask the current transport what the available restore sets are.
42     *
43     * @return A bundle containing two elements:  an int array under the key
44     *   "tokens" whose entries are a transport-private identifier for each backup set;
45     *   and a String array under the key "names" whose entries are the user-meaningful
46     *   text corresponding to the backup sets at each index in the tokens array.
47     *   On error, returns null.
48     */
49    public RestoreSet[] getAvailableRestoreSets() {
50        try {
51            return mBinder.getAvailableRestoreSets();
52        } catch (RemoteException e) {
53            Log.d(TAG, "Can't contact server to get available sets");
54            return null;
55        }
56    }
57
58    /**
59     * Restore the given set onto the device, replacing the current data of any app
60     * contained in the restore set with the data previously backed up.
61     *
62     * <p>Callers must hold the android.permission.BACKUP permission to use this method.
63     *
64     * @return Zero on success; nonzero on error.  The observer will only receive
65     *   progress callbacks if this method returned zero.
66     * @param token The token from {@link #getAvailableRestoreSets()} corresponding to
67     *   the restore set that should be used.
68     * @param observer If non-null, this binder points to an object that will receive
69     *   progress callbacks during the restore operation.
70     */
71    public int restoreAll(long token, RestoreObserver observer) {
72        int err = -1;
73        if (mObserver != null) {
74            Log.d(TAG, "restoreAll() called during active restore");
75            return -1;
76        }
77        mObserver = new RestoreObserverWrapper(mContext, observer);
78        try {
79            err = mBinder.restoreAll(token, mObserver);
80        } catch (RemoteException e) {
81            Log.d(TAG, "Can't contact server to restore");
82        }
83        return err;
84    }
85
86    /**
87     * Restore a single application from backup.  The data will be restored from the
88     * current backup dataset if the given package has stored data there, or from
89     * the dataset used during the last full device setup operation if the current
90     * backup dataset has no matching data.  If no backup data exists for this package
91     * in either source, a nonzero value will be returned.
92     *
93     * @return Zero on success; nonzero on error.  The observer will only receive
94     *   progress callbacks if this method returned zero.
95     * @param packageName The name of the package whose data to restore.  If this is
96     *   not the name of the caller's own package, then the android.permission.BACKUP
97     *   permission must be held.
98     * @param observer If non-null, this binder points to an object that will receive
99     *   progress callbacks during the restore operation.
100     */
101    public int restorePackage(String packageName, RestoreObserver observer) {
102        int err = -1;
103        if (mObserver != null) {
104            Log.d(TAG, "restorePackage() called during active restore");
105            return -1;
106        }
107        mObserver = new RestoreObserverWrapper(mContext, observer);
108        try {
109            err = mBinder.restorePackage(packageName, mObserver);
110        } catch (RemoteException e) {
111            Log.d(TAG, "Can't contact server to restore package");
112        }
113        return err;
114    }
115
116    /**
117     * End this restore session.  After this method is called, the RestoreSession
118     * object is no longer valid.
119     *
120     * <p><b>Note:</b> The caller <i>must</i> invoke this method to end the restore session,
121     *   even if {@link #restorePackage(String, RestoreObserver)} failed.
122     */
123    public void endRestoreSession() {
124        try {
125            mBinder.endRestoreSession();
126        } catch (RemoteException e) {
127            Log.d(TAG, "Can't contact server to get available sets");
128        } finally {
129            mBinder = null;
130        }
131    }
132
133    /*
134     * Nonpublic implementation here
135     */
136
137    RestoreSession(Context context, IRestoreSession binder) {
138        mContext = context;
139        mBinder = binder;
140    }
141
142    /*
143     * We wrap incoming binder calls with a private class implementation that
144     * redirects them into main-thread actions.  This serializes the restore
145     * progress callbacks nicely within the usual main-thread lifecycle pattern.
146     */
147    private class RestoreObserverWrapper extends IRestoreObserver.Stub {
148        final Handler mHandler;
149        final RestoreObserver mAppObserver;
150
151        static final int MSG_RESTORE_STARTING = 1;
152        static final int MSG_UPDATE = 2;
153        static final int MSG_RESTORE_FINISHED = 3;
154
155        RestoreObserverWrapper(Context context, RestoreObserver appObserver) {
156            mHandler = new Handler(context.getMainLooper()) {
157                @Override
158                public void handleMessage(Message msg) {
159                    switch (msg.what) {
160                    case MSG_RESTORE_STARTING:
161                        mAppObserver.restoreStarting(msg.arg1);
162                        break;
163                    case MSG_UPDATE:
164                        mAppObserver.onUpdate(msg.arg1, (String)msg.obj);
165                        break;
166                    case MSG_RESTORE_FINISHED:
167                        mAppObserver.restoreFinished(msg.arg1);
168                        break;
169                    }
170                }
171            };
172            mAppObserver = appObserver;
173        }
174
175        // Binder calls into this object just enqueue on the main-thread handler
176        public void restoreStarting(int numPackages) {
177            mHandler.sendMessage(
178                    mHandler.obtainMessage(MSG_RESTORE_STARTING, numPackages, 0));
179        }
180
181        public void onUpdate(int nowBeingRestored, String currentPackage) {
182            mHandler.sendMessage(
183                    mHandler.obtainMessage(MSG_UPDATE, nowBeingRestored, 0, currentPackage));
184        }
185
186        public void restoreFinished(int error) {
187            mHandler.sendMessage(
188                    mHandler.obtainMessage(MSG_RESTORE_FINISHED, error, 0));
189        }
190    }
191}
192