Use SSL connection for T-Mobile.

The connection to the IMAP server cannot be made over a non-encrypted
cellular data connection. Instead, use the SSL connection to connect to
the IMAP server for T-Mobile which bipasses the network request. This
includes the following changes:
- Factor out syncing logic from OmtpVvmSyncService into a separate
  method so it can be called both directly and from the network callback
- Factor out voicemail fetching logic from FetchVoicemailReceiver into a
  separate method so it can be called both directly and from the network
  callback
- Use the SSL flag and port 993 for just T-Mobile queries.

Bug: 22802280
Change-Id: I938f4c7475327f9a133b74c0c9459edeece1a5b0
diff --git a/src/com/android/phone/vvm/omtp/fetch/FetchVoicemailReceiver.java b/src/com/android/phone/vvm/omtp/fetch/FetchVoicemailReceiver.java
index 43724e4..0f9a41f 100644
--- a/src/com/android/phone/vvm/omtp/fetch/FetchVoicemailReceiver.java
+++ b/src/com/android/phone/vvm/omtp/fetch/FetchVoicemailReceiver.java
@@ -33,6 +33,7 @@
 import android.util.Log;
 
 import com.android.phone.PhoneUtils;
+import com.android.phone.vvm.omtp.OmtpVvmCarrierConfigHelper;
 import com.android.phone.vvm.omtp.imap.ImapHelper;
 import com.android.phone.vvm.omtp.sync.OmtpVvmSourceManager;
 
@@ -111,14 +112,21 @@
                     }
 
                     int subId = PhoneUtils.getSubIdForPhoneAccountHandle(mPhoneAccount);
-                    mNetworkRequest = new NetworkRequest.Builder()
-                    .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
-                    .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
-                    .setNetworkSpecifier(Integer.toString(subId))
-                    .build();
+                    OmtpVvmCarrierConfigHelper carrierConfigHelper =
+                            new OmtpVvmCarrierConfigHelper(context, subId);
 
-                    mNetworkCallback = new OmtpVvmNetworkRequestCallback();
-                    requestNetwork();
+                    if (TelephonyManager.VVM_TYPE_CVVM.equals(carrierConfigHelper.getVvmType())) {
+                        fetchVoicemail(null);
+                    } else {
+                        mNetworkRequest = new NetworkRequest.Builder()
+                                .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
+                                .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
+                                .setNetworkSpecifier(Integer.toString(subId))
+                                .build();
+
+                        mNetworkCallback = new OmtpVvmNetworkRequestCallback();
+                        requestNetwork();
+                    }
                 }
             } finally {
                 cursor.close();
@@ -129,59 +137,56 @@
     private class OmtpVvmNetworkRequestCallback extends ConnectivityManager.NetworkCallback {
         @Override
         public void onAvailable(final Network network) {
-            Executor executor = Executors.newCachedThreadPool();
-            executor.execute(new Runnable() {
-                @Override
-                public void run() {
-                    while (mRetryCount > 0) {
-                        ImapHelper imapHelper = new ImapHelper(mContext, mPhoneAccount, network);
-                        if (!imapHelper.isSuccessfullyInitialized()) {
-                            Log.w(TAG, "Can't retrieve Imap credentials.");
-                            releaseNetwork();
-                            return;
-                        }
-
-                        boolean success = imapHelper.fetchVoicemailPayload(
-                                new VoicemailFetchedCallback(mContext, mUri), mUid);
-                        if (!success && mRetryCount > 0) {
-                            mRetryCount--;
-                        } else {
-                            releaseNetwork();
-                            return;
-                        }
-                    }
-                }
-            });
+            fetchVoicemail(network);
         }
 
         @Override
         public void onLost(Network network) {
             releaseNetwork();
-
-            if (mRetryCount > 0) {
-                mRetryCount--;
-                requestNetwork();
-            }
         }
 
         @Override
         public void onUnavailable() {
             releaseNetwork();
-
-            if (mRetryCount > 0) {
-                mRetryCount--;
-                requestNetwork();
-            }
         }
     }
 
+    private void fetchVoicemail(final Network network) {
+        Executor executor = Executors.newCachedThreadPool();
+        executor.execute(new Runnable() {
+            @Override
+            public void run() {
+                while (mRetryCount > 0) {
+                    ImapHelper imapHelper = new ImapHelper(mContext, mPhoneAccount, network);
+                    if (!imapHelper.isSuccessfullyInitialized()) {
+                        Log.w(TAG, "Can't retrieve Imap credentials.");
+                        // releaseNetwork() will check if the network callback exists
+                        releaseNetwork();
+                        return;
+                    }
+
+                    boolean success = imapHelper.fetchVoicemailPayload(
+                            new VoicemailFetchedCallback(mContext, mUri), mUid);
+                    if (!success && mRetryCount > 0) {
+                        mRetryCount--;
+                    } else {
+                        releaseNetwork();
+                        return;
+                    }
+                }
+            }
+        });
+    }
+
     private void requestNetwork() {
         getConnectivityManager().requestNetwork(
                 mNetworkRequest, mNetworkCallback, NETWORK_REQUEST_TIMEOUT_MILLIS);
     }
 
     private void releaseNetwork() {
-        getConnectivityManager().unregisterNetworkCallback(mNetworkCallback);
+        if (mNetworkCallback != null) {
+            getConnectivityManager().unregisterNetworkCallback(mNetworkCallback);
+        }
     }
 
     private ConnectivityManager getConnectivityManager() {
diff --git a/src/com/android/phone/vvm/omtp/imap/ImapHelper.java b/src/com/android/phone/vvm/omtp/imap/ImapHelper.java
index d68a36b..1c2ae32 100644
--- a/src/com/android/phone/vvm/omtp/imap/ImapHelper.java
+++ b/src/com/android/phone/vvm/omtp/imap/ImapHelper.java
@@ -19,9 +19,10 @@
 import android.net.Network;
 import android.telecom.PhoneAccountHandle;
 import android.telecom.Voicemail;
-
+import android.telephony.TelephonyManager;
 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;
@@ -38,6 +39,7 @@
 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.OmtpVvmCarrierConfigHelper;
 import com.android.phone.vvm.omtp.fetch.VoicemailFetchedCallback;
 
 import libcore.io.IoUtils;
@@ -75,9 +77,18 @@
             int port = Integer.parseInt(
                     VisualVoicemailSettingsUtil.getVisualVoicemailCredentials(context,
                             OmtpConstants.IMAP_PORT, phoneAccount));
-            // TODO: determine the security protocol (e.g. ssl, tls, none, etc.)
+            int auth = ImapStore.FLAG_NONE;
+
+            OmtpVvmCarrierConfigHelper carrierConfigHelper = new OmtpVvmCarrierConfigHelper(context,
+                    PhoneUtils.getSubIdForPhoneAccountHandle(phoneAccount));
+            if (TelephonyManager.VVM_TYPE_CVVM.equals(carrierConfigHelper.getVvmType())) {
+                // TODO: move these into the carrier config app
+                port = 993;
+                auth = ImapStore.FLAG_SSL;
+            }
+
             mImapStore = new ImapStore(
-                    context, username, password, port, serverName, ImapStore.FLAG_NONE, network);
+                    context, username, password, port, serverName, auth, network);
         } catch (NumberFormatException e) {
             LogUtils.w(TAG, "Could not parse port number");
         }
diff --git a/src/com/android/phone/vvm/omtp/sync/OmtpVvmSyncService.java b/src/com/android/phone/vvm/omtp/sync/OmtpVvmSyncService.java
index 3c47975..ba3d236 100644
--- a/src/com/android/phone/vvm/omtp/sync/OmtpVvmSyncService.java
+++ b/src/com/android/phone/vvm/omtp/sync/OmtpVvmSyncService.java
@@ -28,11 +28,13 @@
 import android.provider.VoicemailContract;
 import android.telecom.PhoneAccountHandle;
 import android.telecom.Voicemail;
+import android.telephony.TelephonyManager;
 import android.util.Log;
 
 import com.android.phone.PhoneUtils;
 import com.android.phone.settings.VisualVoicemailSettingsUtil;
 import com.android.phone.vvm.omtp.LocalLogHelper;
+import com.android.phone.vvm.omtp.OmtpVvmCarrierConfigHelper;
 import com.android.phone.vvm.omtp.imap.ImapHelper;
 
 import java.util.HashMap;
@@ -149,19 +151,19 @@
 
         if (phoneAccount != null) {
             Log.v(TAG, "Sync requested: " + action + " - for account: " + phoneAccount);
-            setupAndSendNetworkRequest(phoneAccount, action);
+            setupAndSendRequest(phoneAccount, action);
         } else {
             Log.v(TAG, "Sync requested: " + action + " - for all accounts");
             OmtpVvmSourceManager vvmSourceManager =
                     OmtpVvmSourceManager.getInstance(this);
             Set<PhoneAccountHandle> sources = vvmSourceManager.getOmtpVvmSources();
             for (PhoneAccountHandle source : sources) {
-                setupAndSendNetworkRequest(source, action);
+                setupAndSendRequest(source, action);
             }
         }
     }
 
-    private void setupAndSendNetworkRequest(PhoneAccountHandle phoneAccount, String action) {
+    private void setupAndSendRequest(PhoneAccountHandle phoneAccount, String action) {
         if (!VisualVoicemailSettingsUtil.isVisualVoicemailEnabled(this, phoneAccount)) {
             Log.v(TAG, "Sync requested for disabled account");
             return;
@@ -181,30 +183,35 @@
                     this, phoneAccount, currentTime);
         }
 
-        OmtpVvmNetworkRequestCallback networkCallback = new OmtpVvmNetworkRequestCallback(this,
-                phoneAccount, action);
-        requestNetwork(networkCallback);
+        int subId = PhoneUtils.getSubIdForPhoneAccountHandle(phoneAccount);
+        OmtpVvmCarrierConfigHelper carrierConfigHelper =
+                new OmtpVvmCarrierConfigHelper(this, subId);
+
+        if (TelephonyManager.VVM_TYPE_CVVM.equals(carrierConfigHelper.getVvmType())) {
+            doSync(null, null, phoneAccount, action);
+        } else {
+            OmtpVvmNetworkRequestCallback networkCallback = new OmtpVvmNetworkRequestCallback(
+                    phoneAccount, action);
+            requestNetwork(networkCallback);
+        }
     }
 
     private class OmtpVvmNetworkRequestCallback extends ConnectivityManager.NetworkCallback {
-        Context mContext;
         PhoneAccountHandle mPhoneAccount;
         String mAction;
         NetworkRequest mNetworkRequest;
-        int mRetryCount;
 
-        public OmtpVvmNetworkRequestCallback(Context context, PhoneAccountHandle phoneAccount,
+        public OmtpVvmNetworkRequestCallback(PhoneAccountHandle phoneAccount,
                 String action) {
-            mContext = context;
             mPhoneAccount = phoneAccount;
             mAction = action;
             mNetworkRequest = new NetworkRequest.Builder()
-            .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
-            .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
-            .setNetworkSpecifier(
-                    Integer.toString(PhoneUtils.getSubIdForPhoneAccountHandle(phoneAccount)))
-            .build();
-            mRetryCount = NETWORK_RETRY_COUNT;
+                    .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
+                    .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
+                    .setNetworkSpecifier(
+                            Integer.toString(
+                                    PhoneUtils.getSubIdForPhoneAccountHandle(phoneAccount)))
+                    .build();
         }
 
         public NetworkRequest getNetworkRequest() {
@@ -213,59 +220,7 @@
 
         @Override
         public void onAvailable(final Network network) {
-            boolean uploadSuccess;
-            boolean downloadSuccess;
-
-            while (mRetryCount > 0) {
-                uploadSuccess = true;
-                downloadSuccess = true;
-
-                ImapHelper imapHelper = new ImapHelper(mContext, mPhoneAccount, network);
-                if (!imapHelper.isSuccessfullyInitialized()) {
-                    Log.w(TAG, "Can't retrieve Imap credentials.");
-                    releaseNetwork(this);
-                    VisualVoicemailSettingsUtil.resetVisualVoicemailRetryInterval(mContext,
-                            mPhoneAccount);
-                    return;
-                }
-
-                if (SYNC_FULL_SYNC.equals(mAction) || SYNC_UPLOAD_ONLY.equals(mAction)) {
-                    uploadSuccess = upload(imapHelper);
-                }
-                if (SYNC_FULL_SYNC.equals(mAction) || SYNC_DOWNLOAD_ONLY.equals(mAction)) {
-                    downloadSuccess = download(imapHelper);
-                }
-
-                Log.v(TAG, "upload succeeded: ["+  String.valueOf(uploadSuccess)
-                        + "] download succeeded: [" + String.valueOf(downloadSuccess) + "]");
-
-                // 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(mContext, mPhoneAccount) &&
-                        (!uploadSuccess || !downloadSuccess)) {
-                    mRetryCount--;
-                    // Re-adjust so that only the unsuccessful action needs to be retried.
-                    // No need to re-adjust if both are unsuccessful. It means the full sync
-                    // failed so the action remains unchanged.
-                    if (uploadSuccess) {
-                        mAction = SYNC_DOWNLOAD_ONLY;
-                    } else if (downloadSuccess) {
-                        mAction = SYNC_UPLOAD_ONLY;
-                    }
-
-                    Log.v(TAG, "Retrying " + mAction);
-                    LocalLogHelper.log(TAG, "Immediately retrying " + mAction);
-                } else {
-                    // Nothing more to do here, just exit.
-                    releaseNetwork(this);
-                    VisualVoicemailSettingsUtil.resetVisualVoicemailRetryInterval(mContext,
-                            mPhoneAccount);
-                    return;
-                }
-            }
-
-            releaseNetwork(this);
-            setRetryAlarm(mPhoneAccount, mAction);
+            doSync(network, this, mPhoneAccount, mAction);
         }
 
         @Override
@@ -279,13 +234,74 @@
         }
     }
 
+    private void doSync(Network network, OmtpVvmNetworkRequestCallback callback,
+            PhoneAccountHandle phoneAccount, String action) {
+        int retryCount = NETWORK_RETRY_COUNT;
+
+        boolean uploadSuccess;
+        boolean downloadSuccess;
+
+        while (retryCount > 0) {
+            uploadSuccess = true;
+            downloadSuccess = true;
+
+            ImapHelper imapHelper = new ImapHelper(this, phoneAccount, network);
+            if (!imapHelper.isSuccessfullyInitialized()) {
+                Log.w(TAG, "Can't retrieve Imap credentials.");
+                releaseNetwork(callback);
+                VisualVoicemailSettingsUtil.resetVisualVoicemailRetryInterval(this,
+                        phoneAccount);
+                return;
+            }
+
+            if (SYNC_FULL_SYNC.equals(action) || SYNC_UPLOAD_ONLY.equals(action)) {
+                uploadSuccess = upload(imapHelper);
+            }
+            if (SYNC_FULL_SYNC.equals(action) || SYNC_DOWNLOAD_ONLY.equals(action)) {
+                downloadSuccess = download(imapHelper);
+            }
+
+            Log.v(TAG, "upload succeeded: ["+  String.valueOf(uploadSuccess)
+                    + "] download succeeded: [" + String.valueOf(downloadSuccess) + "]");
+
+            // 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) &&
+                    (!uploadSuccess || !downloadSuccess)) {
+                retryCount--;
+                // Re-adjust so that only the unsuccessful action needs to be retried.
+                // No need to re-adjust if both are unsuccessful. It means the full sync
+                // failed so the action remains unchanged.
+                if (uploadSuccess) {
+                    action = SYNC_DOWNLOAD_ONLY;
+                } else if (downloadSuccess) {
+                    action = SYNC_UPLOAD_ONLY;
+                }
+
+                Log.v(TAG, "Retrying " + action);
+                LocalLogHelper.log(TAG, "Immediately retrying " + action);
+            } else {
+                // Nothing more to do here, just exit.
+                releaseNetwork(callback);
+
+                VisualVoicemailSettingsUtil.resetVisualVoicemailRetryInterval(this, phoneAccount);
+                return;
+            }
+        }
+
+        releaseNetwork(callback);
+        setRetryAlarm(phoneAccount, action);
+    }
+
     private void requestNetwork(OmtpVvmNetworkRequestCallback networkCallback) {
         getConnectivityManager().requestNetwork(networkCallback.getNetworkRequest(),
                 networkCallback, NETWORK_REQUEST_TIMEOUT_MILLIS);
     }
 
     private void releaseNetwork(NetworkCallback networkCallback) {
-        getConnectivityManager().unregisterNetworkCallback(networkCallback);
+        if (networkCallback != null) {
+            getConnectivityManager().unregisterNetworkCallback(networkCallback);
+        }
     }
 
     private ConnectivityManager getConnectivityManager() {