1d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian/* 2d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian * Copyright (C) 2015 The Android Open Source Project 3d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian * 4d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian * Licensed under the Apache License, Version 2.0 (the "License"); 5d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian * you may not use this file except in compliance with the License. 6d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian * You may obtain a copy of the License at 7d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian * 8d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian * http://www.apache.org/licenses/LICENSE-2.0 9d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian * 10d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian * Unless required by applicable law or agreed to in writing, software 11d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian * distributed under the License is distributed on an "AS IS" BASIS, 12d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian * See the License for the specific language governing permissions and 14d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian * limitations under the License 15d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian */ 16d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanianpackage com.android.voicemail.impl.sync; 17d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian 18d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanianimport android.annotation.TargetApi; 19d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanianimport android.content.ContentResolver; 20d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanianimport android.content.ContentUris; 21d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanianimport android.content.ContentValues; 22d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanianimport android.content.Context; 23d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanianimport android.database.Cursor; 24d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanianimport android.net.Uri; 25d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanianimport android.os.Build.VERSION_CODES; 26d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanianimport android.provider.VoicemailContract; 27d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanianimport android.provider.VoicemailContract.Voicemails; 288369df095a73a77b3715f8ae7ba06089cebca4ceEric Erfanianimport android.support.annotation.NonNull; 29d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanianimport android.telecom.PhoneAccountHandle; 30d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanianimport com.android.dialer.common.Assert; 31d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanianimport com.android.voicemail.impl.Voicemail; 32d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanianimport java.util.ArrayList; 33d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanianimport java.util.List; 34d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian 35d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian/** Construct queries to interact with the voicemails table. */ 36d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanianpublic class VoicemailsQueryHelper { 37d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian static final String[] PROJECTION = 38d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian new String[] { 39d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian Voicemails._ID, // 0 40d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian Voicemails.SOURCE_DATA, // 1 41d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian Voicemails.IS_READ, // 2 42d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian Voicemails.DELETED, // 3 43d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian Voicemails.TRANSCRIPTION // 4 44d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian }; 45d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian 46d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian public static final int _ID = 0; 47d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian public static final int SOURCE_DATA = 1; 48d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian public static final int IS_READ = 2; 49d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian public static final int DELETED = 3; 50d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian public static final int TRANSCRIPTION = 4; 51d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian 52d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian static final String READ_SELECTION = 53d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian Voicemails.DIRTY + "=1 AND " + Voicemails.DELETED + "!=1 AND " + Voicemails.IS_READ + "=1"; 54d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian static final String DELETED_SELECTION = Voicemails.DELETED + "=1"; 55d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian static final String ARCHIVED_SELECTION = Voicemails.ARCHIVED + "=0"; 56d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian 57d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian private Context mContext; 58d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian private ContentResolver mContentResolver; 59d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian private Uri mSourceUri; 60d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian 61d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian public VoicemailsQueryHelper(Context context) { 62d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian mContext = context; 63d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian mContentResolver = context.getContentResolver(); 64d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian mSourceUri = VoicemailContract.Voicemails.buildSourceUri(mContext.getPackageName()); 65d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian } 66d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian 67d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian /** 68d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian * Get all the local read voicemails that have not been synced to the server. 69d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian * 70d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian * @return A list of read voicemails. 71d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian */ 728369df095a73a77b3715f8ae7ba06089cebca4ceEric Erfanian public List<Voicemail> getReadVoicemails(@NonNull PhoneAccountHandle phoneAccountHandle) { 738369df095a73a77b3715f8ae7ba06089cebca4ceEric Erfanian return getLocalVoicemails(phoneAccountHandle, READ_SELECTION); 74d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian } 75d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian 76d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian /** 77d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian * Get all the locally deleted voicemails that have not been synced to the server. 78d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian * 79d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian * @return A list of deleted voicemails. 80d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian */ 818369df095a73a77b3715f8ae7ba06089cebca4ceEric Erfanian public List<Voicemail> getDeletedVoicemails(@NonNull PhoneAccountHandle phoneAccountHandle) { 828369df095a73a77b3715f8ae7ba06089cebca4ceEric Erfanian return getLocalVoicemails(phoneAccountHandle, DELETED_SELECTION); 83d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian } 84d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian 85d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian /** 86d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian * Get all voicemails locally stored. 87d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian * 88d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian * @return A list of all locally stored voicemails. 89d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian */ 908369df095a73a77b3715f8ae7ba06089cebca4ceEric Erfanian public List<Voicemail> getAllVoicemails(@NonNull PhoneAccountHandle phoneAccountHandle) { 918369df095a73a77b3715f8ae7ba06089cebca4ceEric Erfanian return getLocalVoicemails(phoneAccountHandle, null); 92d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian } 93d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian 94d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian /** 95d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian * Utility method to make queries to the voicemail database. 96d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian * 9710b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian * <p>TODO(b/36588206) add PhoneAccountHandle filtering back 9810b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian * 99d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian * @param selection A filter declaring which rows to return. {@code null} returns all rows. 100d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian * @return A list of voicemails according to the selection statement. 101d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian */ 1028369df095a73a77b3715f8ae7ba06089cebca4ceEric Erfanian private List<Voicemail> getLocalVoicemails( 10310b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian @NonNull PhoneAccountHandle unusedPhoneAccountHandle, String selection) { 10410b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian Cursor cursor = mContentResolver.query(mSourceUri, PROJECTION, selection, null, null); 105d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian if (cursor == null) { 106d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian return null; 107d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian } 108d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian try { 109d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian List<Voicemail> voicemails = new ArrayList<Voicemail>(); 110d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian while (cursor.moveToNext()) { 111d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian final long id = cursor.getLong(_ID); 112d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian final String sourceData = cursor.getString(SOURCE_DATA); 113d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian final boolean isRead = cursor.getInt(IS_READ) == 1; 114d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian final String transcription = cursor.getString(TRANSCRIPTION); 115d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian Voicemail voicemail = 116d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian Voicemail.createForUpdate(id, sourceData) 117d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian .setIsRead(isRead) 118d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian .setTranscription(transcription) 119d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian .build(); 120d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian voicemails.add(voicemail); 121d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian } 122d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian return voicemails; 123d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian } finally { 124d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian cursor.close(); 125d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian } 126d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian } 127d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian 128d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian /** 129d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian * Deletes a list of voicemails from the voicemail content provider. 130d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian * 131d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian * @param voicemails The list of voicemails to delete 132d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian * @return The number of voicemails deleted 133d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian */ 134d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian public int deleteFromDatabase(List<Voicemail> voicemails) { 135d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian int count = voicemails.size(); 136d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian if (count == 0) { 137d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian return 0; 138d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian } 139d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian 140d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian StringBuilder sb = new StringBuilder(); 141d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian for (int i = 0; i < count; i++) { 142d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian if (i > 0) { 143d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian sb.append(","); 144d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian } 145d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian sb.append(voicemails.get(i).getId()); 146d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian } 147d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian 148d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian String selectionStatement = String.format(Voicemails._ID + " IN (%s)", sb.toString()); 149d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian return mContentResolver.delete(Voicemails.CONTENT_URI, selectionStatement, null); 150d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian } 151d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian 152d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian /** Utility method to delete a single voicemail that is not archived. */ 153d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian public void deleteNonArchivedFromDatabase(Voicemail voicemail) { 154d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian mContentResolver.delete( 155d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian Voicemails.CONTENT_URI, 156d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian Voicemails._ID + "=? AND " + Voicemails.ARCHIVED + "= 0", 157d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian new String[] {Long.toString(voicemail.getId())}); 158d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian } 159d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian 160d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian public int markReadInDatabase(List<Voicemail> voicemails) { 161d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian int count = voicemails.size(); 162d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian for (int i = 0; i < count; i++) { 163d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian markReadInDatabase(voicemails.get(i)); 164d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian } 165d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian return count; 166d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian } 167d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian 168d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian /** Utility method to mark single message as read. */ 169d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian public void markReadInDatabase(Voicemail voicemail) { 170d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian Uri uri = ContentUris.withAppendedId(mSourceUri, voicemail.getId()); 171d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian ContentValues contentValues = new ContentValues(); 172d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian contentValues.put(Voicemails.IS_READ, "1"); 173d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian mContentResolver.update(uri, contentValues, null, null); 174d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian } 175d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian 176d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian /** 177d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian * Sends an update command to the voicemail content provider for a list of voicemails. From the 178d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian * view of the provider, since the updater is the owner of the entry, a blank "update" means that 179d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian * the voicemail source is indicating that the server has up-to-date information on the voicemail. 180d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian * This flips the "dirty" bit to "0". 181d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian * 182d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian * @param voicemails The list of voicemails to update 183d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian * @return The number of voicemails updated 184d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian */ 185d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian public int markCleanInDatabase(List<Voicemail> voicemails) { 186d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian int count = voicemails.size(); 187d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian for (int i = 0; i < count; i++) { 188d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian markCleanInDatabase(voicemails.get(i)); 189d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian } 190d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian return count; 191d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian } 192d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian 193d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian /** Utility method to mark single message as clean. */ 194d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian public void markCleanInDatabase(Voicemail voicemail) { 195d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian Uri uri = ContentUris.withAppendedId(mSourceUri, voicemail.getId()); 196d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian ContentValues contentValues = new ContentValues(); 197d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian mContentResolver.update(uri, contentValues, null, null); 198d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian } 199d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian 200d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian /** Utility method to add a transcription to the voicemail. */ 201d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian public void updateWithTranscription(Voicemail voicemail, String transcription) { 202d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian Uri uri = ContentUris.withAppendedId(mSourceUri, voicemail.getId()); 203d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian ContentValues contentValues = new ContentValues(); 204d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian contentValues.put(Voicemails.TRANSCRIPTION, transcription); 205d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian mContentResolver.update(uri, contentValues, null, null); 206d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian } 207d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian 208d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian /** 209d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian * Voicemail is unique if the tuple of (phone account component name, phone account id, source 210d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian * data) is unique. If the phone account is missing, we also consider this unique since it's 211d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian * simply an "unknown" account. 212d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian * 213d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian * @param voicemail The voicemail to check if it is unique. 214d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian * @return {@code true} if the voicemail is unique, {@code false} otherwise. 215d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian */ 216d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian public boolean isVoicemailUnique(Voicemail voicemail) { 217d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian Cursor cursor = null; 218d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian PhoneAccountHandle phoneAccount = voicemail.getPhoneAccount(); 219d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian if (phoneAccount != null) { 220d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian String phoneAccountComponentName = phoneAccount.getComponentName().flattenToString(); 221d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian String phoneAccountId = phoneAccount.getId(); 222d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian String sourceData = voicemail.getSourceData(); 223d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian if (phoneAccountComponentName == null || phoneAccountId == null || sourceData == null) { 224d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian return true; 225d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian } 226d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian try { 227d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian String whereClause = 228d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian Voicemails.PHONE_ACCOUNT_COMPONENT_NAME 229d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian + "=? AND " 230d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian + Voicemails.PHONE_ACCOUNT_ID 231d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian + "=? AND " 232d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian + Voicemails.SOURCE_DATA 233d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian + "=?"; 234d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian String[] whereArgs = {phoneAccountComponentName, phoneAccountId, sourceData}; 235d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian cursor = mContentResolver.query(mSourceUri, PROJECTION, whereClause, whereArgs, null); 236d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian if (cursor.getCount() == 0) { 237d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian return true; 238d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian } else { 239d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian return false; 240d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian } 241d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian } finally { 242d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian if (cursor != null) { 243d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian cursor.close(); 244d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian } 245d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian } 246d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian } 247d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian return true; 248d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian } 249d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian 250d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian /** 251d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian * Marks voicemails in the local database as archived. This indicates that the voicemails from the 252d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian * server were removed automatically to make space for new voicemails, and are stored locally on 253d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian * the users devices, without a corresponding server copy. 254d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian */ 255d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian public void markArchivedInDatabase(List<Voicemail> voicemails) { 256d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian for (Voicemail voicemail : voicemails) { 257d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian markArchiveInDatabase(voicemail); 258d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian } 259d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian } 260d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian 261d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian /** Utility method to mark single voicemail as archived. */ 262d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian public void markArchiveInDatabase(Voicemail voicemail) { 263d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian Uri uri = ContentUris.withAppendedId(mSourceUri, voicemail.getId()); 264d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian ContentValues contentValues = new ContentValues(); 265d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian contentValues.put(Voicemails.ARCHIVED, "1"); 266d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian mContentResolver.update(uri, contentValues, null, null); 267d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian } 268d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian 269d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian /** Find the oldest voicemails that are on the device, and also on the server. */ 270d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian @TargetApi(VERSION_CODES.M) // used for try with resources 271d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian public List<Voicemail> oldestVoicemailsOnServer(int numVoicemails) { 272d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian if (numVoicemails <= 0) { 273d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian Assert.fail("Query for remote voicemails cannot be <= 0"); 274d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian } 275d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian 276d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian String sortAndLimit = "date ASC limit " + numVoicemails; 277d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian 278d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian try (Cursor cursor = 2799a090c89e7a0c43a668bd6e2ac5e5e680f323aedEric Erfanian mContentResolver.query(mSourceUri, PROJECTION, ARCHIVED_SELECTION, null, sortAndLimit)) { 280d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian 281d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian Assert.isNotNull(cursor); 282d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian 283d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian List<Voicemail> voicemails = new ArrayList<>(); 284d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian while (cursor.moveToNext()) { 2859a090c89e7a0c43a668bd6e2ac5e5e680f323aedEric Erfanian final long id = cursor.getLong(_ID); 286d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian final String sourceData = cursor.getString(SOURCE_DATA); 2879a090c89e7a0c43a668bd6e2ac5e5e680f323aedEric Erfanian Voicemail voicemail = Voicemail.createForUpdate(id, sourceData).build(); 288d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian voicemails.add(voicemail); 289d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian } 290d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian 291d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian if (voicemails.size() != numVoicemails) { 292d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian Assert.fail( 293d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian String.format( 294d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian "voicemail count (%d) doesn't matched expected (%d)", 295d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian voicemails.size(), numVoicemails)); 296d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian } 297d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian return voicemails; 298d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian } 299d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian } 300d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian} 301