1a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry/*
2a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry * Copyright (C) 2016 The Android Open Source Project
3a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry *
4a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry * Licensed under the Apache License, Version 2.0 (the "License");
5a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry * you may not use this file except in compliance with the License.
6a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry * You may obtain a copy of the License at
7a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry *
8a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry *      http://www.apache.org/licenses/LICENSE-2.0
9a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry *
10a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry * Unless required by applicable law or agreed to in writing, software
11a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry * distributed under the License is distributed on an "AS IS" BASIS,
12a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry * See the License for the specific language governing permissions and
14a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry * limitations under the License
15a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry */
16a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry
17a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastrypackage com.android.providers.blockednumber;
18a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry
19a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastryimport android.annotation.Nullable;
20a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastryimport android.app.backup.BackupAgent;
21a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastryimport android.app.backup.BackupDataInput;
22a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastryimport android.app.backup.BackupDataOutput;
23a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastryimport android.content.ContentResolver;
24a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastryimport android.content.ContentValues;
25a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastryimport android.database.Cursor;
26a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastryimport android.os.ParcelFileDescriptor;
27a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastryimport android.provider.BlockedNumberContract;
28a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastryimport android.util.Log;
29a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry
30a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastryimport libcore.io.IoUtils;
31a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry
32a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastryimport java.io.ByteArrayInputStream;
33a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastryimport java.io.ByteArrayOutputStream;
34a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastryimport java.io.DataInputStream;
35a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastryimport java.io.DataOutputStream;
36a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastryimport java.io.FileInputStream;
37a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastryimport java.io.FileOutputStream;
38a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastryimport java.io.IOException;
39a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastryimport java.util.ArrayList;
40a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastryimport java.util.List;
41a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastryimport java.util.SortedSet;
42a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastryimport java.util.TreeSet;
43a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry
44a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry/**
45a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry * A backup agent to enable backup and restore of blocked numbers.
46a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry */
47a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastrypublic class BlockedNumberBackupAgent extends BackupAgent {
48a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry    private static final String[] BLOCKED_NUMBERS_PROJECTION = new String[] {
49a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry            BlockedNumberContract.BlockedNumbers.COLUMN_ID,
50a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry            BlockedNumberContract.BlockedNumbers.COLUMN_ORIGINAL_NUMBER,
51a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry            BlockedNumberContract.BlockedNumbers.COLUMN_E164_NUMBER,
52a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry    };
53a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry    private static final String TAG = "BlockedNumberBackup";
54a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry    private static final int VERSION = 1;
55a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry    private static final boolean DEBUG = false; // DO NOT SUBMIT WITH TRUE.
56a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry
57a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry    @Override
58a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry    public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput backupDataOutput,
59a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry                         ParcelFileDescriptor newState) throws IOException {
60a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry        logV("Backing up blocked numbers.");
61a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry
62a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry        DataInputStream dataInputStream =
63a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry                new DataInputStream(new FileInputStream(oldState.getFileDescriptor()));
64a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry        final BackupState state;
65a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry        try {
66a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry            state = readState(dataInputStream);
67a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry        } finally {
68a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry            IoUtils.closeQuietly(dataInputStream);
69a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry        }
70a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry
71a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry        runBackup(state, backupDataOutput, getAllBlockedNumbers());
72a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry
73a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry        DataOutputStream dataOutputStream =
74a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry                new DataOutputStream(new FileOutputStream(newState.getFileDescriptor()));
75a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry        try {
76a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry            writeNewState(dataOutputStream, state);
77a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry        } finally {
78a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry            dataOutputStream.close();
79a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry        }
80a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry    }
81a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry
82a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry    @Override
83a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry    public void onRestore(BackupDataInput data, int appVersionCode,
84a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry                          ParcelFileDescriptor newState) throws IOException {
85a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry        logV("Restoring blocked numbers.");
86a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry
87a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry        while (data.readNextHeader()) {
88a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry            BackedUpBlockedNumber blockedNumber = readBlockedNumberFromData(data);
89a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry            if (blockedNumber != null) {
90a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry                writeToProvider(blockedNumber);
91a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry            }
92a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry        }
93a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry    }
94a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry
95a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry    private BackupState readState(DataInputStream dataInputStream) throws IOException {
96a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry        int version = VERSION;
97a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry        if (dataInputStream.available() > 0) {
98a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry            version = dataInputStream.readInt();
99a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry        }
100a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry        BackupState state = new BackupState(version, new TreeSet<Integer>());
101a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry        while (dataInputStream.available() > 0) {
102a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry            state.ids.add(dataInputStream.readInt());
103a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry        }
104a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry        return state;
105a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry    }
106a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry
107a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry    private void runBackup(BackupState state, BackupDataOutput backupDataOutput,
108a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry                           Iterable<BackedUpBlockedNumber> allBlockedNumbers) throws IOException {
109a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry        SortedSet<Integer> deletedBlockedNumbers = new TreeSet<>(state.ids);
110a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry
111a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry        for (BackedUpBlockedNumber blockedNumber : allBlockedNumbers) {
112a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry            if (state.ids.contains(blockedNumber.id)) {
113a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry                // Existing blocked number: do not delete.
114a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry                deletedBlockedNumbers.remove(blockedNumber.id);
115a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry            } else {
116a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry                logV("Adding blocked number to backup: " + blockedNumber);
117a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry                // New blocked number
118a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry                addToBackup(backupDataOutput, blockedNumber);
119a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry                state.ids.add(blockedNumber.id);
120a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry            }
121a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry        }
122a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry
123a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry        for (int id : deletedBlockedNumbers) {
124a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry            logV("Removing blocked number from backup: " + id);
125a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry            removeFromBackup(backupDataOutput, id);
126a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry            state.ids.remove(id);
127a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry        }
128a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry    }
129a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry
130a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry    private void addToBackup(BackupDataOutput output, BackedUpBlockedNumber blockedNumber)
131a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry            throws IOException {
132a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
133a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry        DataOutputStream dataOutputStream = new DataOutputStream(outputStream);
134a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry        dataOutputStream.writeInt(VERSION);
135a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry        writeString(dataOutputStream, blockedNumber.originalNumber);
136a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry        writeString(dataOutputStream, blockedNumber.e164Number);
137a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry        dataOutputStream.flush();
138a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry
139a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry        output.writeEntityHeader(Integer.toString(blockedNumber.id), outputStream.size());
140a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry        output.writeEntityData(outputStream.toByteArray(), outputStream.size());
141a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry    }
142a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry
143a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry    private void writeString(DataOutputStream dataOutputStream, @Nullable String value)
144a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry            throws IOException {
145a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry        if (value == null) {
146a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry            dataOutputStream.writeBoolean(false);
147a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry        } else {
148a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry            dataOutputStream.writeBoolean(true);
149a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry            dataOutputStream.writeUTF(value);
150a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry        }
151a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry    }
152a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry
153a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry    @Nullable
154a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry    private String readString(DataInputStream dataInputStream)
155a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry            throws IOException {
156a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry        if (dataInputStream.readBoolean()) {
157a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry            return dataInputStream.readUTF();
158a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry        } else {
159a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry            return null;
160a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry        }
161a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry    }
162a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry
163a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry    private void removeFromBackup(BackupDataOutput output, int id) throws IOException {
164a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry        output.writeEntityHeader(Integer.toString(id), -1);
165a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry    }
166a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry
167a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry    private Iterable<BackedUpBlockedNumber> getAllBlockedNumbers() {
168a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry        List<BackedUpBlockedNumber> blockedNumbers = new ArrayList<>();
169a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry        ContentResolver resolver = getContentResolver();
170a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry        Cursor cursor = resolver.query(
171a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry                BlockedNumberContract.BlockedNumbers.CONTENT_URI, BLOCKED_NUMBERS_PROJECTION, null,
172a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry                null, null);
173a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry        if (cursor != null) {
174a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry            try {
175a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry                while (cursor.moveToNext()) {
176a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry                    blockedNumbers.add(createBlockedNumberFromCursor(cursor));
177a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry                }
178a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry            } finally {
179a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry                cursor.close();
180a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry            }
181a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry        }
182a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry        return blockedNumbers;
183a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry    }
184a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry
185a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry    private BackedUpBlockedNumber createBlockedNumberFromCursor(Cursor cursor) {
186a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry        return new BackedUpBlockedNumber(
187a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry                cursor.getInt(0), cursor.getString(1), cursor.getString(2));
188a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry    }
189a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry
190a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry    private void writeNewState(DataOutputStream dataOutputStream, BackupState state)
191a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry            throws IOException {
192a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry        dataOutputStream.writeInt(VERSION);
193a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry        for (int i : state.ids) {
194a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry            dataOutputStream.writeInt(i);
195a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry        }
196a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry    }
197a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry
198a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry    @Nullable
199a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry    private BackedUpBlockedNumber readBlockedNumberFromData(BackupDataInput data) {
200a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry        int id;
201a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry        try {
202a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry            id = Integer.parseInt(data.getKey());
203a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry        } catch (NumberFormatException e) {
204a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry            Log.e(TAG, "Unexpected key found in restore: " + data.getKey());
205a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry            return null;
206a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry        }
207a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry
208a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry        try {
209a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry            byte[] byteArray = new byte[data.getDataSize()];
210a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry            data.readEntityData(byteArray, 0, byteArray.length);
211a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry            DataInputStream dataInput = new DataInputStream(new ByteArrayInputStream(byteArray));
212a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry            dataInput.readInt(); // Ignore version.
213a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry            BackedUpBlockedNumber blockedNumber =
214a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry                    new BackedUpBlockedNumber(id, readString(dataInput), readString(dataInput));
215a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry            logV("Restoring blocked number: " + blockedNumber);
216a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry            return blockedNumber;
217a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry        } catch (IOException e) {
218a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry            Log.e(TAG, "Error reading blocked number for: " + id + ": " + e.getMessage());
219a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry            return null;
220a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry        }
221a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry    }
222a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry
223a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry    private void writeToProvider(BackedUpBlockedNumber blockedNumber) {
224a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry        ContentValues contentValues = new ContentValues();
225a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry        contentValues.put(BlockedNumberContract.BlockedNumbers.COLUMN_ORIGINAL_NUMBER,
226a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry                blockedNumber.originalNumber);
227a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry        contentValues.put(BlockedNumberContract.BlockedNumbers.COLUMN_E164_NUMBER,
228a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry                blockedNumber.e164Number);
229a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry        try {
230a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry            getContentResolver().insert(
231a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry                    BlockedNumberContract.BlockedNumbers.CONTENT_URI, contentValues);
232a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry        } catch (Exception e) {
233a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry            Log.e(TAG, "Unable to insert blocked number " + blockedNumber + " :" + e.getMessage());
234a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry        }
235a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry    }
236a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry
237a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry    private static boolean isDebug() {
238a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry        return Log.isLoggable(TAG, Log.DEBUG);
239a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry    }
240a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry
241a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry    private static void logV(String msg) {
242a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry        if (DEBUG) {
243a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry            Log.v(TAG, msg);
244a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry        }
245a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry    }
246a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry
247a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry    private static class BackupState {
248a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry        final int version;
249a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry        final SortedSet<Integer> ids;
250a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry
251a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry        BackupState(int version, SortedSet<Integer> ids) {
252a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry            this.version = version;
253a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry            this.ids = ids;
254a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry        }
255a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry    }
256a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry
257a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry    private static class BackedUpBlockedNumber {
258a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry        final int id;
259a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry        final String originalNumber;
260a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry        final String e164Number;
261a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry
262a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry        BackedUpBlockedNumber(int id, String originalNumber, String e164Number) {
263a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry            this.id = id;
264a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry            this.originalNumber = originalNumber;
265a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry            this.e164Number = e164Number;
266a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry        }
267a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry
268a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry        @Override
269a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry        public String toString() {
270a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry            if (isDebug()) {
271a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry                return String.format("[%d, original number: %s, e164 number: %s]",
272a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry                        id, originalNumber, e164Number);
273a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry            } else {
274a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry                return String.format("[%d]", id);
275a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry            }
276a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry        }
277a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry    }
278a227395c0b0d852f4a51629c85f9f35edf140496Abhijith Shastry}
279