Merge "Force phone number to LTR in forwarding summary." into mnc-dev
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 9e54312..50741ac 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -667,5 +667,12 @@
             android:name="com.android.phone.vvm.omtp.sync.OmtpVvmSyncService"
             android:exported="false"
        />
+       <receiver android:name="com.android.phone.vvm.omtp.VvmPackageInstallReceiver">
+          <intent-filter>
+              <action android:name="android.intent.action.PACKAGE_INSTALL" />
+              <action android:name="android.intent.action.PACKAGE_ADDED" />
+              <data android:scheme="package"/>
+          </intent-filter>
+       </receiver>
     </application>
 </manifest>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 9b3dee9..e8dac11 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1217,6 +1217,9 @@
     <!-- Dialog title for the vibration settings for voice mail notifications [CHAR LIMIT=40]-->
     <string name="voicemail_notification_vibarte_when_dialog_title" msgid="8995274609647451109">Vibrate</string>
 
+    <!-- Visual voicemail on/off title [CHAR LIMIT=40] -->
+    <string name="voicemail_visual_voicemail_switch_title">Visual Voicemail</string>
+
     <!-- Voicemail ringtone title. The user clicks on this preference to select
          which sound to play when a voicemail notification is received.
          [CHAR LIMIT=30] -->
@@ -1282,6 +1285,8 @@
     <string name="voicemail_notification_ringtone_key">voicemail_notification_ringtone_key</string>
     <!-- DO NOT TRANSLATE. Internal key for a voicemail notification preference. -->
     <string name="voicemail_notification_vibrate_key">voicemail_notification_vibrate_key</string>
+    <!-- DO NOT TRANSLATE. Internal key for a visual voicemail preference. -->
+    <string name="voicemail_visual_voicemail_key">voicemail_visual_voicemail_key</string>
     <!-- DO NOT TRANSLATE. Internal key for tty mode preference. -->
     <string name="tty_mode_key">button_tty_mode_key</string>
     <!-- DO NOT TRANSLATE. Internal key for a voicemail notification preference. -->
diff --git a/res/xml/voicemail_settings.xml b/res/xml/voicemail_settings.xml
index a7d5fb4..9334566 100644
--- a/res/xml/voicemail_settings.xml
+++ b/res/xml/voicemail_settings.xml
@@ -60,5 +60,8 @@
         android:key="@string/voicemail_notification_vibrate_key"
         android:title="@string/voicemail_notification_vibrate_when_title"
         android:persistent="true" />
+    <SwitchPreference
+        android:key="@string/voicemail_visual_voicemail_key"
+        android:title="@string/voicemail_visual_voicemail_switch_title" />"
 
 </PreferenceScreen>
diff --git a/src/com/android/phone/CarrierConfigLoader.java b/src/com/android/phone/CarrierConfigLoader.java
index 0c34c5f..66cce28 100644
--- a/src/com/android/phone/CarrierConfigLoader.java
+++ b/src/com/android/phone/CarrierConfigLoader.java
@@ -65,13 +65,13 @@
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
+import java.io.FilenameFilter;
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.util.List;
 
 /**
  * CarrierConfigLoader binds to privileged carrier apps to fetch carrier config overlays.
- * TODO: implement persist cache
  * TODO: handle package install/uninstall events
  */
 
@@ -97,10 +97,6 @@
     // Message codes; see mHandler below.
     // Request from SubscriptionInfoUpdater when SIM becomes absent or error.
     private static final int EVENT_CLEAR_CONFIG = 0;
-    // Request from SubscriptionInfoUpdater to update config.
-    private static final int EVENT_UPDATE_CONFIG = 1;
-    // Request from carrier app to reload config.
-    private static final int EVENT_RELOAD_CONFIG = 2;
     // Has connected to default app.
     private static final int EVENT_CONNECTED_TO_DEFAULT = 3;
     // Has connected to carrier app.
@@ -109,6 +105,12 @@
     private static final int EVENT_LOADED_FROM_DEFAULT = 5;
     // Config has been loaded from carrier app.
     private static final int EVENT_LOADED_FROM_CARRIER = 6;
+    // Attempt to fetch from default app or read from XML.
+    private static final int EVENT_FETCH_DEFAULT = 7;
+    // Attempt to fetch from carrier app or read from XML.
+    private static final int EVENT_FETCH_CARRIER = 8;
+    // A package has been installed, uninstalled, or updated.
+    private static final int EVENT_PACKAGE_CHANGED = 9;
 
     // Tags used for saving and restoring XML documents.
     private static final String TAG_DOCUMENT = "carrier_config";
@@ -117,22 +119,29 @@
 
     // Handler to process various events.
     //
-    // For each phoneId, state transition should be: default app bind->connected->loaded, carrier
-    // app (if exists) bind-> connected->loaded. At any time, at most one connection is active.  If
-    // events are not in this order, previous connection will be unbind, so only latest event takes
-    // effect.
+    // For each phoneId, the event sequence should be:
+    //     fetch default, connected to default, loaded from default,
+    //     fetch carrier, connected to carrier, loaded from carrier.
     //
-    // We broadcast config change when:
-    // 1. loaded from carrier app
-    // 2. loaded from default app if no carrier app
-    // 3. config cleared, possibly due to sim removed
-    // 4. bind or IPC error
+    // If there is a saved config file for either the default app or the carrier app, we skip
+    // binding to the app and go straight from fetch to loaded.
+    //
+    // At any time, at most one connection is active. If events are not in this order, previous
+    // connection will be unbound, so only latest event takes effect.
+    //
+    // We broadcast ACTION_CARRIER_CONFIG_CHANGED after:
+    // 1. loading from carrier app (even if read from a file)
+    // 2. loading from default app if there is no carrier app (even if read from a file)
+    // 3. clearing config (e.g. due to sim removal)
+    // 4. encountering bind or IPC error
     private Handler mHandler = new Handler() {
             @Override
         public void handleMessage(Message msg) {
             int phoneId = msg.arg1;
             log("mHandler: " + msg.what + " phoneId: " + phoneId);
+            String iccid;
             CarrierIdentifier carrierId;
+            String carrierPackageName;
             CarrierServiceConnection conn;
             PersistableBundle config;
             switch (msg.what) {
@@ -145,14 +154,32 @@
                     mServiceConnection[phoneId] = null;
                     broadcastConfigChangedIntent(phoneId);
                     break;
-                case EVENT_UPDATE_CONFIG:
-                    // Use persist cache to avoid loading from app.
-                    // Fall through to next event if cache not hit.
-                case EVENT_RELOAD_CONFIG:
-                    if (!bindToConfigPackage(DEFAULT_CARRIER_CONFIG_PACKAGE,
-                            phoneId, EVENT_CONNECTED_TO_DEFAULT)) {
-                        // Send bcast if bind fails
-                        broadcastConfigChangedIntent(phoneId);
+
+                case EVENT_PACKAGE_CHANGED:
+                    carrierPackageName = (String) msg.obj;
+                    deleteConfigForPackage(carrierPackageName);
+                    int numPhones = TelephonyManager.from(mContext).getPhoneCount();
+                    for (int i = 0; i < numPhones; ++i) {
+                        updateConfigForPhoneId(i);
+                    }
+                    break;
+
+                case EVENT_FETCH_DEFAULT:
+                    iccid = getIccIdForPhoneId(phoneId);
+                    config = restoreConfigFromXml(DEFAULT_CARRIER_CONFIG_PACKAGE, iccid);
+                    if (config != null) {
+                        log("Loaded config from XML. package=" + DEFAULT_CARRIER_CONFIG_PACKAGE
+                                + " phoneId=" + phoneId);
+                        mConfigFromDefaultApp[phoneId] = config;
+                        Message newMsg = obtainMessage(EVENT_LOADED_FROM_DEFAULT, phoneId, -1);
+                        newMsg.getData().putBoolean("loaded_from_xml", true);
+                        mHandler.sendMessage(newMsg);
+                    } else {
+                        if (!bindToConfigPackage(DEFAULT_CARRIER_CONFIG_PACKAGE,
+                                phoneId, EVENT_CONNECTED_TO_DEFAULT)) {
+                            // Send bcast if bind fails
+                            broadcastConfigChangedIntent(phoneId);
+                        }
                     }
                     break;
 
@@ -168,6 +195,8 @@
                         ICarrierService carrierService = ICarrierService.Stub
                                 .asInterface(conn.service);
                         config = carrierService.getCarrierConfig(carrierId);
+                        iccid = getIccIdForPhoneId(phoneId);
+                        saveConfigToXml(DEFAULT_CARRIER_CONFIG_PACKAGE, iccid, config);
                         mConfigFromDefaultApp[phoneId] = config;
                         sendMessage(obtainMessage(EVENT_LOADED_FROM_DEFAULT, phoneId, -1));
                     } catch (RemoteException ex) {
@@ -178,23 +207,41 @@
                     break;
 
                 case EVENT_LOADED_FROM_DEFAULT:
-                    if (mServiceConnection[phoneId] == null) {
+                    // If we attempted to bind to the app, but the service connection is null, then
+                    // config was cleared while we were waiting and we should not continue.
+                    if (!msg.getData().getBoolean("loaded_from_xml", false)
+                            && mServiceConnection[phoneId] == null) {
                         break;
                     }
-                    List<String> carrierPackageNames = TelephonyManager.from(mContext)
-                            .getCarrierPackageNamesForIntentAndPhone(
-                                    new Intent(CarrierService.CONFIG_SERVICE_INTERFACE), phoneId);
-                    log("Found carrier config app: " + carrierPackageNames);
-                    if (carrierPackageNames != null && carrierPackageNames.size() > 0) {
-                        if (!bindToConfigPackage(carrierPackageNames.get(0),
-                                phoneId, EVENT_CONNECTED_TO_CARRIER)) {
-                            broadcastConfigChangedIntent(phoneId);
-                        }
+                    carrierPackageName = getCarrierPackageForPhoneId(phoneId);
+                    if (carrierPackageName != null) {
+                        log("Found carrier config app: " + carrierPackageName);
+                        sendMessage(obtainMessage(EVENT_FETCH_CARRIER, phoneId));
                     } else {
                         broadcastConfigChangedIntent(phoneId);
                     }
                     break;
 
+                case EVENT_FETCH_CARRIER:
+                    carrierPackageName = getCarrierPackageForPhoneId(phoneId);
+                    iccid = getIccIdForPhoneId(phoneId);
+                    config = restoreConfigFromXml(carrierPackageName, iccid);
+                    if (config != null) {
+                        log("Loaded config from XML. package=" + carrierPackageName + " phoneId="
+                                + phoneId);
+                        mConfigFromCarrierApp[phoneId] = config;
+                        Message newMsg = obtainMessage(EVENT_LOADED_FROM_CARRIER, phoneId, -1);
+                        newMsg.getData().putBoolean("loaded_from_xml", true);
+                        sendMessage(newMsg);
+                    } else {
+                        if (!bindToConfigPackage(carrierPackageName, phoneId,
+                                EVENT_CONNECTED_TO_CARRIER)) {
+                            // Send bcast if bind fails
+                            broadcastConfigChangedIntent(phoneId);
+                        }
+                    }
+                    break;
+
                 case EVENT_CONNECTED_TO_CARRIER:
                     carrierId = getCarrierIdForPhoneId(phoneId);
                     conn = (CarrierServiceConnection) msg.obj;
@@ -208,6 +255,9 @@
                         ICarrierService carrierService = ICarrierService.Stub
                                 .asInterface(conn.service);
                         config = carrierService.getCarrierConfig(carrierId);
+                        carrierPackageName = getCarrierPackageForPhoneId(phoneId);
+                        iccid = getIccIdForPhoneId(phoneId);
+                        saveConfigToXml(carrierPackageName, iccid, config);
                         mConfigFromCarrierApp[phoneId] = config;
                         sendMessage(obtainMessage(EVENT_LOADED_FROM_CARRIER, phoneId, -1));
                     } catch (RemoteException ex) {
@@ -218,7 +268,10 @@
                     break;
 
                 case EVENT_LOADED_FROM_CARRIER:
-                    if (mServiceConnection[phoneId] == null) {
+                    // If we attempted to bind to the app, but the service connection is null, then
+                    // config was cleared while we were waiting and we should not continue.
+                    if (!msg.getData().getBoolean("loaded_from_xml", false)
+                            && mServiceConnection[phoneId] == null) {
                         break;
                     }
                     broadcastConfigChangedIntent(phoneId);
@@ -312,18 +365,51 @@
         return new CarrierIdentifier(mcc, mnc, spn, imsi, gid1, gid2);
     }
 
+    /** Returns the package name of a priveleged carrier app, or null if there is none. */
+    private String getCarrierPackageForPhoneId(int phoneId) {
+        List<String> carrierPackageNames = TelephonyManager.from(mContext)
+                .getCarrierPackageNamesForIntentAndPhone(
+                        new Intent(CarrierService.CONFIG_SERVICE_INTERFACE), phoneId);
+        if (carrierPackageNames != null && carrierPackageNames.size() > 0) {
+            return carrierPackageNames.get(0);
+        } else {
+            return null;
+        }
+    }
+
+    private String getIccIdForPhoneId(int phoneId) {
+        if (!SubscriptionManager.isValidPhoneId(phoneId)) {
+            return null;
+        }
+        Phone phone = PhoneFactory.getPhone(phoneId);
+        if (phone == null) {
+            return null;
+        }
+        return phone.getIccSerialNumber();
+    }
+
     /**
      * Writes a bundle to an XML file.
      *
      * The bundle will be written to a file named after the package name and ICCID, so that it can
      * be restored later with {@link @restoreConfigFromXml}. The XML output will include the bundle
-     * and the current version of the specified package. In case of errors, no file will be written.
+     * and the current version of the specified package.
+     *
+     * In case of errors or invalid input, no file will be written.
      *
      * @param packageName the name of the package from which we fetched this bundle.
      * @param iccid the ICCID of the subscription for which this bundle was fetched.
-     * @param config the bundle to be written.
+     * @param config the bundle to be written. Null will be treated as an empty bundle.
      */
     private void saveConfigToXml(String packageName, String iccid, PersistableBundle config) {
+        if (packageName == null || iccid == null) {
+            loge("Cannot save config with null packageName or iccid.");
+            return;
+        }
+        if (config == null) {
+          config = new PersistableBundle();
+        }
+
         final String version = getPackageVersion(packageName);
         if (version == null) {
             loge("Failed to get package version for: " + packageName);
@@ -361,8 +447,10 @@
      * Reads a bundle from an XML file.
      *
      * This restores a bundle that was written with {@link #saveConfigToXml}. This returns the saved
-     * config bundle for the given package and ICCID. If the saved config is for a different package
-     * version than the current version, then null will be returned.
+     * config bundle for the given package and ICCID.
+     *
+     * In case of errors, or if the saved config is from a different package version than the
+     * current version, then null will be returned.
      *
      * @param packageName the name of the package from which we fetched this bundle.
      * @param iccid the ICCID of the subscription for which this bundle was fetched.
@@ -375,6 +463,10 @@
             loge("Failed to get package version for: " + packageName);
             return null;
         }
+        if (packageName == null || iccid == null) {
+            loge("Cannot restore config with null packageName or iccid.");
+            return null;
+        }
 
         PersistableBundle restoredBundle = null;
         FileInputStream inFile = null;
@@ -414,23 +506,48 @@
         return restoredBundle;
     }
 
+    /** Deletes all saved XML files associated with the given package name. */
+    private void deleteConfigForPackage(final String packageName) {
+        File dir = mContext.getFilesDir();
+        File[] packageFiles = dir.listFiles(new FilenameFilter() {
+            public boolean accept(File dir, String filename) {
+                return filename.startsWith("carrierconfig-" + packageName + "-");
+            }
+        });
+        for (File f : packageFiles) {
+            log("deleting " + f.getName());
+            f.delete();
+        }
+    }
+
     /** Builds a canonical file name for a config file. */
-    private String getFilenameForConfig(String packageName, String iccid) {
+    private String getFilenameForConfig(@NonNull String packageName, @NonNull String iccid) {
         return "carrierconfig-" + packageName + "-" + iccid + ".xml";
     }
 
-    /** Return the current version of a package, or null if the name is not found. */
+    /** Return the current version code of a package, or null if the name is not found. */
     private String getPackageVersion(String packageName) {
         try {
             PackageInfo info = mContext.getPackageManager().getPackageInfo(packageName, 0);
-            return info.versionName;
+            return Integer.toString(info.versionCode);
         } catch (PackageManager.NameNotFoundException e) {
             return null;
         }
     }
 
-    @Override
-    public @NonNull PersistableBundle getConfigForSubId(int subId) {
+    /** Read up to date config.
+     *
+     * This reads config bundles for the given phoneId. That means getting the latest bundle from
+     * the default app and a privileged carrier app, if present. This will not bind to an app if we
+     * have a saved config file to use instead.
+     */
+    private void updateConfigForPhoneId(int phoneId) {
+        mHandler.sendMessage(mHandler.obtainMessage(EVENT_FETCH_DEFAULT, phoneId, -1));
+    }
+
+    @Override public
+    @NonNull
+    PersistableBundle getConfigForSubId(int subId) {
         int phoneId = SubscriptionManager.getPhoneId(subId);
         PersistableBundle retConfig = CarrierConfigManager.getDefaultConfig();
         if (SubscriptionManager.isValidPhoneId(phoneId)) {
@@ -447,11 +564,25 @@
     @Override
     public void reloadCarrierConfigForSubId(int subId) {
         int phoneId = SubscriptionManager.getPhoneId(subId);
-        if (SubscriptionManager.isValidPhoneId(phoneId)) {
-            mHandler.sendMessage(mHandler.obtainMessage(EVENT_RELOAD_CONFIG, phoneId, -1));
-        } else {
+        if (!SubscriptionManager.isValidPhoneId(phoneId)) {
             log("Ignore invalid phoneId: " + phoneId + " for subId: " + subId);
+            return;
         }
+        String callingPackageName = mContext.getPackageManager().getNameForUid(
+                Binder.getCallingUid());
+        // TODO: Check that the calling packages is privileged for subId specifically.
+        int privilegeStatus = TelephonyManager.from(mContext).checkCarrierPrivilegesForPackage(
+                callingPackageName);
+        if (privilegeStatus != TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
+            throw new SecurityException(
+                    "Package is not privileged for subId=" + subId + ": " + callingPackageName);
+        }
+
+        // This method should block until deleting has completed, so that an error which prevents us
+        // from clearing the cache is passed back to the carrier app. With the files successfully
+        // deleted, this can return and we will eventually bind to the carrier app.
+        deleteConfigForPackage(callingPackageName);
+        updateConfigForPhoneId(phoneId);
     }
 
     @Override
@@ -469,7 +600,7 @@
                 break;
             case IccCardConstants.INTENT_VALUE_ICC_LOADED:
             case IccCardConstants.INTENT_VALUE_ICC_LOCKED:
-                mHandler.sendMessage(mHandler.obtainMessage(EVENT_UPDATE_CONFIG, phoneId, -1));
+                updateConfigForPhoneId(phoneId);
                 break;
         }
     }
@@ -518,6 +649,18 @@
         public void onReceive(Context context, Intent intent) {
             String action = intent.getAction();
             log("Receive action: " + action);
+            switch (action) {
+                case Intent.ACTION_PACKAGE_ADDED:
+                case Intent.ACTION_PACKAGE_CHANGED:
+                case Intent.ACTION_PACKAGE_REMOVED:
+                    int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
+                    String packageName = mContext.getPackageManager().getNameForUid(uid);
+                    // We don't have a phoneId for arg1.
+                    mHandler.sendMessage(
+                            mHandler.obtainMessage(EVENT_PACKAGE_CHANGED, packageName));
+                    break;
+
+            }
         }
     }
 
diff --git a/src/com/android/phone/PhoneGlobals.java b/src/com/android/phone/PhoneGlobals.java
index 8b0b8a9..d066de2 100644
--- a/src/com/android/phone/PhoneGlobals.java
+++ b/src/com/android/phone/PhoneGlobals.java
@@ -159,7 +159,7 @@
     static int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
     static boolean sVoiceCapable = true;
 
-    // Internal PhoneApp Call state tracker
+    // TODO: Remove, no longer used.
     CdmaPhoneCallState cdmaPhoneCallState;
 
     // The currently-active PUK entry activity and progress dialog.
@@ -780,14 +780,8 @@
         if (DBG) Log.d(LOG_TAG, "initForNewRadioTechnology...");
 
         final Phone phone = PhoneFactory.getPhone(phoneId);
-
-        if (phone.getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA) {
-            // Create an instance of CdmaPhoneCallState and initialize it to IDLE
-            cdmaPhoneCallState = new CdmaPhoneCallState();
-            cdmaPhoneCallState.CdmaPhoneCallStateInit();
-        }
-        if (!TelephonyCapabilities.supportsOtasp(phone)) {
-            //Clean up OTA data in GSM/UMTS. It is valid only for CDMA
+        if (phone == null || !TelephonyCapabilities.supportsOtasp(phone)) {
+            // Clean up OTA for non-CDMA since it is only valid for CDMA.
             clearOtaState();
         }
 
@@ -795,7 +789,7 @@
         callStateMonitor.updateAfterRadioTechnologyChange();
 
         // Update registration for ICC status after radio technology change
-        IccCard sim = phone.getIccCard();
+        IccCard sim = phone == null ? null : phone.getIccCard();
         if (sim != null) {
             if (DBG) Log.d(LOG_TAG, "Update registration for ICC status...");
 
@@ -830,6 +824,7 @@
                 }
                 Phone phone = SubscriptionManager.isValidPhoneId(phoneId) ?
                         PhoneFactory.getPhone(phoneId) : PhoneFactory.getDefaultPhone();
+
                 // The "data disconnected due to roaming" notification is shown
                 // if (a) you have the "data roaming" feature turned off, and
                 // (b) you just lost data connectivity because you're roaming.
@@ -916,11 +911,13 @@
          */
 
         // If service just returned, start sending out the queued messages
-        ServiceState ss = ServiceState.newFromBundle(intent.getExtras());
-
-        if (ss != null) {
-            int state = ss.getState();
-            notificationMgr.updateNetworkSelection(state);
+        Bundle extras = intent.getExtras();
+        if (extras != null) {
+            ServiceState ss = ServiceState.newFromBundle(extras);
+            if (ss != null) {
+                int state = ss.getState();
+                notificationMgr.updateNetworkSelection(state);
+            }
         }
     }
 
diff --git a/src/com/android/phone/settings/VisualVoicemailSettingsUtil.java b/src/com/android/phone/settings/VisualVoicemailSettingsUtil.java
index e3a9307..5dd3166 100644
--- a/src/com/android/phone/settings/VisualVoicemailSettingsUtil.java
+++ b/src/com/android/phone/settings/VisualVoicemailSettingsUtil.java
@@ -20,11 +20,15 @@
 import android.preference.PreferenceManager;
 import android.telecom.PhoneAccountHandle;
 
+import com.android.internal.telephony.Phone;
+import com.android.phone.PhoneUtils;
 import com.android.phone.vvm.omtp.OmtpConstants;
 import com.android.phone.vvm.omtp.sms.StatusMessage;
 
 /**
  * Save visual voicemail login values in shared preferences to be retrieved later.
+ * Because a voicemail source is tied 1:1 to a phone account, the phone account handle is used in
+ * the key for each voicemail source and the associated data.
  */
 public class VisualVoicemailSettingsUtil {
     private static final String VISUAL_VOICEMAIL_SHARED_PREFS_KEY_PREFIX =
@@ -32,6 +36,11 @@
 
     private static final String IS_ENABLED_KEY = "is_enabled";
 
+    public static void setVisualVoicemailEnabled(Phone phone, boolean isEnabled) {
+        setVisualVoicemailEnabled(phone.getContext(), PhoneUtils.makePstnPhoneAccountHandle(phone),
+                isEnabled);
+    }
+
     public static void setVisualVoicemailEnabled(Context context, PhoneAccountHandle phoneAccount,
             boolean isEnabled) {
         SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
@@ -41,17 +50,22 @@
         editor.commit();
     }
 
-    public static boolean getVisualVoicemailEnabled(Context context,
+    public static boolean isVisualVoicemailEnabled(Context context,
             PhoneAccountHandle phoneAccount) {
         if (phoneAccount == null) {
             return false;
         }
         SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
         return prefs.getBoolean(getVisualVoicemailSharedPrefsKey(IS_ENABLED_KEY, phoneAccount),
-                true);
+                false);
     }
 
-    public static void setSourceCredentialsFromStatusMessage(Context context,
+    public static boolean isVisualVoicemailEnabled(Phone phone) {
+        return isVisualVoicemailEnabled(phone.getContext(),
+                PhoneUtils.makePstnPhoneAccountHandle(phone));
+    }
+
+    public static void setVisualVoicemailCredentialsFromStatusMessage(Context context,
             PhoneAccountHandle phoneAccount, StatusMessage message) {
         SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
         SharedPreferences.Editor editor = prefs.edit();
@@ -71,7 +85,7 @@
         editor.commit();
     }
 
-    public static String getCredentialForSource(Context context, String key,
+    public static String getVisualVoicemailCredentials(Context context, String key,
             PhoneAccountHandle phoneAccount) {
         SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
         return prefs.getString(getVisualVoicemailSharedPrefsKey(key, phoneAccount), null);
diff --git a/src/com/android/phone/settings/VoicemailSettingsActivity.java b/src/com/android/phone/settings/VoicemailSettingsActivity.java
index f017836..f70ee65 100644
--- a/src/com/android/phone/settings/VoicemailSettingsActivity.java
+++ b/src/com/android/phone/settings/VoicemailSettingsActivity.java
@@ -28,7 +28,9 @@
 import android.preference.Preference;
 import android.preference.PreferenceActivity;
 import android.preference.PreferenceScreen;
+import android.preference.SwitchPreference;
 import android.provider.ContactsContract.CommonDataKinds;
+import android.telephony.TelephonyManager;
 import android.text.TextUtils;
 import android.util.Log;
 import android.view.MenuItem;
@@ -40,7 +42,10 @@
 import com.android.phone.R;
 import com.android.phone.EditPhoneNumberPreference;
 import com.android.phone.PhoneGlobals;
+import com.android.phone.PhoneUtils;
 import com.android.phone.SubscriptionInfoHelper;
+import com.android.phone.vvm.omtp.OmtpVvmCarrierConfigHelper;
+import com.android.phone.vvm.omtp.sync.OmtpVvmSourceManager;
 
 import java.util.Collection;
 import java.util.HashMap;
@@ -187,12 +192,14 @@
     private boolean mForeground;
     private Phone mPhone;
     private SubscriptionInfoHelper mSubscriptionInfoHelper;
+    private OmtpVvmCarrierConfigHelper mOmtpVvmCarrierConfigHelper;
 
     private EditPhoneNumberPreference mSubMenuVoicemailSettings;
     private VoicemailProviderListPreference mVoicemailProviders;
     private PreferenceScreen mVoicemailSettings;
     private VoicemailRingtonePreference mVoicemailNotificationRingtone;
     private CheckBoxPreference mVoicemailNotificationVibrate;
+    private SwitchPreference mVoicemailVisualVoicemail;
 
 
     //*********************************************************************************************
@@ -212,6 +219,8 @@
         mSubscriptionInfoHelper.setActionBarTitle(
                 getActionBar(), getResources(), R.string.voicemail_settings_with_label);
         mPhone = mSubscriptionInfoHelper.getPhone();
+        mOmtpVvmCarrierConfigHelper = new OmtpVvmCarrierConfigHelper(
+                mPhone.getContext(), mPhone.getSubId());
     }
 
     @Override
@@ -248,6 +257,17 @@
                 getResources().getString(R.string.voicemail_notification_vibrate_key));
         mVoicemailNotificationVibrate.setOnPreferenceChangeListener(this);
 
+        mVoicemailVisualVoicemail = (SwitchPreference) findPreference(
+                getResources().getString(R.string.voicemail_visual_voicemail_key));
+        if (TelephonyManager.VVM_TYPE_OMTP.equals(mOmtpVvmCarrierConfigHelper.getVvmType()) ||
+                TelephonyManager.VVM_TYPE_CVVM.equals(mOmtpVvmCarrierConfigHelper.getVvmType())) {
+            mVoicemailVisualVoicemail.setOnPreferenceChangeListener(this);
+            mVoicemailVisualVoicemail.setChecked(
+                    VisualVoicemailSettingsUtil.isVisualVoicemailEnabled(mPhone));
+        } else {
+            prefSet.removePreference(mVoicemailVisualVoicemail);
+        }
+
         updateVMPreferenceWidgets(mVoicemailProviders.getValue());
 
         // check the intent that started this activity and pop up the voicemail
@@ -366,6 +386,14 @@
             // TODO: Revert to checking reference after migrating voicemail to its own activity.
             VoicemailNotificationSettingsUtil.setVibrationEnabled(
                     mPhone, Boolean.TRUE.equals(objValue));
+        } else if (preference.getKey().equals(mVoicemailVisualVoicemail.getKey())) {
+            if ((Boolean) objValue) {
+                VisualVoicemailSettingsUtil.setVisualVoicemailEnabled(mPhone, true);
+                mOmtpVvmCarrierConfigHelper.startActivation();
+            } else {
+                OmtpVvmSourceManager.getInstance(mPhone.getContext()).removeSource(mPhone);
+                mOmtpVvmCarrierConfigHelper.startDeactivation();
+            }
         }
 
         // Always let the preference setting proceed.
diff --git a/src/com/android/phone/vvm/omtp/OmtpVvmCarrierConfigHelper.java b/src/com/android/phone/vvm/omtp/OmtpVvmCarrierConfigHelper.java
index f2df9b1..6300622 100644
--- a/src/com/android/phone/vvm/omtp/OmtpVvmCarrierConfigHelper.java
+++ b/src/com/android/phone/vvm/omtp/OmtpVvmCarrierConfigHelper.java
@@ -16,6 +16,7 @@
 package com.android.phone.vvm.omtp;
 
 import android.content.Context;
+import android.content.pm.PackageManager.NameNotFoundException;
 import android.os.PersistableBundle;
 import android.telephony.CarrierConfigManager;
 import android.telephony.SmsManager;
@@ -34,54 +35,100 @@
  */
 public class OmtpVvmCarrierConfigHelper {
     private static final String TAG = "OmtpVvmCarrierConfigHelper";
+    private Context mContext;
+    private int mSubId;
+    private PersistableBundle mCarrierConfig;
+    private String mVvmType;
 
-    public static void startActivation(Context context, int subId) {
-        OmtpMessageSender messageSender = getMessageSender(context, subId);
+    public OmtpVvmCarrierConfigHelper(Context context, int subId) {
+        mContext = context;
+        mSubId = subId;
+        mCarrierConfig = getCarrierConfig();
+        mVvmType = getVvmType();
+    }
+
+    public String getVvmType() {
+        if (mCarrierConfig == null) {
+            return null;
+        }
+
+        return mCarrierConfig.getString(
+                CarrierConfigManager.STRING_VVM_TYPE, null);
+    }
+
+    public String getCarrierVvmPackageName() {
+        if (mCarrierConfig == null) {
+            return null;
+        }
+
+        return mCarrierConfig.getString(
+                CarrierConfigManager.STRING_CARRIER_VVM_PACKAGE_NAME, null);
+    }
+
+    public boolean isOmtpVvmType() {
+        return (TelephonyManager.VVM_TYPE_OMTP.equals(mVvmType) ||
+                TelephonyManager.VVM_TYPE_CVVM.equals(mVvmType));
+    }
+
+    /**
+     * For checking upon sim insertion whether visual voicemail should be enabled. This method does
+     * so by checking if the carrier's voicemail app is installed.
+     */
+    public boolean isEnabledByDefault() {
+        String packageName = mCarrierConfig.getString(
+                CarrierConfigManager.STRING_CARRIER_VVM_PACKAGE_NAME);
+        if (packageName == null) {
+            return true;
+        }
+        try {
+            mContext.getPackageManager().getPackageInfo(packageName, 0);
+            return false;
+        } catch (NameNotFoundException e) {
+            return true;
+        }
+    }
+
+    public void startActivation() {
+        OmtpMessageSender messageSender = getMessageSender();
         if (messageSender != null) {
-            Log.i(TAG, "Requesting VVM activation for subId: " + subId);
+            Log.i(TAG, "Requesting VVM activation for subId: " + mSubId);
             messageSender.requestVvmActivation(null);
         }
     }
 
-    public static void startDeactivation(Context context, int subId) {
-        OmtpMessageSender messageSender = getMessageSender(context, subId);
+    public void startDeactivation() {
+        OmtpMessageSender messageSender = getMessageSender();
         if (messageSender != null) {
-            Log.i(TAG, "Requesting VVM deactivation for subId: " + subId);
+            Log.i(TAG, "Requesting VVM deactivation for subId: " + mSubId);
             messageSender.requestVvmDeactivation(null);
         }
     }
 
-    private static OmtpMessageSender getMessageSender(Context context, int subId) {
-        if (!SubscriptionManager.isValidSubscriptionId(subId)) {
+    private PersistableBundle getCarrierConfig() {
+        if (!SubscriptionManager.isValidSubscriptionId(mSubId)) {
             Log.w(TAG, "Invalid subscriptionId or subscriptionId not provided in intent.");
             return null;
         }
 
         CarrierConfigManager carrierConfigManager = (CarrierConfigManager)
-                context.getSystemService(Context.CARRIER_CONFIG_SERVICE);
+                mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);
         if (carrierConfigManager == null) {
             Log.w(TAG, "No carrier config service found.");
             return null;
         }
 
-        PersistableBundle carrierConfig = carrierConfigManager.getConfigForSubId(subId);
-        if (carrierConfig == null) {
+        return carrierConfigManager.getConfigForSubId(mSubId);
+    }
+
+    private OmtpMessageSender getMessageSender() {
+        if (mCarrierConfig == null) {
             Log.w(TAG, "Empty carrier config.");
             return null;
         }
 
-        String vvmType = carrierConfig.getString(
-                CarrierConfigManager.STRING_VVM_TYPE, null);
-
-        if (!(TelephonyManager.VVM_TYPE_OMTP.equals(vvmType) ||
-                TelephonyManager.VVM_TYPE_CVVM.equals(vvmType))) {
-            // This is not an OMTP visual voicemail compatible carrier.
-            return null;
-        }
-
-        int applicationPort = carrierConfig.getInt(
+        int applicationPort = mCarrierConfig.getInt(
                 CarrierConfigManager.INT_VVM_PORT_NUMBER, 0);
-        String destinationNumber = carrierConfig.getString(
+        String destinationNumber = mCarrierConfig.getString(
                 CarrierConfigManager.STRING_VVM_DESTINATION_NUMBER);
         if (TextUtils.isEmpty(destinationNumber)) {
             Log.w(TAG, "No destination number for this carrier.");
@@ -89,8 +136,8 @@
         }
 
         OmtpMessageSender messageSender = null;
-        SmsManager smsManager = SmsManager.getSmsManagerForSubscriptionId(subId);
-        switch (vvmType) {
+        SmsManager smsManager = SmsManager.getSmsManagerForSubscriptionId(mSubId);
+        switch (mVvmType) {
             case TelephonyManager.VVM_TYPE_OMTP:
                 messageSender = new OmtpStandardMessageSender(smsManager, (short) applicationPort,
                         destinationNumber, null, OmtpConstants.PROTOCOL_VERSION1_1, null);
@@ -100,7 +147,7 @@
                         destinationNumber);
                 break;
             default:
-                Log.w(TAG, "Unexpected visual voicemail type: "+vvmType);
+                Log.w(TAG, "Unexpected visual voicemail type: " + mVvmType);
         }
 
         return messageSender;
diff --git a/src/com/android/phone/vvm/omtp/SimChangeReceiver.java b/src/com/android/phone/vvm/omtp/SimChangeReceiver.java
index 5284f0c..3ac1096 100644
--- a/src/com/android/phone/vvm/omtp/SimChangeReceiver.java
+++ b/src/com/android/phone/vvm/omtp/SimChangeReceiver.java
@@ -18,13 +18,17 @@
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
+import android.telecom.PhoneAccountHandle;
 import android.telephony.CarrierConfigManager;
 import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
 import android.util.Log;
 
 import com.android.internal.telephony.IccCardConstants;
 import com.android.internal.telephony.PhoneConstants;
 import com.android.internal.telephony.TelephonyIntents;
+import com.android.phone.PhoneUtils;
+import com.android.phone.settings.VisualVoicemailSettingsUtil;
 import com.android.phone.vvm.omtp.sync.OmtpVvmSourceManager;
 
 /**
@@ -57,7 +61,24 @@
             case CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED:
                 int subId = intent.getIntExtra(PhoneConstants.SUBSCRIPTION_KEY,
                         SubscriptionManager.INVALID_SUBSCRIPTION_ID);
-                OmtpVvmCarrierConfigHelper.startActivation(context, subId);
+                OmtpVvmCarrierConfigHelper carrierConfigHelper =
+                        new OmtpVvmCarrierConfigHelper(context, subId);
+
+                if (carrierConfigHelper.isOmtpVvmType()) {
+                    PhoneAccountHandle phoneAccount = PhoneUtils.makePstnPhoneAccountHandle(
+                            SubscriptionManager.getPhoneId(subId));
+
+                    if (carrierConfigHelper.isEnabledByDefault()) {
+                        VisualVoicemailSettingsUtil.setVisualVoicemailEnabled(
+                                context, phoneAccount, true);
+                        carrierConfigHelper.startActivation();
+                    } else {
+                        // It may be that the source was not registered to begin with but we want
+                        // to run through the steps to remove the source just in case.
+                        OmtpVvmSourceManager.getInstance(context).removeSource(phoneAccount);
+                        carrierConfigHelper.startDeactivation();
+                    }
+                }
                 break;
         }
     }
diff --git a/src/com/android/phone/vvm/omtp/VvmPackageInstallReceiver.java b/src/com/android/phone/vvm/omtp/VvmPackageInstallReceiver.java
new file mode 100644
index 0000000..1541f2d
--- /dev/null
+++ b/src/com/android/phone/vvm/omtp/VvmPackageInstallReceiver.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+package com.android.phone.vvm.omtp;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.telecom.PhoneAccountHandle;
+
+import com.android.phone.PhoneUtils;
+import com.android.phone.vvm.omtp.sync.OmtpVvmSourceManager;
+
+import java.util.Set;
+
+/**
+ * When a new package is installed, check if it matches any of the vvm carrier apps of the currently
+ * enabled dialer vvm sources.
+ */
+public class VvmPackageInstallReceiver extends BroadcastReceiver {
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        if (intent.getData() == null) {
+            return;
+        }
+
+        String packageName = intent.getData().getSchemeSpecificPart();
+        if (packageName == null) {
+            return;
+        }
+
+        OmtpVvmSourceManager vvmSourceManager = OmtpVvmSourceManager.getInstance(context);
+        Set<PhoneAccountHandle> phoneAccounts = vvmSourceManager.getOmtpVvmSources();
+        for (PhoneAccountHandle phoneAccount : phoneAccounts) {
+            OmtpVvmCarrierConfigHelper carrierConfigHelper = new OmtpVvmCarrierConfigHelper(
+                    context, PhoneUtils.getSubIdForPhoneAccountHandle(phoneAccount));
+            if (packageName.equals(carrierConfigHelper.getCarrierVvmPackageName())) {
+                OmtpVvmSourceManager.getInstance(context).removeSource(phoneAccount);
+                carrierConfigHelper.startDeactivation();
+            }
+        }
+    }
+}
diff --git a/src/com/android/phone/vvm/omtp/imap/ImapHelper.java b/src/com/android/phone/vvm/omtp/imap/ImapHelper.java
index 3a197fc..684e5f5 100644
--- a/src/com/android/phone/vvm/omtp/imap/ImapHelper.java
+++ b/src/com/android/phone/vvm/omtp/imap/ImapHelper.java
@@ -66,14 +66,14 @@
             mPhoneAccount = phoneAccount;
             TempDirectory.setTempDirectory(context);
 
-            String username = VisualVoicemailSettingsUtil.getCredentialForSource(context,
+            String username = VisualVoicemailSettingsUtil.getVisualVoicemailCredentials(context,
                     OmtpConstants.IMAP_USER_NAME, phoneAccount);
-            String password = VisualVoicemailSettingsUtil.getCredentialForSource(context,
+            String password = VisualVoicemailSettingsUtil.getVisualVoicemailCredentials(context,
                     OmtpConstants.IMAP_PASSWORD, phoneAccount);
-            String serverName = VisualVoicemailSettingsUtil.getCredentialForSource(context,
+            String serverName = VisualVoicemailSettingsUtil.getVisualVoicemailCredentials(context,
                     OmtpConstants.SERVER_ADDRESS, phoneAccount);
             int port = Integer.parseInt(
-                    VisualVoicemailSettingsUtil.getCredentialForSource(context,
+                    VisualVoicemailSettingsUtil.getVisualVoicemailCredentials(context,
                             OmtpConstants.IMAP_PORT, phoneAccount));
             // TODO: determine the security protocol (e.g. ssl, tls, none, etc.)
             mImapStore = new ImapStore(
diff --git a/src/com/android/phone/vvm/omtp/sms/OmtpMessageReceiver.java b/src/com/android/phone/vvm/omtp/sms/OmtpMessageReceiver.java
index 1911f2a..867a14f 100644
--- a/src/com/android/phone/vvm/omtp/sms/OmtpMessageReceiver.java
+++ b/src/com/android/phone/vvm/omtp/sms/OmtpMessageReceiver.java
@@ -48,7 +48,7 @@
         mPhoneAccount = PhoneUtils.makePstnPhoneAccountHandle(
                 intent.getExtras().getInt(PhoneConstants.PHONE_KEY));
 
-        if (!VisualVoicemailSettingsUtil.getVisualVoicemailEnabled(mContext, mPhoneAccount)) {
+        if (!VisualVoicemailSettingsUtil.isVisualVoicemailEnabled(mContext, mPhoneAccount)) {
             Log.v(TAG, "Received vvm message for disabled vvm source.");
             return;
         }
@@ -69,7 +69,7 @@
                 processSync(message);
             } else if (messageData.getPrefix() == OmtpConstants.STATUS_SMS_PREFIX) {
                 StatusMessage message = new StatusMessage(messageData);
-                updateAccount(message);
+                updateSource(message);
             } else {
                 Log.e(TAG, "This should never have happened");
             }
@@ -113,7 +113,7 @@
         }
     }
 
-    private void updateAccount(StatusMessage message) {
+    private void updateSource(StatusMessage message) {
         OmtpVvmSourceManager vvmSourceManager =
                 OmtpVvmSourceManager.getInstance(mContext);
         VoicemailContract.Status.setStatus(mContext, mPhoneAccount,
@@ -123,7 +123,7 @@
 
         // Save the IMAP credentials in the corresponding account object so they are
         // persistent and can be retrieved.
-        VisualVoicemailSettingsUtil.setSourceCredentialsFromStatusMessage(
+        VisualVoicemailSettingsUtil.setVisualVoicemailCredentialsFromStatusMessage(
                 mContext,
                 mPhoneAccount,
                 message);
diff --git a/src/com/android/phone/vvm/omtp/sync/OmtpVvmSourceManager.java b/src/com/android/phone/vvm/omtp/sync/OmtpVvmSourceManager.java
index 9f49c2a..e7a189d 100644
--- a/src/com/android/phone/vvm/omtp/sync/OmtpVvmSourceManager.java
+++ b/src/com/android/phone/vvm/omtp/sync/OmtpVvmSourceManager.java
@@ -22,6 +22,7 @@
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 
+import com.android.internal.telephony.Phone;
 import com.android.phone.PhoneUtils;
 import com.android.phone.settings.VisualVoicemailSettingsUtil;
 
@@ -30,7 +31,9 @@
 import java.util.Set;
 
 /**
- * A singleton class designed to remember the active OMTP visual voicemail sources.
+ * A singleton class designed to remember the active OMTP visual voicemail sources. Because a
+ * voicemail source is tied 1:1 to a phone account, the phone account handle is used as the key
+ * for each voicemail source and the associated data.
  */
 public class OmtpVvmSourceManager {
     public static final String TAG = "OmtpVvmSourceManager";
@@ -71,22 +74,30 @@
     /**
      * When a voicemail source is removed, we don't always know which one was removed. Check the
      * list of registered phone accounts against the active subscriptions list and remove the
-     * inactive accounts.
+     * inactive sources.
      */
     public void removeInactiveSources() {
-        Set<PhoneAccountHandle> sources = getOmtpVvmSources();
-        for (PhoneAccountHandle source : sources) {
-            if (!PhoneUtils.isPhoneAccountActive(mSubscriptionManager, source)) {
-                VoicemailContract.Status.setStatus(mContext, source,
-                        VoicemailContract.Status.CONFIGURATION_STATE_NOT_CONFIGURED,
-                        VoicemailContract.Status.DATA_CHANNEL_STATE_NO_CONNECTION,
-                        VoicemailContract.Status.NOTIFICATION_CHANNEL_STATE_NO_CONNECTION);
-                removePhoneStateListener(source);
-                VisualVoicemailSettingsUtil.setVisualVoicemailEnabled(mContext, source, false);
+        Set<PhoneAccountHandle> phoneAccounts = getOmtpVvmSources();
+        for (PhoneAccountHandle phoneAccount : phoneAccounts) {
+            if (!PhoneUtils.isPhoneAccountActive(mSubscriptionManager, phoneAccount)) {
+                removeSource(phoneAccount);
             }
         }
     }
 
+    public void removeSource(Phone phone) {
+        removeSource(PhoneUtils.makePstnPhoneAccountHandle(phone));
+    }
+
+    public void removeSource(PhoneAccountHandle phoneAccount) {
+        VoicemailContract.Status.setStatus(mContext, phoneAccount,
+                VoicemailContract.Status.CONFIGURATION_STATE_NOT_CONFIGURED,
+                VoicemailContract.Status.DATA_CHANNEL_STATE_NO_CONNECTION,
+                VoicemailContract.Status.NOTIFICATION_CHANNEL_STATE_NO_CONNECTION);
+        removePhoneStateListener(phoneAccount);
+        VisualVoicemailSettingsUtil.setVisualVoicemailEnabled(mContext, phoneAccount, false);
+    }
+
     public void addPhoneStateListener(PhoneAccountHandle phoneAccount) {
         if (!mPhoneStateListenerMap.containsKey(phoneAccount)) {
             VvmPhoneStateListener phoneStateListener = new VvmPhoneStateListener(mContext,
@@ -126,4 +137,4 @@
         }
         return false;
     }
-}
+}
\ No newline at end of file
diff --git a/src/com/android/phone/vvm/omtp/sync/OmtpVvmSyncService.java b/src/com/android/phone/vvm/omtp/sync/OmtpVvmSyncService.java
index b5bd51f..59f5120 100644
--- a/src/com/android/phone/vvm/omtp/sync/OmtpVvmSyncService.java
+++ b/src/com/android/phone/vvm/omtp/sync/OmtpVvmSyncService.java
@@ -93,7 +93,7 @@
     }
 
     private void doSync(PhoneAccountHandle phoneAccount, String action) {
-        if (!VisualVoicemailSettingsUtil.getVisualVoicemailEnabled(this, phoneAccount)) {
+        if (!VisualVoicemailSettingsUtil.isVisualVoicemailEnabled(this, phoneAccount)) {
             Log.v(TAG, "Sync requested for disabled account");
             return;
         }