116080bf86eb0c42308b5fe767a69453358abb556Nancy Chen/* 216080bf86eb0c42308b5fe767a69453358abb556Nancy Chen * Copyright (C) 2015 The Android Open Source Project 316080bf86eb0c42308b5fe767a69453358abb556Nancy Chen * 416080bf86eb0c42308b5fe767a69453358abb556Nancy Chen * Licensed under the Apache License, Version 2.0 (the "License"); 516080bf86eb0c42308b5fe767a69453358abb556Nancy Chen * you may not use this file except in compliance with the License. 616080bf86eb0c42308b5fe767a69453358abb556Nancy Chen * You may obtain a copy of the License at 716080bf86eb0c42308b5fe767a69453358abb556Nancy Chen * 816080bf86eb0c42308b5fe767a69453358abb556Nancy Chen * http://www.apache.org/licenses/LICENSE-2.0 916080bf86eb0c42308b5fe767a69453358abb556Nancy Chen * 1016080bf86eb0c42308b5fe767a69453358abb556Nancy Chen * Unless required by applicable law or agreed to in writing, software 1116080bf86eb0c42308b5fe767a69453358abb556Nancy Chen * distributed under the License is distributed on an "AS IS" BASIS, 1216080bf86eb0c42308b5fe767a69453358abb556Nancy Chen * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1316080bf86eb0c42308b5fe767a69453358abb556Nancy Chen * See the License for the specific language governing permissions and 1416080bf86eb0c42308b5fe767a69453358abb556Nancy Chen * limitations under the License 1516080bf86eb0c42308b5fe767a69453358abb556Nancy Chen */ 1616080bf86eb0c42308b5fe767a69453358abb556Nancy Chenpackage com.android.phone.vvm.omtp.sync; 1716080bf86eb0c42308b5fe767a69453358abb556Nancy Chen 1816080bf86eb0c42308b5fe767a69453358abb556Nancy Chenimport android.content.ContentResolver; 1916080bf86eb0c42308b5fe767a69453358abb556Nancy Chenimport android.content.ContentUris; 2016080bf86eb0c42308b5fe767a69453358abb556Nancy Chenimport android.content.ContentValues; 2116080bf86eb0c42308b5fe767a69453358abb556Nancy Chenimport android.content.Context; 2216080bf86eb0c42308b5fe767a69453358abb556Nancy Chenimport android.database.Cursor; 2316080bf86eb0c42308b5fe767a69453358abb556Nancy Chenimport android.net.Uri; 2416080bf86eb0c42308b5fe767a69453358abb556Nancy Chenimport android.provider.VoicemailContract; 2516080bf86eb0c42308b5fe767a69453358abb556Nancy Chenimport android.provider.VoicemailContract.Voicemails; 26651358c4c54e01f3241ce277f61ea15bce646ebfNancy Chenimport android.telecom.PhoneAccountHandle; 2716080bf86eb0c42308b5fe767a69453358abb556Nancy Chenimport android.telecom.Voicemail; 28651358c4c54e01f3241ce277f61ea15bce646ebfNancy Chenimport android.util.Log; 2916080bf86eb0c42308b5fe767a69453358abb556Nancy Chen 3016080bf86eb0c42308b5fe767a69453358abb556Nancy Chenimport java.util.ArrayList; 3116080bf86eb0c42308b5fe767a69453358abb556Nancy Chenimport java.util.List; 3216080bf86eb0c42308b5fe767a69453358abb556Nancy Chen 3316080bf86eb0c42308b5fe767a69453358abb556Nancy Chen/** 342cf7f2935c71b0ddbdda86fa6bc18b33db2dbf99Nancy Chen * Construct queries to interact with the voicemails table. 3516080bf86eb0c42308b5fe767a69453358abb556Nancy Chen */ 3616080bf86eb0c42308b5fe767a69453358abb556Nancy Chenpublic class VoicemailsQueryHelper { 37651358c4c54e01f3241ce277f61ea15bce646ebfNancy Chen private static final String TAG = "VoicemailsQueryHelper"; 38651358c4c54e01f3241ce277f61ea15bce646ebfNancy Chen 3916080bf86eb0c42308b5fe767a69453358abb556Nancy Chen final static String[] PROJECTION = new String[] { 4016080bf86eb0c42308b5fe767a69453358abb556Nancy Chen Voicemails._ID, // 0 4116080bf86eb0c42308b5fe767a69453358abb556Nancy Chen Voicemails.SOURCE_DATA, // 1 4216080bf86eb0c42308b5fe767a69453358abb556Nancy Chen Voicemails.IS_READ, // 2 4316080bf86eb0c42308b5fe767a69453358abb556Nancy Chen Voicemails.DELETED, // 3 4416080bf86eb0c42308b5fe767a69453358abb556Nancy Chen }; 4516080bf86eb0c42308b5fe767a69453358abb556Nancy Chen 4616080bf86eb0c42308b5fe767a69453358abb556Nancy Chen public static final int _ID = 0; 4716080bf86eb0c42308b5fe767a69453358abb556Nancy Chen public static final int SOURCE_DATA = 1; 4816080bf86eb0c42308b5fe767a69453358abb556Nancy Chen public static final int IS_READ = 2; 4916080bf86eb0c42308b5fe767a69453358abb556Nancy Chen public static final int DELETED = 3; 5016080bf86eb0c42308b5fe767a69453358abb556Nancy Chen 5142f5cb37b049a2cb1b047ae997538ac3afb90a21Nancy Chen final static String READ_SELECTION = Voicemails.DIRTY + "=1 AND " 5242f5cb37b049a2cb1b047ae997538ac3afb90a21Nancy Chen + Voicemails.DELETED + "!=1 AND " + Voicemails.IS_READ + "=1"; 5316080bf86eb0c42308b5fe767a69453358abb556Nancy Chen final static String DELETED_SELECTION = Voicemails.DELETED + "=1"; 5416080bf86eb0c42308b5fe767a69453358abb556Nancy Chen 5516080bf86eb0c42308b5fe767a69453358abb556Nancy Chen private Context mContext; 5616080bf86eb0c42308b5fe767a69453358abb556Nancy Chen private ContentResolver mContentResolver; 5716080bf86eb0c42308b5fe767a69453358abb556Nancy Chen private Uri mSourceUri; 5816080bf86eb0c42308b5fe767a69453358abb556Nancy Chen 5916080bf86eb0c42308b5fe767a69453358abb556Nancy Chen public VoicemailsQueryHelper(Context context) { 6016080bf86eb0c42308b5fe767a69453358abb556Nancy Chen mContext = context; 6116080bf86eb0c42308b5fe767a69453358abb556Nancy Chen mContentResolver = context.getContentResolver(); 6216080bf86eb0c42308b5fe767a69453358abb556Nancy Chen mSourceUri = VoicemailContract.Voicemails.buildSourceUri(mContext.getPackageName()); 6316080bf86eb0c42308b5fe767a69453358abb556Nancy Chen } 6416080bf86eb0c42308b5fe767a69453358abb556Nancy Chen 6516080bf86eb0c42308b5fe767a69453358abb556Nancy Chen /** 6616080bf86eb0c42308b5fe767a69453358abb556Nancy Chen * Get all the local read voicemails that have not been synced to the server. 6716080bf86eb0c42308b5fe767a69453358abb556Nancy Chen * 6816080bf86eb0c42308b5fe767a69453358abb556Nancy Chen * @return A list of read voicemails. 6916080bf86eb0c42308b5fe767a69453358abb556Nancy Chen */ 7016080bf86eb0c42308b5fe767a69453358abb556Nancy Chen public List<Voicemail> getReadVoicemails() { 7116080bf86eb0c42308b5fe767a69453358abb556Nancy Chen return getLocalVoicemails(READ_SELECTION); 7216080bf86eb0c42308b5fe767a69453358abb556Nancy Chen } 7316080bf86eb0c42308b5fe767a69453358abb556Nancy Chen 7416080bf86eb0c42308b5fe767a69453358abb556Nancy Chen /** 7516080bf86eb0c42308b5fe767a69453358abb556Nancy Chen * Get all the locally deleted voicemails that have not been synced to the server. 7616080bf86eb0c42308b5fe767a69453358abb556Nancy Chen * 7716080bf86eb0c42308b5fe767a69453358abb556Nancy Chen * @return A list of deleted voicemails. 7816080bf86eb0c42308b5fe767a69453358abb556Nancy Chen */ 7916080bf86eb0c42308b5fe767a69453358abb556Nancy Chen public List<Voicemail> getDeletedVoicemails() { 8016080bf86eb0c42308b5fe767a69453358abb556Nancy Chen return getLocalVoicemails(DELETED_SELECTION); 8116080bf86eb0c42308b5fe767a69453358abb556Nancy Chen } 8216080bf86eb0c42308b5fe767a69453358abb556Nancy Chen 8316080bf86eb0c42308b5fe767a69453358abb556Nancy Chen /** 8416080bf86eb0c42308b5fe767a69453358abb556Nancy Chen * Get all voicemails locally stored. 8516080bf86eb0c42308b5fe767a69453358abb556Nancy Chen * 8616080bf86eb0c42308b5fe767a69453358abb556Nancy Chen * @return A list of all locally stored voicemails. 8716080bf86eb0c42308b5fe767a69453358abb556Nancy Chen */ 8816080bf86eb0c42308b5fe767a69453358abb556Nancy Chen public List<Voicemail> getAllVoicemails() { 8916080bf86eb0c42308b5fe767a69453358abb556Nancy Chen return getLocalVoicemails(null); 9016080bf86eb0c42308b5fe767a69453358abb556Nancy Chen } 9116080bf86eb0c42308b5fe767a69453358abb556Nancy Chen 9216080bf86eb0c42308b5fe767a69453358abb556Nancy Chen /** 9316080bf86eb0c42308b5fe767a69453358abb556Nancy Chen * Utility method to make queries to the voicemail database. 9416080bf86eb0c42308b5fe767a69453358abb556Nancy Chen * 9516080bf86eb0c42308b5fe767a69453358abb556Nancy Chen * @param selection A filter declaring which rows to return. {@code null} returns all rows. 9616080bf86eb0c42308b5fe767a69453358abb556Nancy Chen * @return A list of voicemails according to the selection statement. 9716080bf86eb0c42308b5fe767a69453358abb556Nancy Chen */ 9816080bf86eb0c42308b5fe767a69453358abb556Nancy Chen private List<Voicemail> getLocalVoicemails(String selection) { 9916080bf86eb0c42308b5fe767a69453358abb556Nancy Chen Cursor cursor = mContentResolver.query(mSourceUri, PROJECTION, selection, null, null); 10016080bf86eb0c42308b5fe767a69453358abb556Nancy Chen if (cursor == null) { 10116080bf86eb0c42308b5fe767a69453358abb556Nancy Chen return null; 10216080bf86eb0c42308b5fe767a69453358abb556Nancy Chen } 10316080bf86eb0c42308b5fe767a69453358abb556Nancy Chen try { 10416080bf86eb0c42308b5fe767a69453358abb556Nancy Chen List<Voicemail> voicemails = new ArrayList<Voicemail>(); 10516080bf86eb0c42308b5fe767a69453358abb556Nancy Chen while (cursor.moveToNext()) { 1062cf7f2935c71b0ddbdda86fa6bc18b33db2dbf99Nancy Chen final long id = cursor.getLong(_ID); 1072cf7f2935c71b0ddbdda86fa6bc18b33db2dbf99Nancy Chen final String sourceData = cursor.getString(SOURCE_DATA); 1086337d1be5db67c7b81e7998988ca53da50ab44c2Nancy Chen final boolean isRead = cursor.getInt(IS_READ) == 1; 1096337d1be5db67c7b81e7998988ca53da50ab44c2Nancy Chen Voicemail voicemail = Voicemail 1106337d1be5db67c7b81e7998988ca53da50ab44c2Nancy Chen .createForUpdate(id, sourceData) 1116337d1be5db67c7b81e7998988ca53da50ab44c2Nancy Chen .setIsRead(isRead).build(); 11216080bf86eb0c42308b5fe767a69453358abb556Nancy Chen voicemails.add(voicemail); 11316080bf86eb0c42308b5fe767a69453358abb556Nancy Chen } 11416080bf86eb0c42308b5fe767a69453358abb556Nancy Chen return voicemails; 11516080bf86eb0c42308b5fe767a69453358abb556Nancy Chen } finally { 11616080bf86eb0c42308b5fe767a69453358abb556Nancy Chen cursor.close(); 11716080bf86eb0c42308b5fe767a69453358abb556Nancy Chen } 11816080bf86eb0c42308b5fe767a69453358abb556Nancy Chen } 11916080bf86eb0c42308b5fe767a69453358abb556Nancy Chen 12016080bf86eb0c42308b5fe767a69453358abb556Nancy Chen /** 12116080bf86eb0c42308b5fe767a69453358abb556Nancy Chen * Deletes a list of voicemails from the voicemail content provider. 12216080bf86eb0c42308b5fe767a69453358abb556Nancy Chen * 12316080bf86eb0c42308b5fe767a69453358abb556Nancy Chen * @param voicemails The list of voicemails to delete 12416080bf86eb0c42308b5fe767a69453358abb556Nancy Chen * @return The number of voicemails deleted 12516080bf86eb0c42308b5fe767a69453358abb556Nancy Chen */ 12616080bf86eb0c42308b5fe767a69453358abb556Nancy Chen public int deleteFromDatabase(List<Voicemail> voicemails) { 12716080bf86eb0c42308b5fe767a69453358abb556Nancy Chen int count = voicemails.size(); 12816080bf86eb0c42308b5fe767a69453358abb556Nancy Chen if (count == 0) { 12916080bf86eb0c42308b5fe767a69453358abb556Nancy Chen return 0; 13016080bf86eb0c42308b5fe767a69453358abb556Nancy Chen } 13116080bf86eb0c42308b5fe767a69453358abb556Nancy Chen 13216080bf86eb0c42308b5fe767a69453358abb556Nancy Chen StringBuilder sb = new StringBuilder(); 13316080bf86eb0c42308b5fe767a69453358abb556Nancy Chen for (int i = 0; i < count; i++) { 13416080bf86eb0c42308b5fe767a69453358abb556Nancy Chen if (i > 0) { 13516080bf86eb0c42308b5fe767a69453358abb556Nancy Chen sb.append(","); 13616080bf86eb0c42308b5fe767a69453358abb556Nancy Chen } 13716080bf86eb0c42308b5fe767a69453358abb556Nancy Chen sb.append(voicemails.get(i).getId()); 13816080bf86eb0c42308b5fe767a69453358abb556Nancy Chen } 13916080bf86eb0c42308b5fe767a69453358abb556Nancy Chen 14016080bf86eb0c42308b5fe767a69453358abb556Nancy Chen String selectionStatement = String.format(Voicemails._ID + " IN (%s)", sb.toString()); 14116080bf86eb0c42308b5fe767a69453358abb556Nancy Chen return mContentResolver.delete(Voicemails.CONTENT_URI, selectionStatement, null); 14216080bf86eb0c42308b5fe767a69453358abb556Nancy Chen } 14316080bf86eb0c42308b5fe767a69453358abb556Nancy Chen 14416080bf86eb0c42308b5fe767a69453358abb556Nancy Chen /** 14516080bf86eb0c42308b5fe767a69453358abb556Nancy Chen * Utility method to delete a single voicemail. 14616080bf86eb0c42308b5fe767a69453358abb556Nancy Chen */ 14716080bf86eb0c42308b5fe767a69453358abb556Nancy Chen public void deleteFromDatabase(Voicemail voicemail) { 14816080bf86eb0c42308b5fe767a69453358abb556Nancy Chen mContentResolver.delete(Voicemails.CONTENT_URI, Voicemails._ID + "=?", 14916080bf86eb0c42308b5fe767a69453358abb556Nancy Chen new String[] { Long.toString(voicemail.getId()) }); 15016080bf86eb0c42308b5fe767a69453358abb556Nancy Chen } 15116080bf86eb0c42308b5fe767a69453358abb556Nancy Chen 15216080bf86eb0c42308b5fe767a69453358abb556Nancy Chen /** 15316080bf86eb0c42308b5fe767a69453358abb556Nancy Chen * Sends an update command to the voicemail content provider for a list of voicemails. 15416080bf86eb0c42308b5fe767a69453358abb556Nancy Chen * From the view of the provider, since the updater is the owner of the entry, a blank 15516080bf86eb0c42308b5fe767a69453358abb556Nancy Chen * "update" means that the voicemail source is indicating that the server has up-to-date 15616080bf86eb0c42308b5fe767a69453358abb556Nancy Chen * information on the voicemail. This flips the "dirty" bit to "0". 15716080bf86eb0c42308b5fe767a69453358abb556Nancy Chen * 15816080bf86eb0c42308b5fe767a69453358abb556Nancy Chen * @param voicemails The list of voicemails to update 15916080bf86eb0c42308b5fe767a69453358abb556Nancy Chen * @return The number of voicemails updated 16016080bf86eb0c42308b5fe767a69453358abb556Nancy Chen */ 16116080bf86eb0c42308b5fe767a69453358abb556Nancy Chen public int markReadInDatabase(List<Voicemail> voicemails) { 16216080bf86eb0c42308b5fe767a69453358abb556Nancy Chen int count = voicemails.size(); 16316080bf86eb0c42308b5fe767a69453358abb556Nancy Chen for (int i = 0; i < count; i++) { 16416080bf86eb0c42308b5fe767a69453358abb556Nancy Chen markReadInDatabase(voicemails.get(i)); 16516080bf86eb0c42308b5fe767a69453358abb556Nancy Chen } 16616080bf86eb0c42308b5fe767a69453358abb556Nancy Chen return count; 16716080bf86eb0c42308b5fe767a69453358abb556Nancy Chen } 16816080bf86eb0c42308b5fe767a69453358abb556Nancy Chen 16916080bf86eb0c42308b5fe767a69453358abb556Nancy Chen /** 17016080bf86eb0c42308b5fe767a69453358abb556Nancy Chen * Utility method to mark single message as read. 17116080bf86eb0c42308b5fe767a69453358abb556Nancy Chen */ 17216080bf86eb0c42308b5fe767a69453358abb556Nancy Chen public void markReadInDatabase(Voicemail voicemail) { 17316080bf86eb0c42308b5fe767a69453358abb556Nancy Chen Uri uri = ContentUris.withAppendedId(mSourceUri, voicemail.getId()); 17416080bf86eb0c42308b5fe767a69453358abb556Nancy Chen ContentValues contentValues = new ContentValues(); 1756337d1be5db67c7b81e7998988ca53da50ab44c2Nancy Chen contentValues.put(Voicemails.IS_READ, "1"); 17616080bf86eb0c42308b5fe767a69453358abb556Nancy Chen mContentResolver.update(uri, contentValues, null, null); 17716080bf86eb0c42308b5fe767a69453358abb556Nancy Chen } 178651358c4c54e01f3241ce277f61ea15bce646ebfNancy Chen 179651358c4c54e01f3241ce277f61ea15bce646ebfNancy Chen /** 180651358c4c54e01f3241ce277f61ea15bce646ebfNancy Chen * Check if a particular voicemail has already been inserted. If not, insert the new voicemail. 181651358c4c54e01f3241ce277f61ea15bce646ebfNancy Chen * @param voicemail The voicemail to insert. 182651358c4c54e01f3241ce277f61ea15bce646ebfNancy Chen */ 183651358c4c54e01f3241ce277f61ea15bce646ebfNancy Chen public void insertIfUnique(Voicemail voicemail) { 184651358c4c54e01f3241ce277f61ea15bce646ebfNancy Chen if (isVoicemailUnique(voicemail)) { 185651358c4c54e01f3241ce277f61ea15bce646ebfNancy Chen VoicemailContract.Voicemails.insert(mContext, voicemail); 186651358c4c54e01f3241ce277f61ea15bce646ebfNancy Chen } else { 187651358c4c54e01f3241ce277f61ea15bce646ebfNancy Chen Log.w(TAG, "Voicemail already exists."); 188651358c4c54e01f3241ce277f61ea15bce646ebfNancy Chen } 189651358c4c54e01f3241ce277f61ea15bce646ebfNancy Chen } 190651358c4c54e01f3241ce277f61ea15bce646ebfNancy Chen 191651358c4c54e01f3241ce277f61ea15bce646ebfNancy Chen /** 192651358c4c54e01f3241ce277f61ea15bce646ebfNancy Chen * Voicemail is unique if the tuple of (phone account component name, phone account id, source 193651358c4c54e01f3241ce277f61ea15bce646ebfNancy Chen * data) is unique. If the phone account is missing, we also consider this unique since it's 194651358c4c54e01f3241ce277f61ea15bce646ebfNancy Chen * simply an "unknown" account. 195651358c4c54e01f3241ce277f61ea15bce646ebfNancy Chen * @param voicemail The voicemail to check if it is unique. 196651358c4c54e01f3241ce277f61ea15bce646ebfNancy Chen * @return {@code true} if the voicemail is unique, {@code false} otherwise. 197651358c4c54e01f3241ce277f61ea15bce646ebfNancy Chen */ 198651358c4c54e01f3241ce277f61ea15bce646ebfNancy Chen private boolean isVoicemailUnique(Voicemail voicemail) { 199651358c4c54e01f3241ce277f61ea15bce646ebfNancy Chen Cursor cursor = null; 200651358c4c54e01f3241ce277f61ea15bce646ebfNancy Chen PhoneAccountHandle phoneAccount = voicemail.getPhoneAccount(); 201651358c4c54e01f3241ce277f61ea15bce646ebfNancy Chen if (phoneAccount != null) { 202651358c4c54e01f3241ce277f61ea15bce646ebfNancy Chen String phoneAccountComponentName = phoneAccount.getComponentName().flattenToString(); 203651358c4c54e01f3241ce277f61ea15bce646ebfNancy Chen String phoneAccountId = phoneAccount.getId(); 204651358c4c54e01f3241ce277f61ea15bce646ebfNancy Chen String sourceData = voicemail.getSourceData(); 205651358c4c54e01f3241ce277f61ea15bce646ebfNancy Chen if (phoneAccountComponentName == null || phoneAccountId == null || sourceData == null) { 206651358c4c54e01f3241ce277f61ea15bce646ebfNancy Chen return true; 207651358c4c54e01f3241ce277f61ea15bce646ebfNancy Chen } 208651358c4c54e01f3241ce277f61ea15bce646ebfNancy Chen try { 209651358c4c54e01f3241ce277f61ea15bce646ebfNancy Chen String whereClause = 210651358c4c54e01f3241ce277f61ea15bce646ebfNancy Chen Voicemails.PHONE_ACCOUNT_COMPONENT_NAME + "=? AND " + 211651358c4c54e01f3241ce277f61ea15bce646ebfNancy Chen Voicemails.PHONE_ACCOUNT_ID + "=? AND " + Voicemails.SOURCE_DATA + "=?"; 212651358c4c54e01f3241ce277f61ea15bce646ebfNancy Chen String[] whereArgs = { phoneAccountComponentName, phoneAccountId, sourceData }; 213651358c4c54e01f3241ce277f61ea15bce646ebfNancy Chen cursor = mContentResolver.query( 214651358c4c54e01f3241ce277f61ea15bce646ebfNancy Chen mSourceUri, PROJECTION, whereClause, whereArgs, null); 215651358c4c54e01f3241ce277f61ea15bce646ebfNancy Chen if (cursor.getCount() == 0) { 216651358c4c54e01f3241ce277f61ea15bce646ebfNancy Chen return true; 217651358c4c54e01f3241ce277f61ea15bce646ebfNancy Chen } else { 218651358c4c54e01f3241ce277f61ea15bce646ebfNancy Chen return false; 219651358c4c54e01f3241ce277f61ea15bce646ebfNancy Chen } 220651358c4c54e01f3241ce277f61ea15bce646ebfNancy Chen } 221651358c4c54e01f3241ce277f61ea15bce646ebfNancy Chen finally { 222651358c4c54e01f3241ce277f61ea15bce646ebfNancy Chen if (cursor != null) { 223651358c4c54e01f3241ce277f61ea15bce646ebfNancy Chen cursor.close(); 224651358c4c54e01f3241ce277f61ea15bce646ebfNancy Chen } 225651358c4c54e01f3241ce277f61ea15bce646ebfNancy Chen } 226651358c4c54e01f3241ce277f61ea15bce646ebfNancy Chen } 227651358c4c54e01f3241ce277f61ea15bce646ebfNancy Chen return true; 228651358c4c54e01f3241ce277f61ea15bce646ebfNancy Chen } 22916080bf86eb0c42308b5fe767a69453358abb556Nancy Chen} 230