Fixes Contact Modification Bug

PresenceContact was being constructed incorrectly in
some cases leading to contacts not being updated
in the EAB database and never getting capability
information.

This change fixes the bug and removes the existing
rows in the database. It then repopulates the DB
with correct cached numbers.

I have also dialed back the verbosity of the logging
in general and hid PII.

Bug: 37691655
Test: Manual
Merged-In: I74e45eb3bcf47c3e03651421479f59aeb6762571
Change-Id: I74e45eb3bcf47c3e03651421479f59aeb6762571
diff --git a/rcs/presencepolling/AndroidManifest.xml b/rcs/presencepolling/AndroidManifest.xml
index e4f5dfb..67ece49 100644
--- a/rcs/presencepolling/AndroidManifest.xml
+++ b/rcs/presencepolling/AndroidManifest.xml
@@ -39,6 +39,7 @@
             android:protectionLevel="signatureOrSystem" />
 
     <protected-broadcast android:name="android.provider.rcs.eab.EAB_NEW_CONTACT_INSERTED" />
+    <protected-broadcast android:name="android.provider.rcs.eab.EAB_DATABASE_RESET" />
     <protected-broadcast android:name="com.android.service.ims.presence.capability_polling_retry" />
     <protected-broadcast android:name="com.android.service.ims.presence.periodical_capability_discovery" />
 
diff --git a/rcs/presencepolling/src/com/android/service/ims/presence/AlarmBroadcastReceiver.java b/rcs/presencepolling/src/com/android/service/ims/presence/AlarmBroadcastReceiver.java
index 3d586f5..2ce4da9 100644
--- a/rcs/presencepolling/src/com/android/service/ims/presence/AlarmBroadcastReceiver.java
+++ b/rcs/presencepolling/src/com/android/service/ims/presence/AlarmBroadcastReceiver.java
@@ -45,8 +45,6 @@
             PollingTask.ACTION_POLLING_RETRY_ALARM;
     private static final String ACTION_EAB_NEW_CONTACT_INSERTED =
             Contacts.ACTION_NEW_CONTACT_INSERTED;
-    private static final String ACTION_RESET_EAB_DATABASE =
-            Contacts.ACTION_EAB_DATABASE_RESET;
 
     @Override
     public void onReceive(Context context, Intent intent) {
@@ -73,10 +71,6 @@
                 String number = intent.getStringExtra(Contacts.NEW_PHONE_NUMBER);
                 capabilityPolling.enqueueNewContact(number);
             }
-        } else if (ACTION_RESET_EAB_DATABASE.equals(action)) {
-            // Reset the values in shared preference related to sync
-            // logic as EAB database is re-created.
-            SharedPrefUtil.resetEABSharedPref(context);
         } else {
             logger.debug("No interest in this intent: " + action);
         }
diff --git a/rcs/presencepolling/src/com/android/service/ims/presence/Contacts.java b/rcs/presencepolling/src/com/android/service/ims/presence/Contacts.java
index 588edfd..04e7266 100644
--- a/rcs/presencepolling/src/com/android/service/ims/presence/Contacts.java
+++ b/rcs/presencepolling/src/com/android/service/ims/presence/Contacts.java
@@ -29,12 +29,12 @@
 package com.android.service.ims.presence;
 
 import android.net.Uri;
-import android.os.SystemClock;
 import android.provider.BaseColumns;
 import android.text.format.Time;
 import com.android.ims.internal.EABContract;
 
 import com.android.ims.internal.ContactNumberUtils;
+import com.android.ims.internal.Logger;
 
 public final class Contacts {
     private Contacts() {}
@@ -280,7 +280,7 @@
             return new StringBuilder(256)
                 .append("Contacts.Item { ")
                 .append("\nId: " + mId)
-                .append("\nNumber: " + mNumber)
+                .append("\nNumber: " + Logger.hidePhoneNumberPii(mNumber))
                 .append("\nLast update time: " + mLastUpdateTime + "(" +
                         getTimeString(mLastUpdateTime) + ")")
                 .append("\nVolte capability timestamp: " + mVolteTimeStamp + "(" +
diff --git a/rcs/presencepolling/src/com/android/service/ims/presence/EABDbUtil.java b/rcs/presencepolling/src/com/android/service/ims/presence/EABDbUtil.java
index 02285f3..4e65d53 100644
--- a/rcs/presencepolling/src/com/android/service/ims/presence/EABDbUtil.java
+++ b/rcs/presencepolling/src/com/android/service/ims/presence/EABDbUtil.java
@@ -135,7 +135,7 @@
                             phoneNumList.add(uniquePhoneNum);
 
                             allEligibleContacts.add(new PresenceContact(contactName, contactNumber,
-                                    rawContactId, contactId, dataId, formattedNumber));
+                                    formattedNumber, rawContactId, contactId, dataId));
                             logger.debug("Eligible List Name: " + contactName +
                                     " Number:" + contactNumber + " RawContactID: " + rawContactId +
                                     " contactId: " + contactId + " Data.ID : " + dataId
diff --git a/rcs/presencepolling/src/com/android/service/ims/presence/EABProvider.java b/rcs/presencepolling/src/com/android/service/ims/presence/EABProvider.java
index 66bf4ff..a75c696 100644
--- a/rcs/presencepolling/src/com/android/service/ims/presence/EABProvider.java
+++ b/rcs/presencepolling/src/com/android/service/ims/presence/EABProvider.java
@@ -58,7 +58,7 @@
 
     private static final String EAB_DB_NAME = "rcseab.db";
 
-    private static final int EAB_DB_VERSION = 3;
+    private static final int EAB_DB_VERSION = 4;
 
     private static final int EAB_TABLE = 1;
 
@@ -110,7 +110,7 @@
     public void bootstrapDatabase(SQLiteDatabase db) {
         logger.info("Enter: bootstrapDatabase() Creating new EAB database");
         upgradeDatabase(db, 0, EAB_DB_VERSION);
-        logger.info("Exit: bootstrapDatabase()");
+        logger.debug("Exit: bootstrapDatabase()");
     }
 
     /*
@@ -123,6 +123,8 @@
         logger.info("Enter: upgradeDatabase() - oldVersion = " + oldVersion +
                 " newVersion = " + newVersion);
 
+        boolean needsEabResetBroadcast = false;
+
         if (oldVersion == newVersion) {
             logger.info("upgradeDatabase oldVersion == newVersion, No Upgrade Required");
             return true;
@@ -149,7 +151,17 @@
 
                 // Delete all records from EABPresence table.
                 db.execSQL("DELETE FROM " + EABContract.EABColumns.TABLE_NAME);
-                sendEabResetBroadcast();
+                needsEabResetBroadcast = true;
+
+                oldVersion++;
+                logger.debug("upgradeDatabase : DB has been upgraded to " + oldVersion);
+            }
+            if (oldVersion == 3) {
+                // Delete all records from EABPresence table. A bug in the previous version caused
+                // invalid rows to be created. This version removes all rows to allow the DB to
+                // repopulate.
+                db.execSQL("DELETE FROM " + EABContract.EABColumns.TABLE_NAME);
+                needsEabResetBroadcast = true;
 
                 oldVersion++;
                 logger.debug("upgradeDatabase : DB has been upgraded to " + oldVersion);
@@ -162,15 +174,19 @@
             // table is lost.
             db.execSQL(EAB_DROP_STATEMENT);
             upgradeDatabase(db, 0, EAB_DB_VERSION);
-            sendEabResetBroadcast();
+            needsEabResetBroadcast = true;
             logger.debug("Dropped and created new EABPresence table.");
         }
 
+        if (needsEabResetBroadcast) {
+            sendEabResetBroadcast();
+        }
+
         if (oldVersion == newVersion) {
             logger.debug("DB upgrade complete : to " + newVersion);
         }
 
-        logger.info("Exit: upgradeDatabase()");
+        logger.debug("Exit: upgradeDatabase()");
         return true;
     }
 
@@ -183,14 +199,14 @@
         upgradeDatabase(db, 0, EAB_DB_VERSION);
         sendEabResetBroadcast();
         logger.debug("Dropped and created new EABPresence table.");
-        logger.info("Exit: downgradeDatabase()");
+        logger.debug("Exit: downgradeDatabase()");
         return true;
     }
 
     @Override
     protected int deleteInternal(SQLiteDatabase db, Uri uri, String selection,
             String[] selectionArgs) {
-        logger.info("Enter: deleteInternal()");
+        logger.debug("Enter: deleteInternal()");
         final int match = URI_MATCHER.match(uri);
         String table = null;
         switch (match) {
@@ -203,19 +219,19 @@
                 table = EABContract.EABColumns.TABLE_NAME;
                 break;
             default:
-                logger.info("No match for " + uri);
-                logger.info("Exit: deleteInternal()");
+                logger.debug("No match for " + uri);
+                logger.debug("Exit: deleteInternal()");
                 return 0;
         }
         logger.debug("Deleting from the table" + table + " selection= " + selection);
         printDeletingValues(uri, selection, selectionArgs);
-        logger.info("Exit: deleteInternal()");
+        logger.debug("Exit: deleteInternal()");
         return db.delete(table, selection, selectionArgs);
     }
 
     @Override
     protected Uri insertInternal(SQLiteDatabase db, Uri uri, ContentValues values) {
-        logger.info("Enter: insertInternal()");
+        logger.debug("Enter: insertInternal()");
         final int match = URI_MATCHER.match(uri);
         String table = null;
         String nullColumnHack = null;
@@ -225,7 +241,7 @@
                 break;
             default:
                 logger.warn("No match for " + uri);
-                logger.info("Exit: insertInternal() with null");
+                logger.debug("Exit: insertInternal() with null");
                 return null;
         }
         values = verifyIfMdnExists(values);
@@ -236,10 +252,10 @@
         if (id > 0) {
             String contactNumber = values.getAsString(EABContract.EABColumns.CONTACT_NUMBER);
             sendInsertBroadcast(contactNumber);
-            logger.info("Exit: insertInternal()");
+            logger.debug("Exit: insertInternal()");
             return ContentUris.withAppendedId(uri, id);
         } else {
-            logger.info("Exit: insertInternal() with null");
+            logger.debug("Exit: insertInternal() with null");
             return null;
         }
     }
@@ -247,7 +263,7 @@
     @Override
     protected Cursor queryInternal(SQLiteDatabase db, Uri uri, String[] projection,
             String selection, String[] selectionArgs, String sortOrder) {
-        logger.info("Enter: queryInternal()");
+        logger.debug("Enter: queryInternal()");
         final int match = URI_MATCHER.match(uri);
 
         switch (match) {
@@ -298,17 +314,17 @@
                 break;
             default:
                 logger.warn("No match for " + uri);
-                logger.info("Exit: queryInternal()");
+                logger.debug("Exit: queryInternal()");
                 return null;
         }
-        logger.info("Exit: queryInternal()");
+        logger.debug("Exit: queryInternal()");
         return qb.query(db, projection, selection, selectionArgs, groupBy, having, sortOrder);
     }
 
     @Override
     protected int updateInternal(SQLiteDatabase db, Uri uri, ContentValues values,
             String selection, String[] selectionArgs) {
-        logger.info("Enter: updateInternal()");
+        logger.debug("Enter: updateInternal()");
         int result = 0;
         final int match = URI_MATCHER.match(uri);
 
@@ -340,13 +356,13 @@
             logger.debug("Updating the table " + table + " values= " + values.toString());
             result = db.update(table, values, selection, selectionArgs);
         }
-        logger.info("Exit: updateInternal()");
+        logger.debug("Exit: updateInternal()");
         return result;
     }
 
     @Override
     public String getType(Uri uri) {
-        logger.info("Enter: getType()");
+        logger.debug("Enter: getType()");
         final int match = URI_MATCHER.match(uri);
         switch (match) {
             case EAB_TABLE:
@@ -378,10 +394,7 @@
         logger.info("Enter: sendEabResetBroadcast()");
         Intent intent = new Intent(com.android.service.ims.presence.Contacts
                 .ACTION_EAB_DATABASE_RESET);
-        ComponentName component = new ComponentName("com.android.service.ims.presence",
-                "com.android.service.ims.presence.AlarmBroadcastReceiver");
-        intent.setComponent(component);
-        getContext().sendBroadcast(intent);
+        getContext().sendBroadcast(intent, "com.android.ims.permission.PRESENCE_ACCESS");
     }
 
     private ContentValues verifyIfMdnExists(ContentValues cvalues) {
diff --git a/rcs/presencepolling/src/com/android/service/ims/presence/EABService.java b/rcs/presencepolling/src/com/android/service/ims/presence/EABService.java
index 67aa92b..0f659be 100644
--- a/rcs/presencepolling/src/com/android/service/ims/presence/EABService.java
+++ b/rcs/presencepolling/src/com/android/service/ims/presence/EABService.java
@@ -76,6 +76,7 @@
     private static final int BOOT_COMPLETED = 0;
     private static final int CONTACT_TABLE_MODIFIED = 1;
     private static final int CONTACT_PROFILE_TABLE_MODIFIED = 2;
+    private static final int EAB_DATABASE_RESET = 3;
 
     private static final int SYNC_COMPLETE_DELAY_TIMER = 3 * 1000; // 3 seconds.
     private static final String TAG = "EABService";
@@ -104,35 +105,48 @@
             String action = intent.getAction();
             logger.debug("onReceive intent: " + action);
 
-            if(ContactsContract.Intents.CONTACTS_DATABASE_CREATED.equals(action)) {
-                logger.debug("Contacts database created.");
-                // Delete all entries from EAB Provider as it has to be re-synced with Contact db.
-                mContext.getContentResolver().delete(
-                        EABContract.EABColumns.CONTENT_URI, null, null);
-                // Initialise EABProvider.
-                logger.debug("Resetting timestamp values in shared pref.");
-                SharedPrefUtil.resetEABSharedPref(mContext);
-                // init the EAB db after re-setting.
-                ensureInitDone();
-            } else if(Intent.ACTION_TIME_CHANGED.equals(action) ||
-                    Intent.ACTION_TIMEZONE_CHANGED.equals(action)) {
-                Calendar cal = Calendar.getInstance();
-                long currentTimestamp = cal.getTimeInMillis();
-                long lastChangedTimestamp = SharedPrefUtil.getLastContactChangedTimestamp(
-                        mContext, currentTimestamp);
-                logger.debug("lastChangedTimestamp=" + lastChangedTimestamp +
-                        " currentTimestamp=" + currentTimestamp);
-                // Changed time backwards.
-                if(lastChangedTimestamp > currentTimestamp) {
+            switch(action) {
+                case ContactsContract.Intents.CONTACTS_DATABASE_CREATED: {
+                    logger.debug("Contacts database created.");
+                    // Delete all entries from EAB Provider as it has to be re-synced with
+                    // Contact db.
+                    mContext.getContentResolver().delete(
+                            EABContract.EABColumns.CONTENT_URI, null, null);
+                    // Initialise EABProvider.
                     logger.debug("Resetting timestamp values in shared pref.");
                     SharedPrefUtil.resetEABSharedPref(mContext);
-                    // Set Init done to true as only the contact sync timestamps are cleared and
-                    // the EABProvider table data is not cleared.
-                    SharedPrefUtil.setInitDone(mContext, true);
-                    CapabilityPolling capabilityPolling = CapabilityPolling.getInstance(null);
-                    if (capabilityPolling != null) {
-                        capabilityPolling.enqueueDiscovery(CapabilityPolling.ACTION_POLLING_NORMAL);
+                    // init the EAB db after re-setting.
+                    ensureInitDone();
+                    break;
+                }
+                case Intent.ACTION_TIME_CHANGED:
+                    // fall through
+                case Intent.ACTION_TIMEZONE_CHANGED: {
+                    Calendar cal = Calendar.getInstance();
+                    long currentTimestamp = cal.getTimeInMillis();
+                    long lastChangedTimestamp = SharedPrefUtil.getLastContactChangedTimestamp(
+                            mContext, currentTimestamp);
+                    logger.debug("lastChangedTimestamp=" + lastChangedTimestamp +
+                            " currentTimestamp=" + currentTimestamp);
+                    // Changed time backwards.
+                    if(lastChangedTimestamp > currentTimestamp) {
+                        logger.debug("Resetting timestamp values in shared pref.");
+                        SharedPrefUtil.resetEABSharedPref(mContext);
+                        // Set Init done to true as only the contact sync timestamps are cleared and
+                        // the EABProvider table data is not cleared.
+                        SharedPrefUtil.setInitDone(mContext, true);
+                        CapabilityPolling capabilityPolling = CapabilityPolling.getInstance(null);
+                        if (capabilityPolling != null) {
+                            capabilityPolling.enqueueDiscovery(
+                                    CapabilityPolling.ACTION_POLLING_NORMAL);
+                        }
                     }
+                    break;
+                }
+                case Contacts.ACTION_EAB_DATABASE_RESET: {
+                    logger.info("EAB Database Reset, Recreating...");
+                    sendEABResetMessage();
+                    break;
                 }
             }
         }
@@ -192,6 +206,7 @@
         filter.addAction(ContactsContract.Intents.CONTACTS_DATABASE_CREATED);
         filter.addAction(Intent.ACTION_TIME_CHANGED);
         filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
+        filter.addAction(Contacts.ACTION_EAB_DATABASE_RESET);
         registerReceiver(mReceiver, filter);
 
         initializeRcsInterfacer();
@@ -324,6 +339,13 @@
                 logger.debug("case CONTACT_PROFILE_TABLE_MODIFIED");
                 validateAndSyncFromProfileDb();
                 break;
+            case EAB_DATABASE_RESET:
+                // Initialise EABProvider.
+                logger.debug("Resetting timestamp values in shared pref.");
+                SharedPrefUtil.resetEABSharedPref(mContext);
+                // init the EAB db after re-setting.
+                ensureInitDone();
+                break;
             default:
                 logger.debug("default usecase hit! Do nothing");
                 break;
@@ -369,6 +391,20 @@
         }
     }
 
+    private void sendEABResetMessage() {
+        logger.debug("Enter: sendEABResetMsg()");
+        if (null != mServiceHandler) {
+            if (mServiceHandler.hasMessages(EAB_DATABASE_RESET)) {
+                mServiceHandler.removeMessages(EAB_DATABASE_RESET);
+                logger.debug("Removed previous EAB_DATABASE_RESET msg.");
+            }
+
+            logger.debug("Sending new EAB_DATABASE_RESET msg.");
+            Message msg = mServiceHandler.obtainMessage(EAB_DATABASE_RESET);
+            mServiceHandler.sendMessage(msg);
+        }
+    }
+
     private void sendDelayedContactChangeMsg() {
         logger.debug("Enter: sendDelayedContactChangeMsg()");
         if (null != mServiceHandler && !isEABServiceInitializing) {
@@ -980,14 +1016,14 @@
         logger.debug("Removing old number and inserting new number in EABProvider.");
         if (null != oldPhoneNumber) {
             contactListToDelete.add(new PresenceContact(contactName,
-                    oldPhoneNumber, sRawContactId, sContactId, sDataId, null));
+                    oldPhoneNumber, null /*formattedNumber*/, sRawContactId, sContactId, sDataId));
             // Delete old number from EAB Presence Table
             EABDbUtil.deleteNumbersFromEabDb(getApplicationContext(), contactListToDelete);
         }
         if (null != newPhoneNumber) {
             if (EABDbUtil.validateEligibleContact(mContext, newPhoneNumber)) {
                 contactListToInsert.add(new PresenceContact(contactName,
-                        newPhoneNumber, sRawContactId, sContactId, sDataId, newFormattedNumber));
+                        newPhoneNumber, newFormattedNumber, sRawContactId, sContactId, sDataId));
                 // Insert new number from EAB Presence Table
                 EABDbUtil.addContactsToEabDb(getApplicationContext(), contactListToInsert);
             } else {
@@ -1032,7 +1068,7 @@
         }
         ArrayList<PresenceContact> contactNameToUpdate = new ArrayList<PresenceContact>();
         contactNameToUpdate.add(new PresenceContact(newDisplayName,
-                phoneNumber, null, sRawContactId, sContactId, sDataId));
+                phoneNumber, null /*formattedNumber */, sRawContactId, sContactId, sDataId));
 
         EABDbUtil.updateNamesInEabDb(getApplicationContext(), contactNameToUpdate);
     }
@@ -1043,8 +1079,8 @@
             logger.debug("handleContactDeleted : contactId is null");
         }
         ArrayList<PresenceContact> contactListToDelete = new ArrayList<PresenceContact>();
-        contactListToDelete.add(new PresenceContact(
-                                    null, null, null, null, contactId.toString(), null));
+        contactListToDelete.add(new PresenceContact(null, null, null, null, contactId.toString(),
+                null));
 
         //ContactDbUtil.deleteRawContact(getApplicationContext(), contactListToDelete);
         EABDbUtil.deleteContactsFromEabDb(mContext, contactListToDelete);
diff --git a/rcs/presencepolling/src/com/android/service/ims/presence/PollingTask.java b/rcs/presencepolling/src/com/android/service/ims/presence/PollingTask.java
index aeb8f16..55ad09a 100644
--- a/rcs/presencepolling/src/com/android/service/ims/presence/PollingTask.java
+++ b/rcs/presencepolling/src/com/android/service/ims/presence/PollingTask.java
@@ -246,7 +246,7 @@
         for (int i = 0; i < mContacts.size(); i++) {
             sb.append("\n");
             Contacts.Item item = mContacts.get(i);
-            sb.append("Number " + i + ": " + item.number());
+            sb.append("Number " + i + ": " + Logger.hidePhoneNumberPii(item.number()));
         }
         sb.append("\nCompleted: " + mCompleted);
         sb.append(" }");
diff --git a/rcs/rcsmanager/src/java/com/android/ims/RcsPresenceInfo.java b/rcs/rcsmanager/src/java/com/android/ims/RcsPresenceInfo.java
index 8a5b913..bfae114 100644
--- a/rcs/rcsmanager/src/java/com/android/ims/RcsPresenceInfo.java
+++ b/rcs/rcsmanager/src/java/com/android/ims/RcsPresenceInfo.java
@@ -33,6 +33,8 @@
 import android.os.Parcelable;
 import android.net.Uri;
 
+import com.android.ims.internal.Logger;
+
 /**
  * RcsPresenceInfo is the class for presence information.
  * It is used to pass information to application for inent ACTION_PRESENCE_CHANGED
@@ -341,13 +343,15 @@
     }
 
     public String toString() {
-        return" contactNumber=" + getContactNumber() +
+        return" contactNumber=" + Logger.hidePhoneNumberPii(getContactNumber()) +
             " volteStatus=" + getVolteStatus() +
             " ipVoiceCallSate=" + getServiceState(ServiceType.VOLTE_CALL) +
-            " ipVoiceCallServiceNumber=" + getServiceContact(ServiceType.VOLTE_CALL) +
+            " ipVoiceCallServiceNumber=" +
+                Logger.hidePhoneNumberPii(getServiceContact(ServiceType.VOLTE_CALL)) +
             " ipVoiceCallTimestamp=" + getTimeStamp(ServiceType.VOLTE_CALL) +
             " ipVideoCallSate=" + getServiceState(ServiceType.VT_CALL) +
-            " ipVideoCallServiceNumber=" + getServiceContact(ServiceType.VT_CALL) +
+            " ipVideoCallServiceNumber=" +
+                Logger.hidePhoneNumberPii(getServiceContact(ServiceType.VT_CALL)) +
             " ipVideoCallTimestamp=" + getTimeStamp(ServiceType.VT_CALL);
     }
 }
diff --git a/rcs/rcsmanager/src/java/com/android/ims/internal/Logger.java b/rcs/rcsmanager/src/java/com/android/ims/internal/Logger.java
index b8fd072..a07936d 100644
--- a/rcs/rcsmanager/src/java/com/android/ims/internal/Logger.java
+++ b/rcs/rcsmanager/src/java/com/android/ims/internal/Logger.java
@@ -197,6 +197,17 @@
         Log.i(TAG, "[" + mClassName +"] " + trace, e);
     }
 
+    // Hide all numbers except for the last two
+    public static String hidePhoneNumberPii(String number) {
+        if(TextUtils.isEmpty(number) || mRcsTestMode || number.length() <= 2) {
+            return number;
+        }
+        StringBuilder sb = new StringBuilder(number.length());
+        sb.append("...*");
+        sb.append(number.substring(number.length()-2, number.length()));
+        return sb.toString();
+    }
+
     /**
      * Determines if the debug level is currently loggable.
      */