Ensure duplicate voicemails are ignored, add msim to voicemail.

To ensure duplicate voicemails are ignored, check the tuple of phone
account and source data (i.e. server side voicemail id). Additional work
to add phone account field to voicemail in order to make checking this tuple
possible.

Bug: 19990866
Bug: 20954214

Change-Id: I31b876251b93382a5fd92d21162631bd89840cd9
diff --git a/src/com/android/phone/vvm/omtp/imap/ImapHelper.java b/src/com/android/phone/vvm/omtp/imap/ImapHelper.java
index 1d6c559..1368286 100644
--- a/src/com/android/phone/vvm/omtp/imap/ImapHelper.java
+++ b/src/com/android/phone/vvm/omtp/imap/ImapHelper.java
@@ -18,10 +18,12 @@
 import android.accounts.Account;
 import android.accounts.AccountManager;
 import android.content.Context;
+import android.telecom.PhoneAccountHandle;
 import android.telecom.Voicemail;
 
 import android.util.Base64;
 
+import com.android.phone.PhoneUtils;
 import com.android.phone.common.mail.Address;
 import com.android.phone.common.mail.Body;
 import com.android.phone.common.mail.BodyPart;
@@ -57,10 +59,12 @@
     private ImapFolder mFolder;
     private ImapStore mImapStore;
     private Context mContext;
+    private PhoneAccountHandle mPhoneAccount;
 
     public ImapHelper(Context context, Account account) {
         try {
             mContext = context;
+            mPhoneAccount = PhoneUtils.makePstnPhoneAccountHandle(account.name);
             TempDirectory.setTempDirectory(context);
 
             AccountManager accountManager = AccountManager.get(context);
@@ -260,6 +264,7 @@
                     boolean isRead = Arrays.asList(message.getFlags()).contains(Flag.SEEN);
 
                     return Voicemail.createForInsertion(time, number)
+                            .setPhoneAccount(mPhoneAccount)
                             .setSourcePackage(mContext.getPackageName())
                             .setSourceData(message.getUid())
                             .setIsRead(isRead)
diff --git a/src/com/android/phone/vvm/omtp/sms/OmtpMessageReceiver.java b/src/com/android/phone/vvm/omtp/sms/OmtpMessageReceiver.java
index 7e6d645..2d18ee7 100644
--- a/src/com/android/phone/vvm/omtp/sms/OmtpMessageReceiver.java
+++ b/src/com/android/phone/vvm/omtp/sms/OmtpMessageReceiver.java
@@ -33,6 +33,7 @@
 import com.android.phone.vvm.omtp.OmtpConstants;
 import com.android.phone.vvm.omtp.sync.OmtpVvmSyncAccountManager;
 import com.android.phone.vvm.omtp.sync.OmtpVvmSyncService.OmtpVvmSyncAdapter;
+import com.android.phone.vvm.omtp.sync.VoicemailsQueryHelper;
 
 /**
  * Receive SMS messages and send for processing by the OMTP visual voicemail source.
@@ -86,12 +87,13 @@
             case OmtpConstants.NEW_MESSAGE:
                 Voicemail voicemail = Voicemail.createForInsertion(
                         message.getTimestampMillis(), message.getSender())
+                        .setPhoneAccount(mPhoneAccount)
                         .setSourceData(message.getId())
                         .setDuration(message.getLength())
                         .setSourcePackage(mContext.getPackageName())
                         .build();
-
-                VoicemailContract.Voicemails.insert(mContext, voicemail);
+                VoicemailsQueryHelper queryHelper = new VoicemailsQueryHelper(mContext);
+                queryHelper.insertIfUnique(voicemail);
                 break;
             case OmtpConstants.MAILBOX_UPDATE:
                 // Needs a total resync
diff --git a/src/com/android/phone/vvm/omtp/sync/VoicemailsQueryHelper.java b/src/com/android/phone/vvm/omtp/sync/VoicemailsQueryHelper.java
index 151afed..f844e36 100644
--- a/src/com/android/phone/vvm/omtp/sync/VoicemailsQueryHelper.java
+++ b/src/com/android/phone/vvm/omtp/sync/VoicemailsQueryHelper.java
@@ -23,16 +23,19 @@
 import android.net.Uri;
 import android.provider.VoicemailContract;
 import android.provider.VoicemailContract.Voicemails;
+import android.telecom.PhoneAccountHandle;
 import android.telecom.Voicemail;
+import android.util.Log;
 
 import java.util.ArrayList;
-import java.util.Iterator;
 import java.util.List;
 
 /**
  * Construct a queries to interact with the voicemails table.
  */
 public class VoicemailsQueryHelper {
+    private static final String TAG = "VoicemailsQueryHelper";
+
     final static String[] PROJECTION = new String[] {
             Voicemails._ID,              // 0
             Voicemails.SOURCE_DATA,      // 1
@@ -168,4 +171,56 @@
         contentValues.put(Voicemails.IS_READ, "1");
         mContentResolver.update(uri, contentValues, null, null);
     }
+
+
+    /**
+     * Check if a particular voicemail has already been inserted. If not, insert the new voicemail.
+     * @param voicemail The voicemail to insert.
+     */
+    public void insertIfUnique(Voicemail voicemail) {
+        if (isVoicemailUnique(voicemail)) {
+            VoicemailContract.Voicemails.insert(mContext, voicemail);
+        } else {
+            Log.w(TAG, "Voicemail already exists.");
+        }
+    }
+
+    /**
+     * Voicemail is unique if the tuple of (phone account component name, phone account id, source
+     * data) is unique. If the phone account is missing, we also consider this unique since it's
+     * simply an "unknown" account.
+     * @param voicemail The voicemail to check if it is unique.
+     * @return {@code true} if the voicemail is unique, {@code false} otherwise.
+     */
+    private boolean isVoicemailUnique(Voicemail voicemail) {
+        Cursor cursor = null;
+        PhoneAccountHandle phoneAccount = voicemail.getPhoneAccount();
+        if (phoneAccount != null) {
+            String phoneAccountComponentName = phoneAccount.getComponentName().flattenToString();
+            String phoneAccountId = phoneAccount.getId();
+            String sourceData = voicemail.getSourceData();
+            if (phoneAccountComponentName == null || phoneAccountId == null || sourceData == null) {
+                return true;
+            }
+            try {
+                String whereClause =
+                        Voicemails.PHONE_ACCOUNT_COMPONENT_NAME + "=? AND " +
+                        Voicemails.PHONE_ACCOUNT_ID + "=? AND " + Voicemails.SOURCE_DATA + "=?";
+                String[] whereArgs = { phoneAccountComponentName, phoneAccountId, sourceData };
+                cursor = mContentResolver.query(
+                        mSourceUri, PROJECTION, whereClause, whereArgs, null);
+                if (cursor.getCount() == 0) {
+                    return true;
+                } else {
+                    return false;
+                }
+            }
+            finally {
+                if (cursor != null) {
+                    cursor.close();
+                }
+            }
+        }
+        return true;
+    }
 }