Add exception handling and retry when configuring VVM.

In VoicemailStatus#apply there is a possibility for the call to
ContentResolver#insert(.., ...) to throw an IllegalArgumentException if
the content resolver can't be started.  If this happened there was a
possibility of the entire Phone process dying.

Added exception handling to the apply method, and in the
OmtpVvmCarrierConfigHelper added code to retry configuration if it fails.

Bug: 29837276
Change-Id: I419e866e0b44b69932f4d0b9d2b46067ce2efcfe
diff --git a/src/com/android/phone/VoicemailStatus.java b/src/com/android/phone/VoicemailStatus.java
index 4d7d388..00130f1 100644
--- a/src/com/android/phone/VoicemailStatus.java
+++ b/src/com/android/phone/VoicemailStatus.java
@@ -83,17 +83,29 @@
             return this;
         }
 
-        public void apply() {
+        /**
+         * Apply the changes to the {@link VoicemailStatus} {@link #Editor}.
+         *
+         * @return {@code true} if the changes were successfully applied, {@code false} otherwise.
+         */
+        public boolean apply() {
             if (mPhoneAccountHandle == null) {
-                return;
+                return false;
             }
             mValues.put(Status.PHONE_ACCOUNT_COMPONENT_NAME,
                     mPhoneAccountHandle.getComponentName().flattenToString());
             mValues.put(Status.PHONE_ACCOUNT_ID, mPhoneAccountHandle.getId());
             ContentResolver contentResolver = mContext.getContentResolver();
             Uri statusUri = VoicemailContract.Status.buildSourceUri(mContext.getPackageName());
-            contentResolver.insert(statusUri, mValues);
+            try {
+                contentResolver.insert(statusUri, mValues);
+            } catch (IllegalArgumentException iae) {
+                VvmLog.e(TAG, "apply :: failed to insert content resolver ", iae);
+                mValues.clear();
+                return false;
+            }
             mValues.clear();
+            return true;
         }
 
         public ContentValues getValues() {
@@ -114,8 +126,9 @@
         }
 
         @Override
-        public void apply() {
+        public boolean apply() {
             // Do nothing
+            return true;
         }
 
         public void deferredApply() {
diff --git a/src/com/android/phone/vvm/omtp/ActivationTask.java b/src/com/android/phone/vvm/omtp/ActivationTask.java
index 9c58b95..00dd49e 100644
--- a/src/com/android/phone/vvm/omtp/ActivationTask.java
+++ b/src/com/android/phone/vvm/omtp/ActivationTask.java
@@ -62,6 +62,8 @@
 
     private static final String EXTRA_MESSAGE_DATA_BUNDLE = "extra_message_data_bundle";
 
+    public static final String EXTRA_REGISTER_CONTENT_PROVIDER = "extra_register_content_provider";
+
     @Nullable
     private static DeviceProvisionedObserver sDeviceProvisionedObserver;
 
@@ -140,6 +142,21 @@
             VoicemailStatus.disable(getContext(), phoneAccountHandle);
             return;
         }
+
+        if (mData != null && mData.getBoolean(EXTRA_REGISTER_CONTENT_PROVIDER)) {
+            // OmtmVvmCarrierConfigHelper can start the activation process; it will pass in a vvm
+            // content provider URI which we will use.  On some occasions, setting that URI will
+            // fail, so we will perform a few attempts to ensure that the vvm content provider has
+            // a good chance of being started up.
+            if (!VoicemailStatus.edit(getContext(), phoneAccountHandle)
+                    .setType(helper.getVvmType())
+                    .apply()) {
+                VvmLog.e(TAG, "Failed to configure content provider - " + helper.getVvmType());
+                fail();
+            }
+            VvmLog.i(TAG, "VVM content provider configured - " + helper.getVvmType());
+        }
+
         if (!OmtpVvmSourceManager.getInstance(getContext())
                 .isVvmSourceRegistered(phoneAccountHandle)) {
             VisualVoicemailPreferences preferences = new VisualVoicemailPreferences(getContext(),
diff --git a/src/com/android/phone/vvm/omtp/OmtpVvmCarrierConfigHelper.java b/src/com/android/phone/vvm/omtp/OmtpVvmCarrierConfigHelper.java
index b4fbb3f..4d6c63c 100644
--- a/src/com/android/phone/vvm/omtp/OmtpVvmCarrierConfigHelper.java
+++ b/src/com/android/phone/vvm/omtp/OmtpVvmCarrierConfigHelper.java
@@ -315,14 +315,22 @@
             // Error logged in getPhoneAccountHandle().
             return;
         }
-        VoicemailStatus.edit(mContext, phoneAccountHandle)
-                .setType(getVvmType())
-                .apply();
+
+        if (mVvmType == null || mVvmType.isEmpty()) {
+            // The VVM type is invalid; we should never have gotten here in the first place since
+            // this is loaded initially in the constructor, and callers should check isValid()
+            // before trying to start activation anyways.
+            VvmLog.e(TAG, "startActivation : vvmType is null or empty for account " +
+                    phoneAccountHandle);
+            return;
+        }
 
         activateSmsFilter();
 
         if (mProtocol != null) {
-            ActivationTask.start(mContext, mSubId, null);
+            Bundle extras = new Bundle();
+            extras.putBoolean(ActivationTask.EXTRA_REGISTER_CONTENT_PROVIDER, true);
+            ActivationTask.start(mContext, mSubId, extras);
         }
     }