161cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon/*
261cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon * Copyright (C) 2015 The Android Open Source Project
361cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon *
461cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon * Licensed under the Apache License, Version 2.0 (the "License");
561cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon * you may not use this file except in compliance with the License.
661cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon * You may obtain a copy of the License at
761cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon *
861cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon *      http://www.apache.org/licenses/LICENSE-2.0
961cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon *
1061cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon * Unless required by applicable law or agreed to in writing, software
1161cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon * distributed under the License is distributed on an "AS IS" BASIS,
1261cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1361cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon * See the License for the specific language governing permissions and
1461cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon * limitations under the License
1561cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon */
1661cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon
1761cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordonpackage com.android.providers.calllogbackup;
1861cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon
1961cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordonimport android.app.backup.BackupAgent;
2061cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordonimport android.app.backup.BackupDataInput;
2161cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordonimport android.app.backup.BackupDataOutput;
2261cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordonimport android.content.ComponentName;
2361cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordonimport android.content.ContentResolver;
2461cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordonimport android.database.Cursor;
2561cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordonimport android.os.ParcelFileDescriptor;
2661cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordonimport android.os.UserHandle;
2761cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordonimport android.os.UserManager;
2861cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordonimport android.provider.CallLog;
2961cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordonimport android.provider.CallLog.Calls;
3061cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordonimport android.telecom.PhoneAccountHandle;
3161cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordonimport android.util.Log;
3261cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon
3361cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordonimport com.android.internal.annotations.VisibleForTesting;
3461cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon
3561cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordonimport java.io.BufferedOutputStream;
3661cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordonimport java.io.ByteArrayInputStream;
3761cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordonimport java.io.ByteArrayOutputStream;
3861cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordonimport java.io.DataInput;
3961cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordonimport java.io.DataInputStream;
4061cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordonimport java.io.DataOutput;
4161cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordonimport java.io.DataOutputStream;
4261cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordonimport java.io.EOFException;
4361cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordonimport java.io.FileInputStream;
4461cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordonimport java.io.FileOutputStream;
4561cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordonimport java.io.IOException;
4661cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordonimport java.util.LinkedList;
4761cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordonimport java.util.List;
4861cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordonimport java.util.SortedSet;
4961cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordonimport java.util.TreeSet;
5061cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon
5161cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon/**
5261cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon * Call log backup agent.
5361cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon */
5461cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordonpublic class CallLogBackupAgent extends BackupAgent {
5561cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon
5661cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon    @VisibleForTesting
5761cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon    static class CallLogBackupState {
5861cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        int version;
5961cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        SortedSet<Integer> callIds;
6061cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon    }
6161cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon
6261cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon    @VisibleForTesting
6361cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon    static class Call {
6461cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        int id;
6561cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        long date;
6661cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        long duration;
6761cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        String number;
6861cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        int type;
6961cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        int numberPresentation;
7061cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        String accountComponentName;
7161cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        String accountId;
7261cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        String accountAddress;
7361cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        Long dataUsage;
7461cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        int features;
7561cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon
7661cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        @Override
7761cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        public String toString() {
7861cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon            if (isDebug()) {
7961cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon                return  "[" + id + ", account: [" + accountComponentName + " : " + accountId +
8061cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon                    "]," + number + ", " + date + "]";
8161cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon            } else {
8261cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon                return "[" + id + "]";
8361cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon            }
8461cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        }
8561cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon    }
8661cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon
87f128d20ada7474e5714f81533b8f77e915315c1aSantos Cordon    static class OEMData {
88f128d20ada7474e5714f81533b8f77e915315c1aSantos Cordon        String namespace;
89f128d20ada7474e5714f81533b8f77e915315c1aSantos Cordon        byte[] bytes;
90f128d20ada7474e5714f81533b8f77e915315c1aSantos Cordon
91f128d20ada7474e5714f81533b8f77e915315c1aSantos Cordon        public OEMData(String namespace, byte[] bytes) {
92f128d20ada7474e5714f81533b8f77e915315c1aSantos Cordon            this.namespace = namespace;
93f128d20ada7474e5714f81533b8f77e915315c1aSantos Cordon            this.bytes = bytes == null ? ZERO_BYTE_ARRAY : bytes;
94f128d20ada7474e5714f81533b8f77e915315c1aSantos Cordon        }
95f128d20ada7474e5714f81533b8f77e915315c1aSantos Cordon    }
96f128d20ada7474e5714f81533b8f77e915315c1aSantos Cordon
9761cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon    private static final String TAG = "CallLogBackupAgent";
9861cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon
9961cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon    /** Current version of CallLogBackup. Used to track the backup format. */
10061cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon    @VisibleForTesting
101f128d20ada7474e5714f81533b8f77e915315c1aSantos Cordon    static final int VERSION = 1002;
10261cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon    /** Version indicating that there exists no previous backup entry. */
10361cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon    @VisibleForTesting
10461cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon    static final int VERSION_NO_PREVIOUS_STATE = 0;
10561cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon
106f128d20ada7474e5714f81533b8f77e915315c1aSantos Cordon    static final String NO_OEM_NAMESPACE = "no-oem-namespace";
107f128d20ada7474e5714f81533b8f77e915315c1aSantos Cordon
108f128d20ada7474e5714f81533b8f77e915315c1aSantos Cordon    static final byte[] ZERO_BYTE_ARRAY = new byte[0];
109f128d20ada7474e5714f81533b8f77e915315c1aSantos Cordon
110f128d20ada7474e5714f81533b8f77e915315c1aSantos Cordon    static final int END_OEM_DATA_MARKER = 0x60061E;
111f128d20ada7474e5714f81533b8f77e915315c1aSantos Cordon
11261cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon    private static final String[] CALL_LOG_PROJECTION = new String[] {
11361cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        CallLog.Calls._ID,
11461cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        CallLog.Calls.DATE,
11561cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        CallLog.Calls.DURATION,
11661cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        CallLog.Calls.NUMBER,
11761cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        CallLog.Calls.TYPE,
11861cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        CallLog.Calls.COUNTRY_ISO,
11961cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        CallLog.Calls.GEOCODED_LOCATION,
12061cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        CallLog.Calls.NUMBER_PRESENTATION,
12161cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        CallLog.Calls.PHONE_ACCOUNT_COMPONENT_NAME,
12261cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        CallLog.Calls.PHONE_ACCOUNT_ID,
12361cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        CallLog.Calls.PHONE_ACCOUNT_ADDRESS,
12461cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        CallLog.Calls.DATA_USAGE,
12561cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        CallLog.Calls.FEATURES
12661cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon    };
12761cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon
12861cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon    /** ${inheritDoc} */
12961cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon    @Override
13061cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon    public void onBackup(ParcelFileDescriptor oldStateDescriptor, BackupDataOutput data,
13161cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon            ParcelFileDescriptor newStateDescriptor) throws IOException {
13261cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon
13361cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        // Get the list of the previous calls IDs which were backed up.
13461cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        DataInputStream dataInput = new DataInputStream(
13561cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon                new FileInputStream(oldStateDescriptor.getFileDescriptor()));
13661cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        final CallLogBackupState state;
13761cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        try {
13861cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon            state = readState(dataInput);
13961cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        } finally {
14061cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon            dataInput.close();
14161cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        }
14261cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon
14361cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        // Run the actual backup of data
14461cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        runBackup(state, data, getAllCallLogEntries());
14561cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon
14661cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        // Rewrite the backup state.
14761cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        DataOutputStream dataOutput = new DataOutputStream(new BufferedOutputStream(
14861cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon                new FileOutputStream(newStateDescriptor.getFileDescriptor())));
14961cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        try {
15061cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon            writeState(dataOutput, state);
15161cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        } finally {
15261cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon            dataOutput.close();
15361cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        }
15461cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon    }
15561cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon
15661cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon    /** ${inheritDoc} */
15761cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon    @Override
15861cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon    public void onRestore(BackupDataInput data, int appVersionCode, ParcelFileDescriptor newState)
15961cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon            throws IOException {
16061cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        if (isDebug()) {
16161cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon            Log.d(TAG, "Performing Restore");
16261cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        }
16361cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon
16461cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        while (data.readNextHeader()) {
16561cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon            Call call = readCallFromData(data);
16661cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon            if (call != null) {
16761cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon                writeCallToProvider(call);
16861cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon                if (isDebug()) {
16961cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon                    Log.d(TAG, "Restored call: " + call);
17061cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon                }
17161cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon            }
17261cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        }
17361cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon    }
17461cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon
17561cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon    @VisibleForTesting
17661cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon    void runBackup(CallLogBackupState state, BackupDataOutput data, Iterable<Call> calls) {
17761cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        SortedSet<Integer> callsToRemove = new TreeSet<>(state.callIds);
17861cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon
17961cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        // Loop through all the call log entries to identify:
18061cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        // (1) new calls
18161cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        // (2) calls which have been deleted.
18261cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        for (Call call : calls) {
18361cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon            if (!state.callIds.contains(call.id)) {
18461cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon
18561cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon                if (isDebug()) {
18661cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon                    Log.d(TAG, "Adding call to backup: " + call);
18761cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon                }
18861cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon
18961cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon                // This call new (not in our list from the last backup), lets back it up.
19061cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon                addCallToBackup(data, call);
19161cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon                state.callIds.add(call.id);
19261cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon            } else {
19361cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon                // This call still exists in the current call log so delete it from the
19461cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon                // "callsToRemove" set since we want to keep it.
19561cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon                callsToRemove.remove(call.id);
19661cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon            }
19761cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        }
19861cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon
19961cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        // Remove calls which no longer exist in the set.
20061cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        for (Integer i : callsToRemove) {
20161cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon            if (isDebug()) {
20261cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon                Log.d(TAG, "Removing call from backup: " + i);
20361cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon            }
20461cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon
20561cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon            removeCallFromBackup(data, i);
20661cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon            state.callIds.remove(i);
20761cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        }
20861cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon    }
20961cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon
21061cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon    private Iterable<Call> getAllCallLogEntries() {
21161cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        List<Call> calls = new LinkedList<>();
21261cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon
21361cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        // We use the API here instead of querying ContactsDatabaseHelper directly because
21461cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        // CallLogProvider has special locks in place for sychronizing when to read.  Using the APIs
21561cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        // gives us that for free.
21661cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        ContentResolver resolver = getContentResolver();
21761cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        Cursor cursor = resolver.query(
21861cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon                CallLog.Calls.CONTENT_URI, CALL_LOG_PROJECTION, null, null, null);
21961cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        if (cursor != null) {
22061cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon            try {
22161cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon                while (cursor.moveToNext()) {
22261cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon                    Call call = readCallFromCursor(cursor);
22361cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon                    if (call != null) {
22461cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon                        calls.add(call);
22561cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon                    }
22661cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon                }
22761cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon            } finally {
22861cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon                cursor.close();
22961cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon            }
23061cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        }
23161cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon
23261cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        return calls;
23361cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon    }
23461cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon
23561cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon    private void writeCallToProvider(Call call) {
23661cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        Long dataUsage = call.dataUsage == 0 ? null : call.dataUsage;
23761cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon
238755cc64c7ff675cbc6ee930b2afc690eab8e35dfSantos Cordon        PhoneAccountHandle handle = null;
239755cc64c7ff675cbc6ee930b2afc690eab8e35dfSantos Cordon        if (call.accountComponentName != null && call.accountId != null) {
240755cc64c7ff675cbc6ee930b2afc690eab8e35dfSantos Cordon            handle = new PhoneAccountHandle(
241755cc64c7ff675cbc6ee930b2afc690eab8e35dfSantos Cordon                    ComponentName.unflattenFromString(call.accountComponentName), call.accountId);
242755cc64c7ff675cbc6ee930b2afc690eab8e35dfSantos Cordon        }
24361cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        Calls.addCall(null /* CallerInfo */, this, call.number, call.numberPresentation, call.type,
24461cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon                call.features, handle, call.date, (int) call.duration,
245a172ae826f3e53c637d239a354acd0a0dd9f40beRoshan Pius                dataUsage, true /* addForAllUsers */, true /* is_read */);
24661cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon    }
24761cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon
24861cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon    @VisibleForTesting
24961cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon    CallLogBackupState readState(DataInput dataInput) throws IOException {
25061cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        CallLogBackupState state = new CallLogBackupState();
25161cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        state.callIds = new TreeSet<>();
25261cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon
25361cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        try {
25461cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon            // Read the version.
25561cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon            state.version = dataInput.readInt();
25661cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon
25761cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon            if (state.version >= 1) {
25861cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon                // Read the size.
25961cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon                int size = dataInput.readInt();
26061cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon
26161cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon                // Read all of the call IDs.
26261cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon                for (int i = 0; i < size; i++) {
26361cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon                    state.callIds.add(dataInput.readInt());
26461cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon                }
26561cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon            }
26661cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        } catch (EOFException e) {
26761cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon            state.version = VERSION_NO_PREVIOUS_STATE;
26861cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        }
26961cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon
27061cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        return state;
27161cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon    }
27261cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon
27361cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon    @VisibleForTesting
27461cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon    void writeState(DataOutput dataOutput, CallLogBackupState state)
27561cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon            throws IOException {
27661cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        // Write version first of all
27761cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        dataOutput.writeInt(VERSION);
27861cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon
27961cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        // [Version 1]
28061cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        // size + callIds
28161cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        dataOutput.writeInt(state.callIds.size());
28261cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        for (Integer i : state.callIds) {
28361cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon            dataOutput.writeInt(i);
28461cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        }
28561cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon    }
28661cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon
28761cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon    @VisibleForTesting
28861cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon    Call readCallFromData(BackupDataInput data) {
28961cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        final int callId;
29061cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        try {
29161cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon            callId = Integer.parseInt(data.getKey());
29261cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        } catch (NumberFormatException e) {
29361cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon            Log.e(TAG, "Unexpected key found in restore: " + data.getKey());
29461cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon            return null;
29561cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        }
29661cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon
29761cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        try {
29861cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon            byte [] byteArray = new byte[data.getDataSize()];
29961cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon            data.readEntityData(byteArray, 0, byteArray.length);
30061cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon            DataInputStream dataInput = new DataInputStream(new ByteArrayInputStream(byteArray));
30161cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon
30261cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon            Call call = new Call();
30361cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon            call.id = callId;
30461cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon
30561cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon            int version = dataInput.readInt();
30661cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon            if (version >= 1) {
30761cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon                call.date = dataInput.readLong();
30861cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon                call.duration = dataInput.readLong();
30961cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon                call.number = readString(dataInput);
31061cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon                call.type = dataInput.readInt();
31161cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon                call.numberPresentation = dataInput.readInt();
31261cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon                call.accountComponentName = readString(dataInput);
31361cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon                call.accountId = readString(dataInput);
31461cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon                call.accountAddress = readString(dataInput);
31561cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon                call.dataUsage = dataInput.readLong();
31661cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon                call.features = dataInput.readInt();
31761cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon            }
31861cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon
319f128d20ada7474e5714f81533b8f77e915315c1aSantos Cordon            if (version >= 1002) {
320f128d20ada7474e5714f81533b8f77e915315c1aSantos Cordon                String namespace = dataInput.readUTF();
321f128d20ada7474e5714f81533b8f77e915315c1aSantos Cordon                int length = dataInput.readInt();
322f128d20ada7474e5714f81533b8f77e915315c1aSantos Cordon                byte[] buffer = new byte[length];
323f128d20ada7474e5714f81533b8f77e915315c1aSantos Cordon                dataInput.read(buffer);
324f128d20ada7474e5714f81533b8f77e915315c1aSantos Cordon                readOEMDataForCall(call, new OEMData(namespace, buffer));
325f128d20ada7474e5714f81533b8f77e915315c1aSantos Cordon
326f128d20ada7474e5714f81533b8f77e915315c1aSantos Cordon                int marker = dataInput.readInt();
327f128d20ada7474e5714f81533b8f77e915315c1aSantos Cordon                if (marker != END_OEM_DATA_MARKER) {
328f128d20ada7474e5714f81533b8f77e915315c1aSantos Cordon                    Log.e(TAG, "Did not find END-OEM marker for call " + call.id);
329f128d20ada7474e5714f81533b8f77e915315c1aSantos Cordon                    // The marker does not match the expected value, ignore this call completely.
330f128d20ada7474e5714f81533b8f77e915315c1aSantos Cordon                    return null;
331f128d20ada7474e5714f81533b8f77e915315c1aSantos Cordon                }
332f128d20ada7474e5714f81533b8f77e915315c1aSantos Cordon            }
333f128d20ada7474e5714f81533b8f77e915315c1aSantos Cordon
33461cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon            return call;
33561cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        } catch (IOException e) {
33661cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon            Log.e(TAG, "Error reading call data for " + callId, e);
33761cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon            return null;
33861cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        }
33961cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon    }
34061cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon
34161cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon    private Call readCallFromCursor(Cursor cursor) {
34261cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        Call call = new Call();
34361cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        call.id = cursor.getInt(cursor.getColumnIndex(CallLog.Calls._ID));
34461cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        call.date = cursor.getLong(cursor.getColumnIndex(CallLog.Calls.DATE));
34561cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        call.duration = cursor.getLong(cursor.getColumnIndex(CallLog.Calls.DURATION));
34661cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        call.number = cursor.getString(cursor.getColumnIndex(CallLog.Calls.NUMBER));
34761cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        call.type = cursor.getInt(cursor.getColumnIndex(CallLog.Calls.TYPE));
34861cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        call.numberPresentation =
34961cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon                cursor.getInt(cursor.getColumnIndex(CallLog.Calls.NUMBER_PRESENTATION));
35061cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        call.accountComponentName =
35161cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon                cursor.getString(cursor.getColumnIndex(CallLog.Calls.PHONE_ACCOUNT_COMPONENT_NAME));
35261cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        call.accountId =
35361cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon                cursor.getString(cursor.getColumnIndex(CallLog.Calls.PHONE_ACCOUNT_ID));
35461cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        call.accountAddress =
35561cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon                cursor.getString(cursor.getColumnIndex(CallLog.Calls.PHONE_ACCOUNT_ADDRESS));
35661cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        call.dataUsage = cursor.getLong(cursor.getColumnIndex(CallLog.Calls.DATA_USAGE));
35761cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        call.features = cursor.getInt(cursor.getColumnIndex(CallLog.Calls.FEATURES));
35861cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        return call;
35961cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon    }
36061cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon
36161cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon    private void addCallToBackup(BackupDataOutput output, Call call) {
36261cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        ByteArrayOutputStream baos = new ByteArrayOutputStream();
36361cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        DataOutputStream data = new DataOutputStream(baos);
36461cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon
36561cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        try {
36661cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon            data.writeInt(VERSION);
36761cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon            data.writeLong(call.date);
36861cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon            data.writeLong(call.duration);
36961cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon            writeString(data, call.number);
37061cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon            data.writeInt(call.type);
37161cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon            data.writeInt(call.numberPresentation);
37261cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon            writeString(data, call.accountComponentName);
37361cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon            writeString(data, call.accountId);
37461cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon            writeString(data, call.accountAddress);
37561cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon            data.writeLong(call.dataUsage == null ? 0 : call.dataUsage);
37661cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon            data.writeInt(call.features);
377f128d20ada7474e5714f81533b8f77e915315c1aSantos Cordon
378f128d20ada7474e5714f81533b8f77e915315c1aSantos Cordon            OEMData oemData = getOEMDataForCall(call);
379f128d20ada7474e5714f81533b8f77e915315c1aSantos Cordon            data.writeUTF(oemData.namespace);
380f128d20ada7474e5714f81533b8f77e915315c1aSantos Cordon            data.writeInt(oemData.bytes.length);
381f128d20ada7474e5714f81533b8f77e915315c1aSantos Cordon            data.write(oemData.bytes);
3825fe9573b5dca5de8d789459eedb1df49497f3ae3Roshan Pius            data.writeInt(END_OEM_DATA_MARKER);
383f128d20ada7474e5714f81533b8f77e915315c1aSantos Cordon
38461cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon            data.flush();
38561cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon
38661cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon            output.writeEntityHeader(Integer.toString(call.id), baos.size());
38761cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon            output.writeEntityData(baos.toByteArray(), baos.size());
38861cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon
38961cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon            if (isDebug()) {
39061cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon                Log.d(TAG, "Wrote call to backup: " + call + " with byte array: " + baos);
39161cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon            }
39261cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        } catch (IOException e) {
39361cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon            Log.e(TAG, "Failed to backup call: " + call, e);
39461cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        }
39561cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon    }
39661cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon
397f128d20ada7474e5714f81533b8f77e915315c1aSantos Cordon    /**
398f128d20ada7474e5714f81533b8f77e915315c1aSantos Cordon     * Allows OEMs to provide proprietary data to backup along with the rest of the call log
399f128d20ada7474e5714f81533b8f77e915315c1aSantos Cordon     * data. Because there is no way to provide a Backup Transport implementation
400f128d20ada7474e5714f81533b8f77e915315c1aSantos Cordon     * nor peek into the data format of backup entries without system-level permissions, it is
401f128d20ada7474e5714f81533b8f77e915315c1aSantos Cordon     * not possible (at the time of this writing) to write CTS tests for this piece of code.
402f128d20ada7474e5714f81533b8f77e915315c1aSantos Cordon     * It is, therefore, important that if you alter this portion of code that you
403f128d20ada7474e5714f81533b8f77e915315c1aSantos Cordon     * test backup and restore of call log is working as expected; ideally this would be tested by
404f128d20ada7474e5714f81533b8f77e915315c1aSantos Cordon     * backing up and restoring between two different Android phone devices running M+.
405f128d20ada7474e5714f81533b8f77e915315c1aSantos Cordon     */
406f128d20ada7474e5714f81533b8f77e915315c1aSantos Cordon    private OEMData getOEMDataForCall(Call call) {
407f128d20ada7474e5714f81533b8f77e915315c1aSantos Cordon        return new OEMData(NO_OEM_NAMESPACE, ZERO_BYTE_ARRAY);
408f128d20ada7474e5714f81533b8f77e915315c1aSantos Cordon
409f128d20ada7474e5714f81533b8f77e915315c1aSantos Cordon        // OEMs that want to add their own proprietary data to call log backup should replace the
410f128d20ada7474e5714f81533b8f77e915315c1aSantos Cordon        // code above with their own namespace and add any additional data they need.
411f128d20ada7474e5714f81533b8f77e915315c1aSantos Cordon        // Versioning and size-prefixing the data should be done here as needed.
412f128d20ada7474e5714f81533b8f77e915315c1aSantos Cordon        //
413f128d20ada7474e5714f81533b8f77e915315c1aSantos Cordon        // Example:
414f128d20ada7474e5714f81533b8f77e915315c1aSantos Cordon
415f128d20ada7474e5714f81533b8f77e915315c1aSantos Cordon        /*
416f128d20ada7474e5714f81533b8f77e915315c1aSantos Cordon        ByteArrayOutputStream baos = new ByteArrayOutputStream();
417f128d20ada7474e5714f81533b8f77e915315c1aSantos Cordon        DataOutputStream data = new DataOutputStream(baos);
418f128d20ada7474e5714f81533b8f77e915315c1aSantos Cordon
419f128d20ada7474e5714f81533b8f77e915315c1aSantos Cordon        String customData1 = "Generic OEM";
420f128d20ada7474e5714f81533b8f77e915315c1aSantos Cordon        int customData2 = 42;
421f128d20ada7474e5714f81533b8f77e915315c1aSantos Cordon
422f128d20ada7474e5714f81533b8f77e915315c1aSantos Cordon        // Write a version for the data
423f128d20ada7474e5714f81533b8f77e915315c1aSantos Cordon        data.writeInt(OEM_DATA_VERSION);
424f128d20ada7474e5714f81533b8f77e915315c1aSantos Cordon
425f128d20ada7474e5714f81533b8f77e915315c1aSantos Cordon        // Write the data and flush
426f128d20ada7474e5714f81533b8f77e915315c1aSantos Cordon        data.writeUTF(customData1);
427f128d20ada7474e5714f81533b8f77e915315c1aSantos Cordon        data.writeInt(customData2);
428f128d20ada7474e5714f81533b8f77e915315c1aSantos Cordon        data.flush();
429f128d20ada7474e5714f81533b8f77e915315c1aSantos Cordon
430f128d20ada7474e5714f81533b8f77e915315c1aSantos Cordon        String oemNamespace = "com.oem.namespace";
431f128d20ada7474e5714f81533b8f77e915315c1aSantos Cordon        return new OEMData(oemNamespace, baos.toByteArray());
432f128d20ada7474e5714f81533b8f77e915315c1aSantos Cordon        */
433f128d20ada7474e5714f81533b8f77e915315c1aSantos Cordon    }
434f128d20ada7474e5714f81533b8f77e915315c1aSantos Cordon
435f128d20ada7474e5714f81533b8f77e915315c1aSantos Cordon    /**
436f128d20ada7474e5714f81533b8f77e915315c1aSantos Cordon     * Allows OEMs to read their own proprietary data when doing a call log restore. It is important
437f128d20ada7474e5714f81533b8f77e915315c1aSantos Cordon     * that the implementation verify the namespace of the data matches their expected value before
438f128d20ada7474e5714f81533b8f77e915315c1aSantos Cordon     * attempting to read the data or else you may risk reading invalid data.
439f128d20ada7474e5714f81533b8f77e915315c1aSantos Cordon     *
440f128d20ada7474e5714f81533b8f77e915315c1aSantos Cordon     * See {@link #getOEMDataForCall} for information concerning proper testing of this code.
441f128d20ada7474e5714f81533b8f77e915315c1aSantos Cordon     */
442f128d20ada7474e5714f81533b8f77e915315c1aSantos Cordon    private void readOEMDataForCall(Call call, OEMData oemData) {
443f128d20ada7474e5714f81533b8f77e915315c1aSantos Cordon        // OEMs that want to read proprietary data from a call log restore should do so here.
444f128d20ada7474e5714f81533b8f77e915315c1aSantos Cordon        // Before reading from the data, an OEM should verify that the data matches their
445f128d20ada7474e5714f81533b8f77e915315c1aSantos Cordon        // expected namespace.
446f128d20ada7474e5714f81533b8f77e915315c1aSantos Cordon        //
447f128d20ada7474e5714f81533b8f77e915315c1aSantos Cordon        // Example:
448f128d20ada7474e5714f81533b8f77e915315c1aSantos Cordon
449f128d20ada7474e5714f81533b8f77e915315c1aSantos Cordon        /*
450f128d20ada7474e5714f81533b8f77e915315c1aSantos Cordon        if ("com.oem.expected.namespace".equals(oemData.namespace)) {
451f128d20ada7474e5714f81533b8f77e915315c1aSantos Cordon            ByteArrayInputStream bais = new ByteArrayInputStream(oemData.bytes);
452f128d20ada7474e5714f81533b8f77e915315c1aSantos Cordon            DataInputStream data = new DataInputStream(bais);
453f128d20ada7474e5714f81533b8f77e915315c1aSantos Cordon
454f128d20ada7474e5714f81533b8f77e915315c1aSantos Cordon            // Check against this version as we read data.
455f128d20ada7474e5714f81533b8f77e915315c1aSantos Cordon            int version = data.readInt();
456f128d20ada7474e5714f81533b8f77e915315c1aSantos Cordon            String customData1 = data.readUTF();
457f128d20ada7474e5714f81533b8f77e915315c1aSantos Cordon            int customData2 = data.readInt();
458f128d20ada7474e5714f81533b8f77e915315c1aSantos Cordon            // do something with data
459f128d20ada7474e5714f81533b8f77e915315c1aSantos Cordon        }
460f128d20ada7474e5714f81533b8f77e915315c1aSantos Cordon        */
461f128d20ada7474e5714f81533b8f77e915315c1aSantos Cordon    }
462f128d20ada7474e5714f81533b8f77e915315c1aSantos Cordon
463f128d20ada7474e5714f81533b8f77e915315c1aSantos Cordon
46461cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon    private void writeString(DataOutputStream data, String str) throws IOException {
46561cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        if (str == null) {
46661cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon            data.writeBoolean(false);
46761cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        } else {
46861cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon            data.writeBoolean(true);
46961cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon            data.writeUTF(str);
47061cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        }
47161cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon    }
47261cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon
47361cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon    private String readString(DataInputStream data) throws IOException {
47461cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        if (data.readBoolean()) {
47561cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon            return data.readUTF();
47661cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        } else {
47761cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon            return null;
47861cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        }
47961cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon    }
48061cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon
48161cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon    private void removeCallFromBackup(BackupDataOutput output, int callId) {
48261cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        try {
48361cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon            output.writeEntityHeader(Integer.toString(callId), -1);
48461cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        } catch (IOException e) {
48561cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon            Log.e(TAG, "Failed to remove call: " + callId, e);
48661cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        }
48761cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon    }
48861cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon
48961cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon    private static boolean isDebug() {
49061cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon        return Log.isLoggable(TAG, Log.DEBUG);
49161cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon    }
49261cc930dd36a8d9efa02195fa7f55bbe87209788Santos Cordon}
493