11c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate/*
21c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate * Copyright (C) 2010 The Android Open Source Project
31c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate *
41c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate * Licensed under the Apache License, Version 2.0 (the "License");
51c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate * you may not use this file except in compliance with the License.
61c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate * You may obtain a copy of the License at
71c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate *
81c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate *      http://www.apache.org/licenses/LICENSE-2.0
91c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate *
101c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate * Unless required by applicable law or agreed to in writing, software
111c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate * distributed under the License is distributed on an "AS IS" BASIS,
121c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
131c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate * See the License for the specific language governing permissions and
141c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate * limitations under the License.
151c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate */
161c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate
171c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tatepackage com.example.android.backuprestore;
181c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate
191c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tateimport android.app.backup.BackupAgent;
201c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tateimport android.app.backup.BackupDataInput;
211c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tateimport android.app.backup.BackupDataOutput;
221c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tateimport android.os.ParcelFileDescriptor;
231c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate
241c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tateimport java.io.ByteArrayInputStream;
251c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tateimport java.io.ByteArrayOutputStream;
261c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tateimport java.io.DataInputStream;
271c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tateimport java.io.DataOutputStream;
281c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tateimport java.io.File;
291c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tateimport java.io.FileInputStream;
301c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tateimport java.io.FileOutputStream;
311c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tateimport java.io.IOException;
321c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tateimport java.io.RandomAccessFile;
331c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate
341c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate/**
351c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate * This is the backup/restore agent class for the BackupRestore sample
361c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate * application.  This particular agent illustrates using the backup and
371c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate * restore APIs directly, without taking advantage of any helper classes.
381c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate */
391c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tatepublic class ExampleAgent extends BackupAgent {
401c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate    /**
411c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate     * We put a simple version number into the state files so that we can
421c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate     * tell properly how to read "old" versions if at some point we want
431c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate     * to change what data we back up and how we store the state blob.
441c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate     */
451c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate    static final int AGENT_VERSION = 1;
461c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate
471c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate    /**
481c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate     * Pick an arbitrary string to use as the "key" under which the
491c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate     * data is backed up.  This key identifies different data records
501c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate     * within this one application's data set.  Since we only maintain
511c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate     * one piece of data we don't need to distinguish, so we just pick
521c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate     * some arbitrary tag to use.
531c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate     */
541c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate    static final String APP_DATA_KEY = "alldata";
551c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate
561c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate    /** The app's current data, read from the live disk file */
571c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate    boolean mAddMayo;
581c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate    boolean mAddTomato;
591c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate    int mFilling;
601c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate
611c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate    /** The location of the application's persistent data file */
621c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate    File mDataFile;
631c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate
641c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate    /** For convenience, we set up the File object for the app's data on creation */
651c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate    @Override
661c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate    public void onCreate() {
671c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate        mDataFile = new File(getFilesDir(), BackupRestoreActivity.DATA_FILE_NAME);
681c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate    }
691c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate
701c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate    /**
711c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate     * The set of data backed up by this application is very small: just
721c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate     * two booleans and an integer.  With such a simple dataset, it's
731c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate     * easiest to simply store a copy of the backed-up data as the state
741c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate     * blob describing the last dataset backed up.  The state file
751c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate     * contents can be anything; it is private to the agent class, and
761c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate     * is never stored off-device.
771c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate     *
781c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate     * <p>One thing that an application may wish to do is tag the state
791c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate     * blob contents with a version number.  This is so that if the
801c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate     * application is upgraded, the next time it attempts to do a backup,
811c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate     * it can detect that the last backup operation was performed by an
821c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate     * older version of the agent, and might therefore require different
831c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate     * handling.
841c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate     */
851c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate    @Override
861c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate    public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
871c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate            ParcelFileDescriptor newState) throws IOException {
881c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate        // First, get the current data from the application's file.  This
891c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate        // may throw an IOException, but in that case something has gone
901c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate        // badly wrong with the app's data on disk, and we do not want
911c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate        // to back up garbage data.  If we just let the exception go, the
921c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate        // Backup Manager will handle it and simply skip the current
931c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate        // backup operation.
941c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate        synchronized (BackupRestoreActivity.sDataLock) {
951c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate            RandomAccessFile file = new RandomAccessFile(mDataFile, "r");
961c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate            mFilling = file.readInt();
971c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate            mAddMayo = file.readBoolean();
981c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate            mAddTomato = file.readBoolean();
991c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate        }
1001c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate
1011c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate        // If the new state file descriptor is null, this is the first time
1021c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate        // a backup is being performed, so we know we have to write the
1031c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate        // data.  If there <em>is</em> a previous state blob, we want to
1041c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate        // double check whether the current data is actually different from
1051c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate        // our last backup, so that we can avoid transmitting redundant
1061c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate        // data to the storage backend.
1071c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate        boolean doBackup = (oldState == null);
1081c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate        if (!doBackup) {
1091c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate            doBackup = compareStateFile(oldState);
1101c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate        }
1111c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate
1121c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate        // If we decided that we do in fact need to write our dataset, go
1131c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate        // ahead and do that.  The way this agent backs up the data is to
1141c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate        // flatten it into a single buffer, then write that to the backup
1151c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate        // transport under the single key string.
1161c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate        if (doBackup) {
1171c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate            ByteArrayOutputStream bufStream = new ByteArrayOutputStream();
1181c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate
1191c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate            // We use a DataOutputStream to write structured data into
1201c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate            // the buffering stream
1211c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate            DataOutputStream outWriter = new DataOutputStream(bufStream);
1221c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate            outWriter.writeInt(mFilling);
1231c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate            outWriter.writeBoolean(mAddMayo);
1241c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate            outWriter.writeBoolean(mAddTomato);
1251c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate
1261c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate            // Okay, we've flattened the data for transmission.  Pull it
1271c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate            // out of the buffering stream object and send it off.
1281c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate            byte[] buffer = bufStream.toByteArray();
1291c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate            int len = buffer.length;
1301c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate            data.writeEntityHeader(APP_DATA_KEY, len);
1311c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate            data.writeEntityData(buffer, len);
1321c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate        }
1331c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate
1341c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate        // Finally, in all cases, we need to write the new state blob
1351c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate        writeStateFile(newState);
1361c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate    }
1371c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate
1381c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate    /**
1391c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate     * Helper routine - read a previous state file and decide whether to
1401c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate     * perform a backup based on its contents.
1411c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate     *
1421c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate     * @return <code>true</code> if the application's data has changed since
1431c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate     *   the last backup operation; <code>false</code> otherwise.
1441c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate     */
1451c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate    boolean compareStateFile(ParcelFileDescriptor oldState) {
1461c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate        FileInputStream instream = new FileInputStream(oldState.getFileDescriptor());
1471c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate        DataInputStream in = new DataInputStream(instream);
1481c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate
1491c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate        try {
1501c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate            int stateVersion = in.readInt();
1511c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate            if (stateVersion > AGENT_VERSION) {
1521c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate                // Whoops; the last version of the app that backed up
1531c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate                // data on this device was <em>newer</em> than the current
1541c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate                // version -- the user has downgraded.  That's problematic.
1551c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate                // In this implementation, we recover by simply rewriting
1561c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate                // the backup.
1571c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate                return true;
1581c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate            }
1591c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate
1601c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate            // The state data we store is just a mirror of the app's data;
1611c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate            // read it from the state file then return 'true' if any of
1621c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate            // it differs from the current data.
1631c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate            int lastFilling = in.readInt();
1641c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate            boolean lastMayo = in.readBoolean();
1651c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate            boolean lastTomato = in.readBoolean();
1661c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate
1671c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate            return (lastFilling != mFilling)
1681c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate                    || (lastTomato != mAddTomato)
1691c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate                    || (lastMayo != mAddMayo);
1701c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate        } catch (IOException e) {
1711c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate            // If something went wrong reading the state file, be safe
1721c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate            // and back up the data again.
1731c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate            return true;
1741c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate        }
1751c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate    }
1761c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate
1771c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate    /**
1781c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate     * Write out the new state file:  the version number, followed by the
1791c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate     * three bits of data as we sent them off to the backup transport.
1801c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate     */
1811c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate    void writeStateFile(ParcelFileDescriptor stateFile) throws IOException {
1821c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate        FileOutputStream outstream = new FileOutputStream(stateFile.getFileDescriptor());
1831c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate        DataOutputStream out = new DataOutputStream(outstream);
1841c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate
1851c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate        out.writeInt(AGENT_VERSION);
1861c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate        out.writeInt(mFilling);
1871c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate        out.writeBoolean(mAddMayo);
1881c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate        out.writeBoolean(mAddTomato);
1891c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate    }
1901c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate
1911c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate    /**
1921c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate     * This application does not do any "live" restores of its own data,
1931c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate     * so the only time a restore will happen is when the application is
1941c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate     * installed.  This means that the activity itself is not going to
1951c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate     * be running while we change its data out from under it.  That, in
1961c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate     * turn, means that there is no need to send out any sort of notification
1971c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate     * of the new data:  we only need to read the data from the stream
1981c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate     * provided here, build the application's new data file, and then
1991c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate     * write our new backup state blob that will be consulted at the next
2001c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate     * backup operation.
2011c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate     *
2021c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate     * <p>We don't bother checking the versionCode of the app who originated
2031c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate     * the data because we have never revised the backup data format.  If
2041c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate     * we had, the 'appVersionCode' parameter would tell us how we should
2051c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate     * interpret the data we're about to read.
2061c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate     */
2071c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate    @Override
2081c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate    public void onRestore(BackupDataInput data, int appVersionCode,
2091c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate            ParcelFileDescriptor newState) throws IOException {
2101c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate        // We should only see one entity in the data stream, but the safest
2111c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate        // way to consume it is using a while() loop
2121c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate        while (data.readNextHeader()) {
2131c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate            String key = data.getKey();
2141c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate            int dataSize = data.getDataSize();
2151c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate
2161c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate            if (APP_DATA_KEY.equals(key)) {
2171c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate                // It's our saved data, a flattened chunk of data all in
2181c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate                // one buffer.  Use some handy structured I/O classes to
2191c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate                // extract it.
2201c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate                byte[] dataBuf = new byte[dataSize];
2211c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate                data.readEntityData(dataBuf, 0, dataSize);
2221c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate                ByteArrayInputStream baStream = new ByteArrayInputStream(dataBuf);
2231c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate                DataInputStream in = new DataInputStream(baStream);
2241c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate
2251c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate                mFilling = in.readInt();
2261c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate                mAddMayo = in.readBoolean();
2271c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate                mAddTomato = in.readBoolean();
2281c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate
2291c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate                // Now we are ready to construct the app's data file based
2301c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate                // on the data we are restoring from.
2311c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate                synchronized (BackupRestoreActivity.sDataLock) {
2321c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate                    RandomAccessFile file = new RandomAccessFile(mDataFile, "rw");
2331c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate                    file.setLength(0L);
2341c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate                    file.writeInt(mFilling);
2351c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate                    file.writeBoolean(mAddMayo);
2361c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate                    file.writeBoolean(mAddTomato);
2371c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate                }
2381c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate            } else {
2391c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate                // Curious!  This entity is data under a key we do not
2401c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate                // understand how to process.  Just skip it.
2411c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate                data.skipEntityData();
2421c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate            }
2431c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate        }
2441c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate
2451c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate        // The last thing to do is write the state blob that describes the
2461c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate        // app's data as restored from backup.
2471c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate        writeStateFile(newState);
2481c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate    }
2491c0a20aeeb089971a624c102435755ba9ae74aabChristopher Tate}
250