Home | History | Annotate | Download | only in sync
      1 /*
      2  * Copyright (C) 2015 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License
     15  */
     16 package com.android.phone.vvm.omtp.sync;
     17 
     18 import android.content.ContentResolver;
     19 import android.content.ContentUris;
     20 import android.content.ContentValues;
     21 import android.content.Context;
     22 import android.database.Cursor;
     23 import android.net.Uri;
     24 import android.provider.VoicemailContract;
     25 import android.provider.VoicemailContract.Voicemails;
     26 import android.telecom.PhoneAccountHandle;
     27 import android.telecom.Voicemail;
     28 
     29 import java.util.ArrayList;
     30 import java.util.List;
     31 
     32 /**
     33  * Construct queries to interact with the voicemails table.
     34  */
     35 public class VoicemailsQueryHelper {
     36     final static String[] PROJECTION = new String[] {
     37             Voicemails._ID,              // 0
     38             Voicemails.SOURCE_DATA,      // 1
     39             Voicemails.IS_READ,          // 2
     40             Voicemails.DELETED,          // 3
     41             Voicemails.TRANSCRIPTION     // 4
     42     };
     43 
     44     public static final int _ID = 0;
     45     public static final int SOURCE_DATA = 1;
     46     public static final int IS_READ = 2;
     47     public static final int DELETED = 3;
     48     public static final int TRANSCRIPTION = 4;
     49 
     50     final static String READ_SELECTION = Voicemails.DIRTY + "=1 AND "
     51                 + Voicemails.DELETED + "!=1 AND " + Voicemails.IS_READ + "=1";
     52     final static String DELETED_SELECTION = Voicemails.DELETED + "=1";
     53 
     54     private Context mContext;
     55     private ContentResolver mContentResolver;
     56     private Uri mSourceUri;
     57 
     58     public VoicemailsQueryHelper(Context context) {
     59         mContext = context;
     60         mContentResolver = context.getContentResolver();
     61         mSourceUri = VoicemailContract.Voicemails.buildSourceUri(mContext.getPackageName());
     62     }
     63 
     64     /**
     65      * Get all the local read voicemails that have not been synced to the server.
     66      *
     67      * @return A list of read voicemails.
     68      */
     69     public List<Voicemail> getReadVoicemails() {
     70         return getLocalVoicemails(READ_SELECTION);
     71     }
     72 
     73     /**
     74      * Get all the locally deleted voicemails that have not been synced to the server.
     75      *
     76      * @return A list of deleted voicemails.
     77      */
     78     public List<Voicemail> getDeletedVoicemails() {
     79         return getLocalVoicemails(DELETED_SELECTION);
     80     }
     81 
     82     /**
     83      * Get all voicemails locally stored.
     84      *
     85      * @return A list of all locally stored voicemails.
     86      */
     87     public List<Voicemail> getAllVoicemails() {
     88         return getLocalVoicemails(null);
     89     }
     90 
     91     /**
     92      * Utility method to make queries to the voicemail database.
     93      *
     94      * @param selection A filter declaring which rows to return. {@code null} returns all rows.
     95      * @return A list of voicemails according to the selection statement.
     96      */
     97     private List<Voicemail> getLocalVoicemails(String selection) {
     98         Cursor cursor = mContentResolver.query(mSourceUri, PROJECTION, selection, null, null);
     99         if (cursor == null) {
    100             return null;
    101         }
    102         try {
    103             List<Voicemail> voicemails = new ArrayList<Voicemail>();
    104             while (cursor.moveToNext()) {
    105                 final long id = cursor.getLong(_ID);
    106                 final String sourceData = cursor.getString(SOURCE_DATA);
    107                 final boolean isRead = cursor.getInt(IS_READ) == 1;
    108                 final String transcription = cursor.getString(TRANSCRIPTION);
    109                 Voicemail voicemail = Voicemail
    110                         .createForUpdate(id, sourceData)
    111                         .setIsRead(isRead)
    112                         .setTranscription(transcription).build();
    113                 voicemails.add(voicemail);
    114             }
    115             return voicemails;
    116         } finally {
    117             cursor.close();
    118         }
    119     }
    120 
    121     /**
    122      * Deletes a list of voicemails from the voicemail content provider.
    123      *
    124      * @param voicemails The list of voicemails to delete
    125      * @return The number of voicemails deleted
    126      */
    127     public int deleteFromDatabase(List<Voicemail> voicemails) {
    128         int count = voicemails.size();
    129         if (count == 0) {
    130             return 0;
    131         }
    132 
    133         StringBuilder sb = new StringBuilder();
    134         for (int i = 0; i < count; i++) {
    135             if (i > 0) {
    136                 sb.append(",");
    137             }
    138             sb.append(voicemails.get(i).getId());
    139         }
    140 
    141         String selectionStatement = String.format(Voicemails._ID + " IN (%s)", sb.toString());
    142         return mContentResolver.delete(Voicemails.CONTENT_URI, selectionStatement, null);
    143     }
    144 
    145     /**
    146      * Utility method to delete a single voicemail.
    147      */
    148     public void deleteFromDatabase(Voicemail voicemail) {
    149         mContentResolver.delete(Voicemails.CONTENT_URI, Voicemails._ID + "=?",
    150                 new String[] { Long.toString(voicemail.getId()) });
    151     }
    152 
    153     /**
    154      * Sends an update command to the voicemail content provider for a list of voicemails.
    155      * From the view of the provider, since the updater is the owner of the entry, a blank
    156      * "update" means that the voicemail source is indicating that the server has up-to-date
    157      * information on the voicemail. This flips the "dirty" bit to "0".
    158      *
    159      * @param voicemails The list of voicemails to update
    160      * @return The number of voicemails updated
    161      */
    162     public int markReadInDatabase(List<Voicemail> voicemails) {
    163         int count = voicemails.size();
    164         for (int i = 0; i < count; i++) {
    165             markReadInDatabase(voicemails.get(i));
    166         }
    167         return count;
    168     }
    169 
    170     /**
    171      * Utility method to mark single message as read.
    172      */
    173     public void markReadInDatabase(Voicemail voicemail) {
    174         Uri uri = ContentUris.withAppendedId(mSourceUri, voicemail.getId());
    175         ContentValues contentValues = new ContentValues();
    176         contentValues.put(Voicemails.IS_READ, "1");
    177         mContentResolver.update(uri, contentValues, null, null);
    178     }
    179 
    180     /**
    181      * Utility method to add a transcription to the voicemail.
    182      */
    183     public void updateWithTranscription(Voicemail voicemail, String transcription) {
    184         Uri uri = ContentUris.withAppendedId(mSourceUri, voicemail.getId());
    185         ContentValues contentValues = new ContentValues();
    186         contentValues.put(Voicemails.TRANSCRIPTION, transcription);
    187         mContentResolver.update(uri, contentValues, null, null);
    188     }
    189 
    190     /**
    191      * Voicemail is unique if the tuple of (phone account component name, phone account id, source
    192      * data) is unique. If the phone account is missing, we also consider this unique since it's
    193      * simply an "unknown" account.
    194      * @param voicemail The voicemail to check if it is unique.
    195      * @return {@code true} if the voicemail is unique, {@code false} otherwise.
    196      */
    197     public boolean isVoicemailUnique(Voicemail voicemail) {
    198         Cursor cursor = null;
    199         PhoneAccountHandle phoneAccount = voicemail.getPhoneAccount();
    200         if (phoneAccount != null) {
    201             String phoneAccountComponentName = phoneAccount.getComponentName().flattenToString();
    202             String phoneAccountId = phoneAccount.getId();
    203             String sourceData = voicemail.getSourceData();
    204             if (phoneAccountComponentName == null || phoneAccountId == null || sourceData == null) {
    205                 return true;
    206             }
    207             try {
    208                 String whereClause =
    209                         Voicemails.PHONE_ACCOUNT_COMPONENT_NAME + "=? AND " +
    210                         Voicemails.PHONE_ACCOUNT_ID + "=? AND " + Voicemails.SOURCE_DATA + "=?";
    211                 String[] whereArgs = { phoneAccountComponentName, phoneAccountId, sourceData };
    212                 cursor = mContentResolver.query(
    213                         mSourceUri, PROJECTION, whereClause, whereArgs, null);
    214                 if (cursor.getCount() == 0) {
    215                     return true;
    216                 } else {
    217                     return false;
    218                 }
    219             }
    220             finally {
    221                 if (cursor != null) {
    222                     cursor.close();
    223                 }
    224             }
    225         }
    226         return true;
    227     }
    228 }
    229