Merge "Handle non-ready provisioning status on non-VVM3" into nyc-mr1-dev
diff --git a/sip/res/values/strings.xml b/sip/res/values/strings.xml
index 6ac7c8d..d515736 100644
--- a/sip/res/values/strings.xml
+++ b/sip/res/values/strings.xml
@@ -115,8 +115,12 @@
     <!-- Help text of the auth_username field. [CHAR LIMIT=NONE] -->
     <string name="auth_username_summary">Username used for authentication</string>
 
-    <!-- Initial status of the preferences is '<Not set>'. [CHAR LIMIT=NONE] -->
-    <string name="default_preference_summary">&lt;Not set&gt;</string>
+    <!-- Initial status of the username preference is '<Not set>'. [CHAR LIMIT=NONE] -->
+    <string name="default_preference_summary_username">&lt;Not set&gt;</string>
+    <!-- Initial status of the password preference is '<Not set>'. [CHAR LIMIT=NONE] -->
+    <string name="default_preference_summary_password">&lt;Not set&gt;</string>
+    <!-- Initial status of the domain address preference is '<Not set>'. [CHAR LIMIT=NONE] -->
+    <string name="default_preference_summary_domain_address">&lt;Not set&gt;</string>
     <!-- Default value for the display-name preference summary. [CHAR LIMIT=NONE] -->
     <string name="display_name_summary">&lt;Same as username&gt;</string>
     <!-- Default value for the outbound-proxy-address preference summary. [CHAR LIMIT=NONE] -->
diff --git a/sip/res/xml/sip_edit.xml b/sip/res/xml/sip_edit.xml
index 15e5ce1..58a8a92 100644
--- a/sip/res/xml/sip_edit.xml
+++ b/sip/res/xml/sip_edit.xml
@@ -22,7 +22,7 @@
         android:key="@string/username"
         android:title="@string/username_title"
         android:dialogTitle="@string/username_title"
-        android:summary="@string/default_preference_summary"
+        android:summary="@string/default_preference_summary_username"
         android:persistent="false"
         android:singleLine="true"
         android:inputType="textNoSuggestions"/>
@@ -32,7 +32,7 @@
         android:title="@string/password_title"
         android:dialogTitle="@string/password_title"
         android:password="true"
-        android:summary="@string/default_preference_summary"
+        android:summary="@string/default_preference_summary_password"
         android:persistent="false"
         android:singleLine="true"/>
 
@@ -40,7 +40,7 @@
         android:key="@string/domain_address"
         android:title="@string/domain_address_title"
         android:dialogTitle="@string/domain_address_title"
-        android:summary="@string/default_preference_summary"
+        android:summary="@string/default_preference_summary_domain_address"
         android:persistent="false"
         android:singleLine="true"
         android:inputType="textNoSuggestions"/>
diff --git a/sip/src/com/android/services/telephony/sip/SipEditor.java b/sip/src/com/android/services/telephony/sip/SipEditor.java
index 8bc7734..f6e9c22 100644
--- a/sip/src/com/android/services/telephony/sip/SipEditor.java
+++ b/sip/src/com/android/services/telephony/sip/SipEditor.java
@@ -68,9 +68,10 @@
     private SipAccountRegistry mSipAccountRegistry;
 
     enum PreferenceKey {
-        Username(R.string.username, 0, R.string.default_preference_summary),
-        Password(R.string.password, 0, R.string.default_preference_summary),
-        DomainAddress(R.string.domain_address, 0, R.string.default_preference_summary),
+        Username(R.string.username, 0, R.string.default_preference_summary_username),
+        Password(R.string.password, 0, R.string.default_preference_summary_password),
+        DomainAddress(R.string.domain_address, 0,
+                R.string.default_preference_summary_domain_address),
         DisplayName(R.string.display_name, 0, R.string.display_name_summary),
         ProxyAddress(R.string.proxy_address, 0, R.string.optional_summary),
         Port(R.string.port, R.string.default_port, R.string.default_port),
diff --git a/src/com/android/phone/PhoneGlobals.java b/src/com/android/phone/PhoneGlobals.java
index 808a5d6..4ff8d8e 100644
--- a/src/com/android/phone/PhoneGlobals.java
+++ b/src/com/android/phone/PhoneGlobals.java
@@ -34,10 +34,8 @@
 import android.os.Message;
 import android.os.PersistableBundle;
 import android.os.PowerManager;
-import android.os.ServiceManager;
 import android.os.SystemClock;
 import android.os.SystemProperties;
-import android.os.SystemService;
 import android.os.UpdateLock;
 import android.os.UserManager;
 import android.preference.PreferenceManager;
@@ -59,7 +57,6 @@
 import com.android.internal.telephony.TelephonyIntents;
 import com.android.phone.common.CallLogAsync;
 import com.android.phone.settings.SettingsConstants;
-import com.android.server.sip.SipService;
 import com.android.services.telephony.activation.SimActivationManager;
 import com.android.services.telephony.sip.SipUtil;
 
@@ -851,6 +848,8 @@
      * @param subId the subscription id we should dismiss the notification for.
      */
     public void clearMwiIndicator(int subId) {
-        notificationMgr.updateMwi(subId, false);
+        // Setting voiceMessageCount to 0 will remove the current notification and clear the system
+        // cached value.
+        getPhone(subId).setVoiceMessageCount(0);
     }
 }
diff --git a/src/com/android/phone/common/mail/store/ImapConnection.java b/src/com/android/phone/common/mail/store/ImapConnection.java
index 0360e3e..6945b94 100644
--- a/src/com/android/phone/common/mail/store/ImapConnection.java
+++ b/src/com/android/phone/common/mail/store/ImapConnection.java
@@ -30,6 +30,7 @@
 import com.android.phone.common.mail.store.imap.ImapUtility;
 import com.android.phone.common.mail.utils.LogUtils;
 import com.android.phone.vvm.omtp.OmtpEvents;
+import com.android.phone.vvm.omtp.VvmLog;
 
 import java.io.IOException;
 import java.util.ArrayList;
@@ -110,7 +111,7 @@
             // The server should greet us with something like
             // * OK IMAP4rev1 Server
             // consume the response before doing anything else.
-            ImapResponse response = mParser.readResponse();
+            ImapResponse response = mParser.readResponse(false);
             if (!response.isOk()) {
                 mImapStore.getImapHelper()
                         .handleEvent(OmtpEvents.DATA_INVALID_INITIAL_SERVER_RESPONSE);
@@ -138,11 +139,26 @@
         }
     }
 
+    void logout() {
+        try {
+            sendCommand(ImapConstants.LOGOUT, false);
+            if (!mParser.readResponse(true).is(0, ImapConstants.BYE)) {
+                VvmLog.e(TAG, "Server did not respond LOGOUT with BYE");
+            }
+            if (!mParser.readResponse(false).isOk()) {
+                VvmLog.e(TAG, "Server did not respond OK after LOGOUT");
+            }
+        } catch (IOException | MessagingException e) {
+            VvmLog.e(TAG, "Error while logging out:" + e);
+        }
+    }
+
     /**
      * Closes the connection and releases all resources. This connection can not be used again
      * until {@link #setStore(ImapStore)} is called.
      */
     void close() {
+        logout();
         if (mTransport != null) {
             mTransport.close();
             mTransport = null;
@@ -323,7 +339,7 @@
     }
 
     public ImapResponse readResponse() throws IOException, MessagingException {
-        return mParser.readResponse();
+        return mParser.readResponse(false);
     }
 
     public List<ImapResponse> executeSimpleCommand(String command)
@@ -377,11 +393,12 @@
      * @throws IOException
      * @throws MessagingException
      */
-    List<ImapResponse> getCommandResponses() throws IOException, MessagingException {
+    List<ImapResponse> getCommandResponses()
+            throws IOException, MessagingException {
         final List<ImapResponse> responses = new ArrayList<ImapResponse>();
         ImapResponse response;
         do {
-            response = mParser.readResponse();
+            response = mParser.readResponse(false);
             responses.add(response);
         } while (!(response.isTagged() || response.isContinuationRequest()));
 
diff --git a/src/com/android/phone/common/mail/store/ImapFolder.java b/src/com/android/phone/common/mail/store/ImapFolder.java
index fe3df30..4abb7f5 100644
--- a/src/com/android/phone/common/mail/store/ImapFolder.java
+++ b/src/com/android/phone/common/mail/store/ImapFolder.java
@@ -94,23 +94,7 @@
     public void open(String mode) throws MessagingException {
         try {
             if (isOpen()) {
-                if (mMode == mode) {
-                    // Make sure the connection is valid.
-                    // If it's not we'll close it down and continue on to get a new one.
-                    try {
-                        mConnection.executeSimpleCommand(ImapConstants.NOOP);
-                        return;
-
-                    } catch (IOException ioe) {
-                        mStore.getImapHelper().handleEvent(OmtpEvents.DATA_GENERIC_IMAP_IOE);
-                        ioExceptionHandler(mConnection, ioe);
-                    } finally {
-                        destroyResponses();
-                    }
-                } else {
-                    // Return the connection to the pool, if exists.
-                    close(false);
-                }
+                throw new AssertionError("Duplicated open on ImapFolder");
             }
             synchronized (this) {
                 mConnection = mStore.getConnection();
@@ -161,7 +145,6 @@
         }
         mMessageCount = -1;
         synchronized (this) {
-            mStore.closeConnection();
             mConnection = null;
         }
     }
diff --git a/src/com/android/phone/common/mail/store/imap/ImapResponseParser.java b/src/com/android/phone/common/mail/store/imap/ImapResponseParser.java
index a6d2df6..6fc5abe 100644
--- a/src/com/android/phone/common/mail/store/imap/ImapResponseParser.java
+++ b/src/com/android/phone/common/mail/store/imap/ImapResponseParser.java
@@ -136,10 +136,12 @@
      * is stored in the internal storage.  When the {@link ImapResponse} is no longer used
      * {@link #destroyResponses} should be called to destroy all the responses in the array.
      *
+     * @param byeExpected is a untagged BYE response expected? If not proper cleanup will be done
+     * and {@link ByeException} will be thrown.
      * @return the parsed {@link ImapResponse} object.
-     * @exception ByeException when detects BYE.
+     * @exception ByeException when detects BYE and <code>byeExpected</code> is false.
      */
-    public ImapResponse readResponse() throws IOException, MessagingException {
+    public ImapResponse readResponse(boolean byeExpected) throws IOException, MessagingException {
         ImapResponse response = null;
         try {
             response = parseResponse();
@@ -154,7 +156,7 @@
         }
 
         // Handle this outside of try-catch.  We don't have to dump protocol log when getting BYE.
-        if (response.is(0, ImapConstants.BYE)) {
+        if (!byeExpected && response.is(0, ImapConstants.BYE)) {
             Log.w(TAG, ByeException.MESSAGE);
             response.destroy();
             throw new ByeException();
diff --git a/src/com/android/phone/settings/VoicemailChangePinDialogPreference.java b/src/com/android/phone/settings/VoicemailChangePinDialogPreference.java
index e4230ff..3411228 100644
--- a/src/com/android/phone/settings/VoicemailChangePinDialogPreference.java
+++ b/src/com/android/phone/settings/VoicemailChangePinDialogPreference.java
@@ -175,8 +175,7 @@
         @Override
         public void onAvailable(Network network) {
             super.onAvailable(network);
-            ImapHelper helper = new ImapHelper(getContext(), mPhoneAccountHandle, network);
-            try {
+            try (ImapHelper helper = new ImapHelper(getContext(), mPhoneAccountHandle, network)) {
                 @ChangePinResult int result =
                         helper.changePin(mOldPin.getText().toString(),
                                 mNewPin.getText().toString());
diff --git a/src/com/android/phone/vvm/omtp/fetch/FetchVoicemailReceiver.java b/src/com/android/phone/vvm/omtp/fetch/FetchVoicemailReceiver.java
index fe3911c..d267e68 100644
--- a/src/com/android/phone/vvm/omtp/fetch/FetchVoicemailReceiver.java
+++ b/src/com/android/phone/vvm/omtp/fetch/FetchVoicemailReceiver.java
@@ -159,19 +159,21 @@
                 try {
                     while (mRetryCount > 0) {
                         VvmLog.i(TAG, "fetching voicemail, retry count=" + mRetryCount);
-                        ImapHelper imapHelper = new ImapHelper(mContext, mPhoneAccount, network);
-                        if (!imapHelper.isSuccessfullyInitialized()) {
-                            VvmLog.w(TAG, "Can't retrieve Imap credentials.");
-                            return;
-                        }
+                        try (ImapHelper imapHelper = new ImapHelper(mContext, mPhoneAccount,
+                                network)) {
+                            if (!imapHelper.isSuccessfullyInitialized()) {
+                                VvmLog.w(TAG, "Can't retrieve Imap credentials.");
+                                return;
+                            }
 
-                        boolean success = imapHelper.fetchVoicemailPayload(
-                                new VoicemailFetchedCallback(mContext, mUri), mUid);
-                        if (!success && mRetryCount > 0) {
-                            VvmLog.i(TAG, "fetch voicemail failed, retrying");
-                            mRetryCount--;
-                        } else {
-                            return;
+                            boolean success = imapHelper.fetchVoicemailPayload(
+                                    new VoicemailFetchedCallback(mContext, mUri), mUid);
+                            if (!success && mRetryCount > 0) {
+                                VvmLog.i(TAG, "fetch voicemail failed, retrying");
+                                mRetryCount--;
+                            } else {
+                                return;
+                            }
                         }
                     }
                 } finally {
diff --git a/src/com/android/phone/vvm/omtp/imap/ImapHelper.java b/src/com/android/phone/vvm/omtp/imap/ImapHelper.java
index 216b6a4..908d0f7 100644
--- a/src/com/android/phone/vvm/omtp/imap/ImapHelper.java
+++ b/src/com/android/phone/vvm/omtp/imap/ImapHelper.java
@@ -57,6 +57,7 @@
 
 import java.io.BufferedOutputStream;
 import java.io.ByteArrayOutputStream;
+import java.io.Closeable;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -66,7 +67,7 @@
 /**
  * A helper interface to abstract commands sent across IMAP interface for a given account.
  */
-public class ImapHelper {
+public class ImapHelper implements Closeable {
 
     private static final String TAG = "ImapHelper";
 
@@ -126,6 +127,11 @@
                 VoicemailContract.Status.QUOTA_UNAVAILABLE);
     }
 
+    @Override
+    public void close() {
+        mImapStore.closeConnection();
+    }
+
     /**
      * If mImapStore is null, this means that there was a missing or badly formatted port number,
      * which means there aren't sufficient credentials for login. If mImapStore is succcessfully
diff --git a/src/com/android/phone/vvm/omtp/protocol/Vvm3Protocol.java b/src/com/android/phone/vvm/omtp/protocol/Vvm3Protocol.java
index b00ed2a..fadf104 100644
--- a/src/com/android/phone/vvm/omtp/protocol/Vvm3Protocol.java
+++ b/src/com/android/phone/vvm/omtp/protocol/Vvm3Protocol.java
@@ -153,9 +153,7 @@
             super.onAvailable(network);
             VvmLog.i(TAG, "new user: network available");
             ImapHelper helper = new ImapHelper(mContext, mPhoneAccount, network);
-
             try {
-
                 // VVM3 has inconsistent error language code to OMTP. Just issue a raw command
                 // here.
                 // TODO(b/29082671): use LocaleList
@@ -181,7 +179,10 @@
             } catch (MessagingException | IOException e) {
                 helper.handleEvent(OmtpEvents.VVM3_NEW_USER_SETUP_FAILED);
                 VvmLog.e(TAG, e.toString());
+            } finally {
+                helper.close();
             }
+
         }
 
         private boolean setPin(ImapHelper helper) throws IOException, MessagingException {
diff --git a/src/com/android/phone/vvm/omtp/sync/OmtpVvmSyncService.java b/src/com/android/phone/vvm/omtp/sync/OmtpVvmSyncService.java
index 74b1f66..9884e9d 100644
--- a/src/com/android/phone/vvm/omtp/sync/OmtpVvmSyncService.java
+++ b/src/com/android/phone/vvm/omtp/sync/OmtpVvmSyncService.java
@@ -235,35 +235,36 @@
         int retryCount = NETWORK_RETRY_COUNT;
         try {
             while (retryCount > 0) {
-                ImapHelper imapHelper = new ImapHelper(this, phoneAccount, network);
-                if (!imapHelper.isSuccessfullyInitialized()) {
-                    VvmLog.w(TAG, "Can't retrieve Imap credentials.");
-                    VisualVoicemailSettingsUtil.resetVisualVoicemailRetryInterval(this,
-                            phoneAccount);
-                    return;
-                }
+                try (ImapHelper imapHelper = new ImapHelper(this, phoneAccount, network)) {
+                    if (!imapHelper.isSuccessfullyInitialized()) {
+                        VvmLog.w(TAG, "Can't retrieve Imap credentials.");
+                        VisualVoicemailSettingsUtil.resetVisualVoicemailRetryInterval(this,
+                                phoneAccount);
+                        return;
+                    }
 
-                boolean success = true;
-                if (voicemail == null) {
-                    success = syncAll(action, imapHelper, phoneAccount);
-                } else {
-                    success = syncOne(imapHelper, voicemail, phoneAccount);
-                }
-                imapHelper.updateQuota();
+                    boolean success = true;
+                    if (voicemail == null) {
+                        success = syncAll(action, imapHelper, phoneAccount);
+                    } else {
+                        success = syncOne(imapHelper, voicemail, phoneAccount);
+                    }
+                    imapHelper.updateQuota();
 
-                // Need to check again for whether visual voicemail is enabled because it could have
-                // been disabled while waiting for the response from the network.
-                if (VisualVoicemailSettingsUtil.isVisualVoicemailEnabled(this, phoneAccount) &&
-                        !success) {
-                    retryCount--;
-                    VvmLog.v(TAG, "Retrying " + action);
-                } else {
-                    // Nothing more to do here, just exit.
-                    VisualVoicemailSettingsUtil.resetVisualVoicemailRetryInterval(this,
-                            phoneAccount);
+                    // Need to check again for whether visual voicemail is enabled because it could
+                    // have been disabled while waiting for the response from the network.
+                    if (VisualVoicemailSettingsUtil.isVisualVoicemailEnabled(this, phoneAccount) &&
+                            !success) {
+                        retryCount--;
+                        VvmLog.v(TAG, "Retrying " + action);
+                    } else {
+                        // Nothing more to do here, just exit.
+                        VisualVoicemailSettingsUtil.resetVisualVoicemailRetryInterval(this,
+                                phoneAccount);
 
-                    imapHelper.handleEvent(OmtpEvents.DATA_IMAP_OPERATION_COMPLETED);
-                    return;
+                        imapHelper.handleEvent(OmtpEvents.DATA_IMAP_OPERATION_COMPLETED);
+                        return;
+                    }
                 }
             }
         } finally {
diff --git a/src/com/android/services/telephony/TelecomAccountRegistry.java b/src/com/android/services/telephony/TelecomAccountRegistry.java
index b5b23b4..a90bc02 100644
--- a/src/com/android/services/telephony/TelecomAccountRegistry.java
+++ b/src/com/android/services/telephony/TelecomAccountRegistry.java
@@ -60,6 +60,7 @@
     // This icon is the one that is used when the Slot ID that we have for a particular SIM
     // is not supported, i.e. SubscriptionManager.INVALID_SLOT_ID or the 5th SIM in a phone.
     private final static int DEFAULT_SIM_ICON =  R.drawable.ic_multi_sim;
+    private final static String GROUP_PREFIX = "group_";
 
     final class AccountEntry implements PstnPhoneCapabilitiesNotifier.Listener {
         private final Phone mPhone;
@@ -101,6 +102,7 @@
 
             // Populate the phone account data.
             int subId = mPhone.getSubId();
+            String subscriberId = mPhone.getSubscriberId();
             int color = PhoneAccount.NO_HIGHLIGHT_COLOR;
             int slotId = SubscriptionManager.INVALID_SIM_SLOT_INDEX;
             String line1Number = mTelephonyManager.getLine1Number(subId);
@@ -216,6 +218,23 @@
                 icon = Icon.createWithBitmap(bitmap);
             }
 
+            // Check to see if the newly registered account should replace the old account.
+            String groupId = "";
+            String[] mergedImsis = mTelephonyManager.getMergedSubscriberIds();
+            boolean isMergedSim = false;
+            if (mergedImsis != null && subscriberId != null && !isEmergency) {
+                for (String imsi : mergedImsis) {
+                    if (imsi.equals(subscriberId)) {
+                        isMergedSim = true;
+                        break;
+                    }
+                }
+            }
+            if(isMergedSim) {
+                groupId = GROUP_PREFIX + line1Number;
+                Log.i(this, "Adding Merged Account with group: " + Log.pii(groupId));
+            }
+
             PhoneAccount account = PhoneAccount.builder(phoneAccountHandle, label)
                     .setAddress(Uri.fromParts(PhoneAccount.SCHEME_TEL, line1Number, null))
                     .setSubscriptionAddress(
@@ -227,6 +246,7 @@
                     .setSupportedUriSchemes(Arrays.asList(
                             PhoneAccount.SCHEME_TEL, PhoneAccount.SCHEME_VOICEMAIL))
                     .setExtras(instantLetteringExtras)
+                    .setGroupId(groupId)
                     .build();
 
             // Register with Telecom and put into the account entry.
@@ -622,7 +642,9 @@
                 for (Phone phone : phones) {
                     int subscriptionId = phone.getSubId();
                     Log.d(this, "Phone with subscription id %d", subscriptionId);
-                    if (subscriptionId >= 0) {
+                    // setupAccounts can be called multiple times during service changes. Don't add an
+                    // account if the Icc has not been set yet.
+                    if (subscriptionId >= 0 && phone.getFullIccSerialNumber() != null) {
                         mAccounts.add(new AccountEntry(phone, false /* emergency */,
                                 false /* isDummy */));
                     }