Remove vvm dependence on AccountManager, save values in shared prefs.

Instead of using the sync adapter and accounts framework,
use an intent service for syncing and shared preferences for saving
the IMAP login values. This solves the phantom account problem.
* Renamed OmtpVvmSyncAccountManager to OmtpVvmSourceManager
* Moved carrier-specific code in SimChangeReceiver to
  OmtpVvmCarrierConfigHelpoer

Bug: 20057303
Change-Id: I79347849d63bd7907df2e9aac9a14e7311215fe1
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index f663328..9e54312 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -634,15 +634,6 @@
                 <data android:scheme="sms" />
             </intent-filter>
         </receiver>
-        <service
-            android:name="android.telecom.AuthenticatorService">
-            <intent-filter>
-                <action android:name="android.accounts.AccountAuthenticator"/>
-            </intent-filter>
-            <meta-data
-                android:name="android.accounts.AccountAuthenticator"
-                android:resource="@xml/authenticator" />
-       </service>
        <receiver android:name="com.android.phone.vvm.omtp.SimChangeReceiver"
             android:exported="true">
             <intent-filter>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 4080e76..688beb1 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1209,7 +1209,7 @@
     -->
     <string name="description_dial_button">dial</string>
 
-    <!-- Dialog title for the vibration settings for voicemail notifications [CHAR LIMIT=40] -->
+    <!-- Title for the vibration settings for voicemail notifications [CHAR LIMIT=40] -->
     <string name="voicemail_notification_vibrate_when_title" msgid="8731372580674292759">Vibrate</string>
     <!-- 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>
diff --git a/res/xml/authenticator.xml b/res/xml/authenticator.xml
deleted file mode 100644
index f035d3a..0000000
--- a/res/xml/authenticator.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-<account-authenticator
-        xmlns:android="http://schemas.android.com/apk/res/android"
-        android:accountType="com.android.phone.vvm.omtp" />
\ No newline at end of file
diff --git a/src/com/android/phone/settings/VisualVoicemailSettingsUtil.java b/src/com/android/phone/settings/VisualVoicemailSettingsUtil.java
new file mode 100644
index 0000000..e3a9307
--- /dev/null
+++ b/src/com/android/phone/settings/VisualVoicemailSettingsUtil.java
@@ -0,0 +1,84 @@
+/*
+ * 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.settings;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.preference.PreferenceManager;
+import android.telecom.PhoneAccountHandle;
+
+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.
+ */
+public class VisualVoicemailSettingsUtil {
+    private static final String VISUAL_VOICEMAIL_SHARED_PREFS_KEY_PREFIX =
+            "visual_voicemail_";
+
+    private static final String IS_ENABLED_KEY = "is_enabled";
+
+    public static void setVisualVoicemailEnabled(Context context, PhoneAccountHandle phoneAccount,
+            boolean isEnabled) {
+        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
+        SharedPreferences.Editor editor = prefs.edit();
+        editor.putBoolean(
+                getVisualVoicemailSharedPrefsKey(IS_ENABLED_KEY, phoneAccount), isEnabled);
+        editor.commit();
+    }
+
+    public static boolean getVisualVoicemailEnabled(Context context,
+            PhoneAccountHandle phoneAccount) {
+        if (phoneAccount == null) {
+            return false;
+        }
+        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
+        return prefs.getBoolean(getVisualVoicemailSharedPrefsKey(IS_ENABLED_KEY, phoneAccount),
+                true);
+    }
+
+    public static void setSourceCredentialsFromStatusMessage(Context context,
+            PhoneAccountHandle phoneAccount, StatusMessage message) {
+        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
+        SharedPreferences.Editor editor = prefs.edit();
+
+        editor.putString(
+                getVisualVoicemailSharedPrefsKey(OmtpConstants.IMAP_PORT, phoneAccount),
+                message.getImapPort());
+        editor.putString(
+                getVisualVoicemailSharedPrefsKey(OmtpConstants.SERVER_ADDRESS, phoneAccount),
+                message.getServerAddress());
+        editor.putString(
+                getVisualVoicemailSharedPrefsKey(OmtpConstants.IMAP_USER_NAME, phoneAccount),
+                message.getImapUserName());
+        editor.putString(
+                getVisualVoicemailSharedPrefsKey(OmtpConstants.IMAP_PASSWORD, phoneAccount),
+                message.getImapPassword());
+        editor.commit();
+    }
+
+    public static String getCredentialForSource(Context context, String key,
+            PhoneAccountHandle phoneAccount) {
+        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
+        return prefs.getString(getVisualVoicemailSharedPrefsKey(key, phoneAccount), null);
+    }
+
+    private static String getVisualVoicemailSharedPrefsKey(String key,
+            PhoneAccountHandle phoneAccount) {
+        return VISUAL_VOICEMAIL_SHARED_PREFS_KEY_PREFIX + key + "_" + phoneAccount.getId();
+    }
+}
diff --git a/src/com/android/phone/vvm/omtp/OmtpVvmCarrierConfigHelper.java b/src/com/android/phone/vvm/omtp/OmtpVvmCarrierConfigHelper.java
new file mode 100644
index 0000000..f2df9b1
--- /dev/null
+++ b/src/com/android/phone/vvm/omtp/OmtpVvmCarrierConfigHelper.java
@@ -0,0 +1,108 @@
+/*
+ * 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.Context;
+import android.os.PersistableBundle;
+import android.telephony.CarrierConfigManager;
+import android.telephony.SmsManager;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
+import android.text.TextUtils;
+import android.util.Log;
+
+import com.android.phone.vvm.omtp.sms.OmtpCvvmMessageSender;
+import com.android.phone.vvm.omtp.sms.OmtpMessageSender;
+import com.android.phone.vvm.omtp.sms.OmtpStandardMessageSender;
+
+/**
+ * Handle activation and deactivation of a visual voicemail source. This class is necessary to
+ * retrieve carrier vvm configuration details before sending the appropriate texts.
+ */
+public class OmtpVvmCarrierConfigHelper {
+    private static final String TAG = "OmtpVvmCarrierConfigHelper";
+
+    public static void startActivation(Context context, int subId) {
+        OmtpMessageSender messageSender = getMessageSender(context, subId);
+        if (messageSender != null) {
+            Log.i(TAG, "Requesting VVM activation for subId: " + subId);
+            messageSender.requestVvmActivation(null);
+        }
+    }
+
+    public static void startDeactivation(Context context, int subId) {
+        OmtpMessageSender messageSender = getMessageSender(context, subId);
+        if (messageSender != null) {
+            Log.i(TAG, "Requesting VVM deactivation for subId: " + subId);
+            messageSender.requestVvmDeactivation(null);
+        }
+    }
+
+    private static OmtpMessageSender getMessageSender(Context context, int subId) {
+        if (!SubscriptionManager.isValidSubscriptionId(subId)) {
+            Log.w(TAG, "Invalid subscriptionId or subscriptionId not provided in intent.");
+            return null;
+        }
+
+        CarrierConfigManager carrierConfigManager = (CarrierConfigManager)
+                context.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) {
+            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(
+                CarrierConfigManager.INT_VVM_PORT_NUMBER, 0);
+        String destinationNumber = carrierConfig.getString(
+                CarrierConfigManager.STRING_VVM_DESTINATION_NUMBER);
+        if (TextUtils.isEmpty(destinationNumber)) {
+            Log.w(TAG, "No destination number for this carrier.");
+            return null;
+        }
+
+        OmtpMessageSender messageSender = null;
+        SmsManager smsManager = SmsManager.getSmsManagerForSubscriptionId(subId);
+        switch (vvmType) {
+            case TelephonyManager.VVM_TYPE_OMTP:
+                messageSender = new OmtpStandardMessageSender(smsManager, (short) applicationPort,
+                        destinationNumber, null, OmtpConstants.PROTOCOL_VERSION1_1, null);
+                break;
+            case TelephonyManager.VVM_TYPE_CVVM:
+                messageSender = new OmtpCvvmMessageSender(smsManager, (short) applicationPort,
+                        destinationNumber);
+                break;
+            default:
+                Log.w(TAG, "Unexpected visual voicemail type: "+vvmType);
+        }
+
+        return messageSender;
+    }
+}
\ No newline at end of file
diff --git a/src/com/android/phone/vvm/omtp/SimChangeReceiver.java b/src/com/android/phone/vvm/omtp/SimChangeReceiver.java
index cd7a694..5284f0c 100644
--- a/src/com/android/phone/vvm/omtp/SimChangeReceiver.java
+++ b/src/com/android/phone/vvm/omtp/SimChangeReceiver.java
@@ -18,21 +18,14 @@
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
-import android.os.PersistableBundle;
 import android.telephony.CarrierConfigManager;
-import android.telephony.SmsManager;
 import android.telephony.SubscriptionManager;
-import android.telephony.TelephonyManager;
-import android.text.TextUtils;
 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.vvm.omtp.sms.OmtpMessageSender;
-import com.android.phone.vvm.omtp.sms.OmtpStandardMessageSender;
-import com.android.phone.vvm.omtp.sms.OmtpCvvmMessageSender;
-import com.android.phone.vvm.omtp.sync.OmtpVvmSyncAccountManager;
+import com.android.phone.vvm.omtp.sync.OmtpVvmSourceManager;
 
 /**
  * This class listens to the {@link CarrierConfigManager#ACTION_CARRIER_CONFIG_CHANGED} and
@@ -44,8 +37,6 @@
  */
 public class SimChangeReceiver extends BroadcastReceiver {
     private final String TAG = "SimChangeReceiver";
-    // Whether CVVM is allowed, is currently false until settings to enable/disable vvm are added.
-    private boolean CVVM_ALLOWED = false;
 
     @Override
     public void onReceive(Context context, Intent intent) {
@@ -60,76 +51,14 @@
                 if (IccCardConstants.INTENT_VALUE_ICC_ABSENT.equals(
                         intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE))) {
                     Log.i(TAG, "Sim removed, removing inactive accounts");
-                    OmtpVvmSyncAccountManager.getInstance(context).removeInactiveAccounts();
+                    OmtpVvmSourceManager.getInstance(context).removeInactiveSources();
                 }
                 break;
             case CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED:
-                handleCarrierConfigChange(context, intent);
+                int subId = intent.getIntExtra(PhoneConstants.SUBSCRIPTION_KEY,
+                        SubscriptionManager.INVALID_SUBSCRIPTION_ID);
+                OmtpVvmCarrierConfigHelper.startActivation(context, subId);
                 break;
         }
     }
-
-    private void handleCarrierConfigChange(Context context, Intent intent) {
-        int subId = intent.getIntExtra(PhoneConstants.SUBSCRIPTION_KEY,
-                SubscriptionManager.INVALID_SUBSCRIPTION_ID);
-        if (!SubscriptionManager.isValidSubscriptionId(subId)) {
-            Log.w(TAG, "Invalid subscriptionId or subscriptionId not provided in intent.");
-            return;
-        }
-
-        CarrierConfigManager carrierConfigManager = (CarrierConfigManager)
-                context.getSystemService(Context.CARRIER_CONFIG_SERVICE);
-        if (carrierConfigManager == null) {
-            Log.w(TAG, "No carrier config service found.");
-            return;
-        }
-
-        PersistableBundle carrierConfig = carrierConfigManager.getConfigForSubId(subId);
-        if (carrierConfig == null) {
-            Log.w(TAG, "Empty carrier config.");
-            return;
-        }
-        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;
-        }
-
-        int applicationPort = carrierConfig.getInt(
-                CarrierConfigManager.INT_VVM_PORT_NUMBER, 0);
-        String destinationNumber = carrierConfig.getString(
-                CarrierConfigManager.STRING_VVM_DESTINATION_NUMBER);
-        if (TextUtils.isEmpty(destinationNumber)) {
-            Log.w(TAG, "No destination number for this carrier.");
-            return;
-        }
-
-        Log.i(TAG, "Requesting VVM activation for subId: " + subId);
-
-        OmtpMessageSender messageSender = null;
-        SmsManager smsManager = SmsManager.getSmsManagerForSubscriptionId(subId);
-        switch (vvmType) {
-            case TelephonyManager.VVM_TYPE_OMTP:
-                messageSender = new OmtpStandardMessageSender(smsManager, (short) applicationPort,
-                        destinationNumber, null, OmtpConstants.PROTOCOL_VERSION1_1, null);
-                break;
-            case TelephonyManager.VVM_TYPE_CVVM:
-                if (CVVM_ALLOWED) {
-                    messageSender = new OmtpCvvmMessageSender(smsManager, (short) applicationPort,
-                            destinationNumber);
-                }
-                break;
-            default:
-                Log.w(TAG, "Unexpected visual voicemail type: "+vvmType);
-        }
-
-        // It should be impossible for the messageSender to be null because the two types of vvm
-        // were checked earlier.
-        if (messageSender != null) {
-            messageSender.requestVvmActivation(null);
-        }
-    }
 }
\ No newline at end of file
diff --git a/src/com/android/phone/vvm/omtp/fetch/FetchVoicemailReceiver.java b/src/com/android/phone/vvm/omtp/fetch/FetchVoicemailReceiver.java
index 0110d65..de2ccf5 100644
--- a/src/com/android/phone/vvm/omtp/fetch/FetchVoicemailReceiver.java
+++ b/src/com/android/phone/vvm/omtp/fetch/FetchVoicemailReceiver.java
@@ -15,7 +15,6 @@
  */
 package com.android.phone.vvm.omtp.fetch;
 
-import android.accounts.Account;
 import android.content.BroadcastReceiver;
 import android.content.ContentResolver;
 import android.content.Context;
@@ -28,13 +27,14 @@
 import android.net.Uri;
 import android.provider.VoicemailContract;
 import android.provider.VoicemailContract.Voicemails;
+import android.telecom.PhoneAccountHandle;
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
 import android.util.Log;
 
 import com.android.phone.PhoneUtils;
 import com.android.phone.vvm.omtp.imap.ImapHelper;
-import com.android.phone.vvm.omtp.sync.OmtpVvmSyncAccountManager;
+import com.android.phone.vvm.omtp.sync.OmtpVvmSourceManager;
 
 import java.util.concurrent.Executor;
 import java.util.concurrent.Executors;
@@ -58,9 +58,9 @@
     private NetworkRequest mNetworkRequest;
     private OmtpVvmNetworkRequestCallback mNetworkCallback;
     private Context mContext;
-    private Account mAccount;
     private String mUid;
     private ConnectivityManager mConnectivityManager;
+    private PhoneAccountHandle mPhoneAccount;
 
     @Override
     public void onReceive(final Context context, Intent intent) {
@@ -98,17 +98,15 @@
                             return;
                         }
                     }
-                    mAccount = new Account(accountId,
-                            OmtpVvmSyncAccountManager.ACCOUNT_TYPE);
 
-                    if (!OmtpVvmSyncAccountManager.getInstance(context)
-                            .isAccountRegistered(mAccount)) {
+                    mPhoneAccount = PhoneUtils.makePstnPhoneAccountHandle(accountId);
+                    if (!OmtpVvmSourceManager.getInstance(context)
+                            .isVvmSourceRegistered(mPhoneAccount)) {
                         Log.w(TAG, "Account not registered - cannot retrieve message.");
                         return;
                     }
 
-                    int subId = PhoneUtils.getSubIdForPhoneAccountHandle(
-                            PhoneUtils.makePstnPhoneAccountHandle(accountId));
+                    int subId = PhoneUtils.getSubIdForPhoneAccountHandle(mPhoneAccount);
 
                     mNetworkRequest = new NetworkRequest.Builder()
                             .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
@@ -132,7 +130,7 @@
             executor.execute(new Runnable() {
                 @Override
                 public void run() {
-                    new ImapHelper(mContext, mAccount, network).fetchVoicemailPayload(
+                    new ImapHelper(mContext, mPhoneAccount, network).fetchVoicemailPayload(
                             new VoicemailFetchedCallback(mContext, mUri), mUid);
                     releaseNetwork();
                 }
diff --git a/src/com/android/phone/vvm/omtp/imap/ImapHelper.java b/src/com/android/phone/vvm/omtp/imap/ImapHelper.java
index 0d02700..3a197fc 100644
--- a/src/com/android/phone/vvm/omtp/imap/ImapHelper.java
+++ b/src/com/android/phone/vvm/omtp/imap/ImapHelper.java
@@ -15,8 +15,6 @@
  */
 package com.android.phone.vvm.omtp.imap;
 
-import android.accounts.Account;
-import android.accounts.AccountManager;
 import android.content.Context;
 import android.net.Network;
 import android.telecom.PhoneAccountHandle;
@@ -24,7 +22,6 @@
 
 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;
@@ -39,6 +36,7 @@
 import com.android.phone.common.mail.store.ImapStore;
 import com.android.phone.common.mail.store.imap.ImapConstants;
 import com.android.phone.common.mail.utils.LogUtils;
+import com.android.phone.settings.VisualVoicemailSettingsUtil;
 import com.android.phone.vvm.omtp.OmtpConstants;
 import com.android.phone.vvm.omtp.fetch.VoicemailFetchedCallback;
 
@@ -62,18 +60,21 @@
     private Context mContext;
     private PhoneAccountHandle mPhoneAccount;
 
-    public ImapHelper(Context context, Account account, Network network) {
+    public ImapHelper(Context context, PhoneAccountHandle phoneAccount, Network network) {
         try {
             mContext = context;
-            mPhoneAccount = PhoneUtils.makePstnPhoneAccountHandle(account.name);
+            mPhoneAccount = phoneAccount;
             TempDirectory.setTempDirectory(context);
 
-            AccountManager accountManager = AccountManager.get(context);
-            String username = accountManager.getUserData(account, OmtpConstants.IMAP_USER_NAME);
-            String password = accountManager.getUserData(account, OmtpConstants.IMAP_PASSWORD);
-            String serverName = accountManager.getUserData(account, OmtpConstants.SERVER_ADDRESS);
+            String username = VisualVoicemailSettingsUtil.getCredentialForSource(context,
+                    OmtpConstants.IMAP_USER_NAME, phoneAccount);
+            String password = VisualVoicemailSettingsUtil.getCredentialForSource(context,
+                    OmtpConstants.IMAP_PASSWORD, phoneAccount);
+            String serverName = VisualVoicemailSettingsUtil.getCredentialForSource(context,
+                    OmtpConstants.SERVER_ADDRESS, phoneAccount);
             int port = Integer.parseInt(
-                    accountManager.getUserData(account, OmtpConstants.IMAP_PORT));
+                    VisualVoicemailSettingsUtil.getCredentialForSource(context,
+                            OmtpConstants.IMAP_PORT, phoneAccount));
             // TODO: determine the security protocol (e.g. ssl, tls, none, etc.)
             mImapStore = new ImapStore(
                     context, username, password, port, serverName, ImapStore.FLAG_NONE, network);
diff --git a/src/com/android/phone/vvm/omtp/sms/OmtpMessageReceiver.java b/src/com/android/phone/vvm/omtp/sms/OmtpMessageReceiver.java
index 222ea26..1911f2a 100644
--- a/src/com/android/phone/vvm/omtp/sms/OmtpMessageReceiver.java
+++ b/src/com/android/phone/vvm/omtp/sms/OmtpMessageReceiver.java
@@ -15,7 +15,6 @@
  */
 package com.android.phone.vvm.omtp.sms;
 
-import android.accounts.Account;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -28,8 +27,9 @@
 
 import com.android.internal.telephony.PhoneConstants;
 import com.android.phone.PhoneUtils;
+import com.android.phone.settings.VisualVoicemailSettingsUtil;
 import com.android.phone.vvm.omtp.OmtpConstants;
-import com.android.phone.vvm.omtp.sync.OmtpVvmSyncAccountManager;
+import com.android.phone.vvm.omtp.sync.OmtpVvmSourceManager;
 import com.android.phone.vvm.omtp.sync.OmtpVvmSyncService;
 import com.android.phone.vvm.omtp.sync.VoicemailsQueryHelper;
 
@@ -48,6 +48,11 @@
         mPhoneAccount = PhoneUtils.makePstnPhoneAccountHandle(
                 intent.getExtras().getInt(PhoneConstants.PHONE_KEY));
 
+        if (!VisualVoicemailSettingsUtil.getVisualVoicemailEnabled(mContext, mPhoneAccount)) {
+            Log.v(TAG, "Received vvm message for disabled vvm source.");
+            return;
+        }
+
         SmsMessage[] messages = Telephony.Sms.Intents.getMessagesFromIntent(intent);
         StringBuilder messageBody = new StringBuilder();
 
@@ -94,11 +99,9 @@
                 queryHelper.insertIfUnique(voicemail);
                 break;
             case OmtpConstants.MAILBOX_UPDATE:
-                Account account = new Account(
-                        mPhoneAccount.getId(), OmtpVvmSyncAccountManager.ACCOUNT_TYPE);
                 Intent serviceIntent = new Intent(mContext, OmtpVvmSyncService.class);
                 serviceIntent.setAction(OmtpVvmSyncService.SYNC_DOWNLOAD_ONLY);
-                serviceIntent.putExtra(OmtpVvmSyncService.EXTRA_ACCOUNT, account);
+                serviceIntent.putExtra(OmtpVvmSyncService.EXTRA_PHONE_ACCOUNT, mPhoneAccount);
                 mContext.startService(serviceIntent);
                 break;
             case OmtpConstants.GREETINGS_UPDATE:
@@ -111,31 +114,26 @@
     }
 
     private void updateAccount(StatusMessage message) {
-        OmtpVvmSyncAccountManager vvmAccountSyncManager =
-                OmtpVvmSyncAccountManager.getInstance(mContext);
-        Account account = new Account(mPhoneAccount.getId(),
-                OmtpVvmSyncAccountManager.ACCOUNT_TYPE);
-
-        if (!vvmAccountSyncManager.isAccountRegistered(account)) {
-            // If the account has not been previously registered, it means that this STATUS sms
-            // is a result of the ACTIVATE sms, so register the voicemail source.
-            vvmAccountSyncManager.createSyncAccount(account);
-            VoicemailContract.Status.setStatus(mContext, mPhoneAccount,
-                    VoicemailContract.Status.CONFIGURATION_STATE_OK,
-                    VoicemailContract.Status.DATA_CHANNEL_STATE_OK,
-                    VoicemailContract.Status.NOTIFICATION_CHANNEL_STATE_OK);
-        }
+        OmtpVvmSourceManager vvmSourceManager =
+                OmtpVvmSourceManager.getInstance(mContext);
+        VoicemailContract.Status.setStatus(mContext, mPhoneAccount,
+                VoicemailContract.Status.CONFIGURATION_STATE_OK,
+                VoicemailContract.Status.DATA_CHANNEL_STATE_OK,
+                VoicemailContract.Status.NOTIFICATION_CHANNEL_STATE_OK);
 
         // Save the IMAP credentials in the corresponding account object so they are
         // persistent and can be retrieved.
-        vvmAccountSyncManager.setAccountCredentialsFromStatusMessage(account, message);
+        VisualVoicemailSettingsUtil.setSourceCredentialsFromStatusMessage(
+                mContext,
+                mPhoneAccount,
+                message);
 
         // Add a phone state listener so that changes to the communication channels can be recorded.
-        vvmAccountSyncManager.addPhoneStateListener(account);
+        vvmSourceManager.addPhoneStateListener(mPhoneAccount);
 
         Intent serviceIntent = new Intent(mContext, OmtpVvmSyncService.class);
         serviceIntent.setAction(OmtpVvmSyncService.SYNC_FULL_SYNC);
-        serviceIntent.putExtra(OmtpVvmSyncService.EXTRA_ACCOUNT, account);
+        serviceIntent.putExtra(OmtpVvmSyncService.EXTRA_PHONE_ACCOUNT, mPhoneAccount);
         mContext.startService(serviceIntent);
     }
-}
+}
\ No newline at end of file
diff --git a/src/com/android/phone/vvm/omtp/sync/OmtpVvmSourceManager.java b/src/com/android/phone/vvm/omtp/sync/OmtpVvmSourceManager.java
new file mode 100644
index 0000000..9f49c2a
--- /dev/null
+++ b/src/com/android/phone/vvm/omtp/sync/OmtpVvmSourceManager.java
@@ -0,0 +1,129 @@
+/*
+ * 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.sync;
+
+import android.content.Context;
+import android.provider.VoicemailContract;
+import android.telecom.PhoneAccountHandle;
+import android.telephony.PhoneStateListener;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
+
+import com.android.phone.PhoneUtils;
+import com.android.phone.settings.VisualVoicemailSettingsUtil;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * A singleton class designed to remember the active OMTP visual voicemail sources.
+ */
+public class OmtpVvmSourceManager {
+    public static final String TAG = "OmtpVvmSourceManager";
+
+    private static OmtpVvmSourceManager sInstance = new OmtpVvmSourceManager();
+
+    private Context mContext;
+    private SubscriptionManager mSubscriptionManager;
+    private TelephonyManager mTelephonyManager;
+    // Each phone account is associated with a phone state listener for updates to whether the
+    // device is able to sync.
+    private Map<PhoneAccountHandle, PhoneStateListener> mPhoneStateListenerMap;
+
+    /**
+     * Private constructor. Instance should only be acquired through getInstance().
+     */
+    private OmtpVvmSourceManager() {}
+
+    public static OmtpVvmSourceManager getInstance(Context context) {
+        sInstance.setup(context);
+        return sInstance;
+    }
+
+    /**
+     * Set the context and system services so they do not need to be retrieved every time.
+     * @param context The context to get the subscription and telephony manager for.
+     */
+    private void setup(Context context) {
+        if (mContext == null) {
+            mContext = context;
+            mSubscriptionManager = SubscriptionManager.from(context);
+            mTelephonyManager = (TelephonyManager)
+                    mContext.getSystemService(Context.TELEPHONY_SERVICE);
+            mPhoneStateListenerMap = new HashMap<PhoneAccountHandle, PhoneStateListener>();
+        }
+    }
+
+    /**
+     * 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.
+     */
+    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);
+            }
+        }
+    }
+
+    public void addPhoneStateListener(PhoneAccountHandle phoneAccount) {
+        if (!mPhoneStateListenerMap.containsKey(phoneAccount)) {
+            VvmPhoneStateListener phoneStateListener = new VvmPhoneStateListener(mContext,
+                    PhoneUtils.makePstnPhoneAccountHandle(phoneAccount.getId()));
+            mPhoneStateListenerMap.put(phoneAccount, phoneStateListener);
+            mTelephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_SERVICE_STATE);
+        }
+    }
+
+    public void removePhoneStateListener(PhoneAccountHandle phoneAccount) {
+        PhoneStateListener phoneStateListener =
+                mPhoneStateListenerMap.remove(phoneAccount);
+        mTelephonyManager.listen(phoneStateListener, 0);
+    }
+
+    public Set<PhoneAccountHandle> getOmtpVvmSources() {
+        return mPhoneStateListenerMap.keySet();
+    }
+
+    /**
+     * Check if a certain account is registered.
+     *
+     * @param phoneAccount The account to look for.
+     * @return {@code true} if the account is in the list of registered OMTP voicemail sync
+     * accounts. {@code false} otherwise.
+     */
+    public boolean isVvmSourceRegistered(PhoneAccountHandle phoneAccount) {
+        if (phoneAccount == null) {
+            return false;
+        }
+
+        Set<PhoneAccountHandle> sources = getOmtpVvmSources();
+        for (PhoneAccountHandle source : sources) {
+            if (phoneAccount.equals(source)) {
+                return true;
+            }
+        }
+        return false;
+    }
+}
diff --git a/src/com/android/phone/vvm/omtp/sync/OmtpVvmSyncAccountManager.java b/src/com/android/phone/vvm/omtp/sync/OmtpVvmSyncAccountManager.java
deleted file mode 100644
index 6554b71..0000000
--- a/src/com/android/phone/vvm/omtp/sync/OmtpVvmSyncAccountManager.java
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * 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.sync;
-
-import android.accounts.Account;
-import android.accounts.AccountManager;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.provider.VoicemailContract;
-import android.telecom.PhoneAccountHandle;
-import android.telephony.PhoneStateListener;
-import android.telephony.SubscriptionManager;
-import android.telephony.TelephonyManager;
-import android.util.Log;
-
-import com.android.phone.PhoneUtils;
-import com.android.phone.vvm.omtp.OmtpConstants;
-import com.android.phone.vvm.omtp.sms.StatusMessage;
-
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * A singleton class designed to assist in OMTP visual voicemail sync behavior.
- */
-public class OmtpVvmSyncAccountManager {
-    public static final String TAG = "OmtpVvmSyncAccountManager";
-    // Constants
-    // The authority for the sync adapter's content provider
-    public static final String AUTHORITY = "com.android.voicemail";
-    // An account type, in the form of a domain name
-    public static final String ACCOUNT_TYPE = "com.android.phone.vvm.omtp";
-
-    private static OmtpVvmSyncAccountManager sInstance = new OmtpVvmSyncAccountManager();
-
-    private Context mContext;
-    private SubscriptionManager mSubscriptionManager;
-    private AccountManager mAccountManager;
-    private TelephonyManager mTelephonyManager;
-    // Each account is associated with a phone state listener for updates to whether the device
-    // is able to sync.
-    private Map<Account, PhoneStateListener> mPhoneStateListenerMap;
-
-    /**
-     * Private constructor. Instance should only be acquired through getInstance().
-     */
-    private OmtpVvmSyncAccountManager() {}
-
-    public static OmtpVvmSyncAccountManager getInstance(Context context) {
-        sInstance.setup(context);
-        return sInstance;
-    }
-
-    /**
-     * Set the context and system services so they do not need to be retrieved every time.
-     * @param context The context to get the account manager and subscription manager for.
-     */
-    private void setup(Context context) {
-        if (mContext == null) {
-            mContext = context;
-            mSubscriptionManager = SubscriptionManager.from(context);
-            mAccountManager = AccountManager.get(context);
-            mTelephonyManager = (TelephonyManager)
-                    mContext.getSystemService(Context.TELEPHONY_SERVICE);
-            mPhoneStateListenerMap = new HashMap<Account, PhoneStateListener>();
-        }
-    }
-
-    /**
-     * Register a sync account. There should be a one to one mapping of sync account to voicemail
-     * source. These sync accounts primarily service the purpose of keeping track of how many OMTP
-     * voicemail sources are active and which phone accounts they correspond to.
-     *
-     * @param account The account to register
-     */
-    public void createSyncAccount(Account account) {
-        // Add the account and account type, no password or user data
-        if (mAccountManager.addAccountExplicitly(account, null, null)) {
-             ContentResolver.setIsSyncable(account, AUTHORITY, 1);
-             ContentResolver.setSyncAutomatically(account, AUTHORITY, true);
-        } else {
-            Log.w(TAG, "Attempted to re-register existing account.");
-        }
-    }
-
-    /**
-     * When a voicemail source is removed, we don't always know which one was removed. Check the
-     * list of registered sync accounts against the active subscriptions list and remove the
-     * inactive accounts.
-     */
-    public void removeInactiveAccounts() {
-        Account[] registeredAccounts = mAccountManager.getAccountsByType(ACCOUNT_TYPE);
-        for (int i = 0; i < registeredAccounts.length; i++) {
-            PhoneAccountHandle handle = PhoneUtils.makePstnPhoneAccountHandle(
-                    registeredAccounts[i].name);
-            if (!PhoneUtils.isPhoneAccountActive(mSubscriptionManager, handle)) {
-                mAccountManager.removeAccount(registeredAccounts[i], null, null, null);
-                VoicemailContract.Status.setStatus(mContext, handle,
-                        VoicemailContract.Status.CONFIGURATION_STATE_NOT_CONFIGURED,
-                        VoicemailContract.Status.DATA_CHANNEL_STATE_NO_CONNECTION,
-                        VoicemailContract.Status.NOTIFICATION_CHANNEL_STATE_NO_CONNECTION);
-
-                removePhoneStateListener(registeredAccounts[i]);
-            }
-        }
-    }
-
-    public void addPhoneStateListener(Account account) {
-        if (!mPhoneStateListenerMap.containsKey(account)) {
-            VvmPhoneStateListener phoneStateListener = new VvmPhoneStateListener(mContext,
-                    PhoneUtils.makePstnPhoneAccountHandle(account.name));
-            mPhoneStateListenerMap.put(account, phoneStateListener);
-            mTelephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_SERVICE_STATE);
-        }
-    }
-
-    public void removePhoneStateListener(Account account) {
-        PhoneStateListener phoneStateListener =
-                mPhoneStateListenerMap.remove(account);
-        mTelephonyManager.listen(phoneStateListener, 0);
-    }
-
-    public Account[] getOmtpAccounts() {
-        return mAccountManager.getAccountsByType(ACCOUNT_TYPE);
-    }
-
-    /**
-     * Check if a certain account is registered.
-     *
-     * @param account The account to look for.
-     * @return {@code true} if the account is in the list of registered OMTP voicemail sync
-     * accounts. {@code false} otherwise.
-     */
-    public boolean isAccountRegistered(Account account) {
-        Account[] accounts = getOmtpAccounts();
-        for (int i = 0; i < accounts.length; i++) {
-            if (account.equals(accounts[i])) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    /**
-     * Set the IMAP credentials as extra fields in the account.
-     *
-     * @param account The account to add credentials to.
-     * @param message The status message to extract the fields from.
-     */
-    public void setAccountCredentialsFromStatusMessage(Account account, StatusMessage message) {
-        mAccountManager.setUserData(account, OmtpConstants.IMAP_PORT, message.getImapPort());
-        mAccountManager.setUserData(account, OmtpConstants.SERVER_ADDRESS,
-                message.getServerAddress());
-        mAccountManager.setUserData(account, OmtpConstants.IMAP_USER_NAME,
-                message.getImapUserName());
-        mAccountManager.setUserData(account, OmtpConstants.IMAP_PASSWORD,
-                message.getImapPassword());
-    }
-}
diff --git a/src/com/android/phone/vvm/omtp/sync/OmtpVvmSyncService.java b/src/com/android/phone/vvm/omtp/sync/OmtpVvmSyncService.java
index 0a6b5c1..b5bd51f 100644
--- a/src/com/android/phone/vvm/omtp/sync/OmtpVvmSyncService.java
+++ b/src/com/android/phone/vvm/omtp/sync/OmtpVvmSyncService.java
@@ -15,7 +15,6 @@
  */
 package com.android.phone.vvm.omtp.sync;
 
-import android.accounts.Account;
 import android.app.IntentService;
 import android.content.Context;
 import android.content.Intent;
@@ -25,15 +24,18 @@
 import android.net.NetworkCapabilities;
 import android.net.NetworkRequest;
 import android.provider.VoicemailContract;
+import android.telecom.PhoneAccountHandle;
 import android.telecom.Voicemail;
 import android.util.Log;
 
 import com.android.phone.PhoneUtils;
+import com.android.phone.settings.VisualVoicemailSettingsUtil;
 import com.android.phone.vvm.omtp.imap.ImapHelper;
 
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 /**
  * Sync OMTP visual voicemail.
@@ -48,7 +50,7 @@
     /** Only download from the server. */
     public static final String SYNC_DOWNLOAD_ONLY = "download_only";
     /** The account to sync. */
-    public static final String EXTRA_ACCOUNT = "account";
+    public static final String EXTRA_PHONE_ACCOUNT = "phone_account";
 
     // Timeout used to call ConnectivityManager.requestNetwork
     private static final int NETWORK_REQUEST_TIMEOUT_MILLIS = 60 * 1000;
@@ -75,48 +77,55 @@
         }
 
         String action = intent.getAction();
-        OmtpVvmSyncAccountManager syncAccountManager = OmtpVvmSyncAccountManager.getInstance(this);
-        Account account = intent.getParcelableExtra(EXTRA_ACCOUNT);
-        if (account != null && syncAccountManager.isAccountRegistered(account)) {
-            Log.v(TAG, "Sync requested: " + action + " - for account: " + account.name);
-            doSync(account, action);
+        PhoneAccountHandle phoneAccount = intent.getParcelableExtra(EXTRA_PHONE_ACCOUNT);
+        if (phoneAccount != null) {
+            Log.v(TAG, "Sync requested: " + action + " - for account: " + phoneAccount);
+            doSync(phoneAccount, action);
         } else {
             Log.v(TAG, "Sync requested: " + action + " - for all accounts");
-            Account[] accounts = syncAccountManager.getOmtpAccounts();
-            for (int i = 0; i < accounts.length; i++) {
-                doSync(accounts[i], action);
+            OmtpVvmSourceManager vvmSourceManager =
+                    OmtpVvmSourceManager.getInstance(this);
+            Set<PhoneAccountHandle> sources = vvmSourceManager.getOmtpVvmSources();
+            for (PhoneAccountHandle source : sources) {
+                doSync(source, action);
             }
         }
     }
 
-    private void doSync(Account account, String action) {
-        int subId = PhoneUtils.getSubIdForPhoneAccountHandle(
-                PhoneUtils.makePstnPhoneAccountHandle(account.name));
+    private void doSync(PhoneAccountHandle phoneAccount, String action) {
+        if (!VisualVoicemailSettingsUtil.getVisualVoicemailEnabled(this, phoneAccount)) {
+            Log.v(TAG, "Sync requested for disabled account");
+            return;
+        }
+
+        int subId = PhoneUtils.getSubIdForPhoneAccountHandle(phoneAccount);
 
         NetworkRequest networkRequest = new NetworkRequest.Builder()
                 .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
                 .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
                 .setNetworkSpecifier(Integer.toString(subId))
                 .build();
-        NetworkCallback networkCallback = new OmtpVvmNetworkRequestCallback(this, account, action);
+        NetworkCallback networkCallback = new OmtpVvmNetworkRequestCallback(this, phoneAccount,
+                action);
         getConnectivityManager().requestNetwork(
                 networkRequest, networkCallback, NETWORK_REQUEST_TIMEOUT_MILLIS);
     }
 
     private class OmtpVvmNetworkRequestCallback extends ConnectivityManager.NetworkCallback {
         Context mContext;
-        Account mAccount;
+        PhoneAccountHandle mPhoneAccount;
         String mAction;
 
-        public OmtpVvmNetworkRequestCallback(Context context, Account account, String action) {
+        public OmtpVvmNetworkRequestCallback(Context context, PhoneAccountHandle phoneAccount,
+                String action) {
             mContext = context;
-            mAccount = account;
+            mPhoneAccount = phoneAccount;
             mAction = action;
         }
 
         @Override
         public void onAvailable(final Network network) {
-            ImapHelper imapHelper = new ImapHelper(mContext, mAccount, network);
+            ImapHelper imapHelper = new ImapHelper(mContext, mPhoneAccount, network);
             if (SYNC_FULL_SYNC.equals(mAction) || SYNC_UPLOAD_ONLY.equals(mAction)) {
                 upload(imapHelper);
             }
diff --git a/src/com/android/phone/vvm/omtp/sync/VoicemailProviderChangeReceiver.java b/src/com/android/phone/vvm/omtp/sync/VoicemailProviderChangeReceiver.java
index fc1823e..0885d65 100644
--- a/src/com/android/phone/vvm/omtp/sync/VoicemailProviderChangeReceiver.java
+++ b/src/com/android/phone/vvm/omtp/sync/VoicemailProviderChangeReceiver.java
@@ -18,6 +18,7 @@
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
+import android.provider.VoicemailContract;
 
 /**
  * Receives changes to the voicemail provider so they can be sent to the voicemail server.
@@ -25,9 +26,10 @@
 public class VoicemailProviderChangeReceiver extends BroadcastReceiver {
     @Override
     public void onReceive(Context context, Intent intent) {
-        OmtpVvmSyncAccountManager syncAccountManager =
-                OmtpVvmSyncAccountManager.getInstance(context);
-        if (syncAccountManager.getOmtpAccounts().length > 0) {
+        boolean isSelfChanged = intent.getBooleanExtra(VoicemailContract.EXTRA_SELF_CHANGE, false);
+        OmtpVvmSourceManager vvmSourceManager =
+                OmtpVvmSourceManager.getInstance(context);
+        if (vvmSourceManager.getOmtpVvmSources().size() > 0 && !isSelfChanged) {
             Intent serviceIntent = new Intent(context, OmtpVvmSyncService.class);
             serviceIntent.setAction(OmtpVvmSyncService.SYNC_UPLOAD_ONLY);
             context.startService(serviceIntent);