Select VVM network transport base on carrier config

Copied from ag/822719 and removed the wifi settings part

+ OmtpVvmSyncService and FetchVoicemailReceiver now let
  VvmNetworkRequestCallback choose which network to use,
  based on carrier config.
  It was originally based on protocol type, which is just a
  coincidence for the current supported carrier.

+ Add a timeout checker for VvmNetworkRequestCallback. The
  timeout overload of ConnectivityManager.requestNetwork() is not
  triggering a timeout for some unknown reason, and since it's a
  hidden method, choose to implement one our own.

NO_SQ:Submit Queue doesn't pull in dependent changes so it fail
      every time.

Change-Id: I9b5037e2dcb875a4e6c60f01ab4b18a287bc3b54
diff --git a/src/com/android/phone/vvm/omtp/OmtpVvmCarrierConfigHelper.java b/src/com/android/phone/vvm/omtp/OmtpVvmCarrierConfigHelper.java
index 9f39db1..9393f81 100644
--- a/src/com/android/phone/vvm/omtp/OmtpVvmCarrierConfigHelper.java
+++ b/src/com/android/phone/vvm/omtp/OmtpVvmCarrierConfigHelper.java
@@ -88,6 +88,14 @@
         }
     }
 
+    public boolean isCellularDataRequired() {
+        if (mCarrierConfig == null) {
+            return false;
+        }
+        return mCarrierConfig
+                .getBoolean(CarrierConfigManager.KEY_VVM_CELLULAR_DATA_REQUIRED_BOOLEAN);
+    }
+
     public void startActivation() {
         OmtpMessageSender messageSender = getMessageSender();
         if (messageSender != null) {
diff --git a/src/com/android/phone/vvm/omtp/fetch/FetchVoicemailReceiver.java b/src/com/android/phone/vvm/omtp/fetch/FetchVoicemailReceiver.java
index 0f9a41f..da60ad1 100644
--- a/src/com/android/phone/vvm/omtp/fetch/FetchVoicemailReceiver.java
+++ b/src/com/android/phone/vvm/omtp/fetch/FetchVoicemailReceiver.java
@@ -22,7 +22,6 @@
 import android.database.Cursor;
 import android.net.ConnectivityManager;
 import android.net.Network;
-import android.net.NetworkCapabilities;
 import android.net.NetworkRequest;
 import android.net.Uri;
 import android.provider.VoicemailContract;
@@ -36,16 +35,18 @@
 import com.android.phone.vvm.omtp.OmtpVvmCarrierConfigHelper;
 import com.android.phone.vvm.omtp.imap.ImapHelper;
 import com.android.phone.vvm.omtp.sync.OmtpVvmSourceManager;
+import com.android.phone.vvm.omtp.sync.VvmNetworkRequestCallback;
 
 import java.util.concurrent.Executor;
 import java.util.concurrent.Executors;
 
 public class FetchVoicemailReceiver extends BroadcastReceiver {
+
     private static final String TAG = "FetchVoicemailReceiver";
 
     final static String[] PROJECTION = new String[] {
-        Voicemails.SOURCE_DATA,      // 0
-        Voicemails.PHONE_ACCOUNT_ID, // 1
+            Voicemails.SOURCE_DATA,      // 0
+            Voicemails.PHONE_ACCOUNT_ID, // 1
     };
 
     public static final int SOURCE_DATA = 0;
@@ -60,7 +61,7 @@
     private ContentResolver mContentResolver;
     private Uri mUri;
     private NetworkRequest mNetworkRequest;
-    private OmtpVvmNetworkRequestCallback mNetworkCallback;
+    private VvmNetworkRequestCallback mNetworkCallback;
     private Context mContext;
     private String mUid;
     private ConnectivityManager mConnectivityManager;
@@ -115,18 +116,9 @@
                     OmtpVvmCarrierConfigHelper carrierConfigHelper =
                             new OmtpVvmCarrierConfigHelper(context, subId);
 
-                    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();
-                    }
+                    mNetworkCallback = new fetchVoicemailNetworkRequestCallback(context,
+                            mPhoneAccount);
+                    mNetworkCallback.requestNetwork();
                 }
             } finally {
                 cursor.close();
@@ -134,21 +126,18 @@
         }
     }
 
-    private class OmtpVvmNetworkRequestCallback extends ConnectivityManager.NetworkCallback {
+    private class fetchVoicemailNetworkRequestCallback extends VvmNetworkRequestCallback {
+
+        public fetchVoicemailNetworkRequestCallback(Context context,
+                PhoneAccountHandle phoneAccount) {
+            super(context, phoneAccount);
+        }
+
         @Override
         public void onAvailable(final Network network) {
+            super.onAvailable(network);
             fetchVoicemail(network);
         }
-
-        @Override
-        public void onLost(Network network) {
-            releaseNetwork();
-        }
-
-        @Override
-        public void onUnavailable() {
-            releaseNetwork();
-        }
     }
 
     private void fetchVoicemail(final Network network) {
@@ -156,44 +145,28 @@
         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;
-                    }
+                try {
+                    while (mRetryCount > 0) {
+                        ImapHelper imapHelper = new ImapHelper(mContext, mPhoneAccount, network);
+                        if (!imapHelper.isSuccessfullyInitialized()) {
+                            Log.w(TAG, "Can't retrieve Imap credentials.");
+                            return;
+                        }
 
-                    boolean success = imapHelper.fetchVoicemailPayload(
-                            new VoicemailFetchedCallback(mContext, mUri), mUid);
-                    if (!success && mRetryCount > 0) {
-                        mRetryCount--;
-                    } else {
-                        releaseNetwork();
-                        return;
+                        boolean success = imapHelper.fetchVoicemailPayload(
+                                new VoicemailFetchedCallback(mContext, mUri), mUid);
+                        if (!success && mRetryCount > 0) {
+                            mRetryCount--;
+                        } else {
+                            return;
+                        }
+                    }
+                } finally {
+                    if (mNetworkCallback != null) {
+                        mNetworkCallback.releaseNetwork();
                     }
                 }
             }
         });
     }
-
-    private void requestNetwork() {
-        getConnectivityManager().requestNetwork(
-                mNetworkRequest, mNetworkCallback, NETWORK_REQUEST_TIMEOUT_MILLIS);
-    }
-
-    private void releaseNetwork() {
-        if (mNetworkCallback != null) {
-            getConnectivityManager().unregisterNetworkCallback(mNetworkCallback);
-        }
-    }
-
-    private ConnectivityManager getConnectivityManager() {
-        if (mConnectivityManager == null) {
-            mConnectivityManager = (ConnectivityManager) mContext.getSystemService(
-                    Context.CONNECTIVITY_SERVICE);
-        }
-        return mConnectivityManager;
-    }
 }
diff --git a/src/com/android/phone/vvm/omtp/sync/OmtpVvmNetworkRequestCallback.java b/src/com/android/phone/vvm/omtp/sync/OmtpVvmNetworkRequestCallback.java
deleted file mode 100644
index 7ee38ed..0000000
--- a/src/com/android/phone/vvm/omtp/sync/OmtpVvmNetworkRequestCallback.java
+++ /dev/null
@@ -1,83 +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.content.Context;
-import android.net.ConnectivityManager;
-import android.net.Network;
-import android.net.NetworkCapabilities;
-import android.net.NetworkRequest;
-import android.telecom.PhoneAccountHandle;
-
-import com.android.phone.PhoneUtils;
-/**
- * Base class for network request call backs for visual voicemail syncing with the Imap server.
- * This handles retries and network requests.
- */
-public abstract class OmtpVvmNetworkRequestCallback extends ConnectivityManager.NetworkCallback {
-    // Timeout used to call ConnectivityManager.requestNetwork
-    private static final int NETWORK_REQUEST_TIMEOUT_MILLIS = 60 * 1000;
-
-    protected Context mContext;
-    protected PhoneAccountHandle mPhoneAccount;
-    protected String mAction;
-    protected NetworkRequest mNetworkRequest;
-    private ConnectivityManager mConnectivityManager;
-
-    public OmtpVvmNetworkRequestCallback(Context context, 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();
-    }
-
-    public NetworkRequest getNetworkRequest() {
-        return mNetworkRequest;
-    }
-
-    @Override
-    public void onLost(Network network) {
-        releaseNetwork();
-    }
-
-    @Override
-    public void onUnavailable() {
-        releaseNetwork();
-    }
-
-    public void requestNetwork() {
-        getConnectivityManager().requestNetwork(getNetworkRequest(), this,
-                NETWORK_REQUEST_TIMEOUT_MILLIS);
-    }
-
-    public void releaseNetwork() {
-        getConnectivityManager().unregisterNetworkCallback(this);
-    }
-
-    private ConnectivityManager getConnectivityManager() {
-        if (mConnectivityManager == null) {
-            mConnectivityManager = (ConnectivityManager) mContext.getSystemService(
-                    Context.CONNECTIVITY_SERVICE);
-        }
-        return mConnectivityManager;
-    }
-}
diff --git a/src/com/android/phone/vvm/omtp/sync/OmtpVvmSyncService.java b/src/com/android/phone/vvm/omtp/sync/OmtpVvmSyncService.java
index 1f6412b..c2e0687 100644
--- a/src/com/android/phone/vvm/omtp/sync/OmtpVvmSyncService.java
+++ b/src/com/android/phone/vvm/omtp/sync/OmtpVvmSyncService.java
@@ -21,17 +21,15 @@
 import android.content.Context;
 import android.content.Intent;
 import android.net.Network;
+import android.net.NetworkInfo;
 import android.provider.VoicemailContract;
 import android.telecom.PhoneAccountHandle;
 import android.telecom.Voicemail;
-import android.telephony.TelephonyManager;
 import android.text.TextUtils;
 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;
@@ -43,6 +41,7 @@
  * Sync OMTP visual voicemail.
  */
 public class OmtpVvmSyncService extends IntentService {
+
     private static final String TAG = OmtpVvmSyncService.class.getSimpleName();
 
     // Number of retries
@@ -189,57 +188,47 @@
                     this, phoneAccount, currentTime);
         }
 
-        int subId = PhoneUtils.getSubIdForPhoneAccountHandle(phoneAccount);
-        OmtpVvmCarrierConfigHelper carrierConfigHelper =
-                new OmtpVvmCarrierConfigHelper(this, subId);
-
-        if (TelephonyManager.VVM_TYPE_CVVM.equals(carrierConfigHelper.getVvmType())) {
-            if (voicemail == null) {
-                doSync(null, null, phoneAccount, voicemail, action);
-            }
-        } else {
-            OmtpVvmNetworkRequestCallback networkCallback =
-                    new SyncAllNetworkRequestCallback(this, phoneAccount, voicemail, action);
-            networkCallback.requestNetwork();
-        }
+        VvmNetworkRequestCallback networkCallback = new SyncNetworkRequestCallback(this,
+                phoneAccount, voicemail, action);
+        networkCallback.requestNetwork();
     }
 
-    private void doSync(Network network, OmtpVvmNetworkRequestCallback callback,
+    private void doSync(Network network, VvmNetworkRequestCallback callback,
             PhoneAccountHandle phoneAccount, Voicemail voicemail, String action) {
         int retryCount = NETWORK_RETRY_COUNT;
-        while (retryCount > 0) {
-            ImapHelper imapHelper = new ImapHelper(this, phoneAccount, network);
-            if (!imapHelper.isSuccessfullyInitialized()) {
-                Log.w(TAG, "Can't retrieve Imap credentials.");
-                if (callback != null) {
-                    callback.releaseNetwork();
+        try {
+            while (retryCount > 0) {
+                ImapHelper imapHelper = new ImapHelper(this, phoneAccount, network);
+                if (!imapHelper.isSuccessfullyInitialized()) {
+                    Log.w(TAG, "Can't retrieve Imap credentials.");
+                    VisualVoicemailSettingsUtil.resetVisualVoicemailRetryInterval(this,
+                            phoneAccount);
+                    return;
                 }
-                VisualVoicemailSettingsUtil.resetVisualVoicemailRetryInterval(this,
-                        phoneAccount);
-                return;
-            }
 
-            boolean success = true;
-            if (voicemail == null) {
-                success = syncAll(action, imapHelper);
-            } else {
-                success = syncOne(imapHelper, voicemail);
-            }
-
-            // 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--;
-                Log.v(TAG, "Retrying " + action);
-            } else {
-                // Nothing more to do here, just exit.
-                if (callback != null) {
-                    callback.releaseNetwork();
+                boolean success = true;
+                if (voicemail == null) {
+                    success = syncAll(action, imapHelper);
+                } else {
+                    success = syncOne(imapHelper, voicemail);
                 }
-                VisualVoicemailSettingsUtil.resetVisualVoicemailRetryInterval(this,
-                        phoneAccount);
-                return;
+
+                // 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--;
+                    Log.v(TAG, "Retrying " + action);
+                } else {
+                    // Nothing more to do here, just exit.
+                    VisualVoicemailSettingsUtil.resetVisualVoicemailRetryInterval(this,
+                            phoneAccount);
+                    return;
+                }
+            }
+        } finally {
+            if (callback != null) {
+                callback.releaseNetwork();
             }
         }
     }
@@ -255,7 +244,7 @@
             downloadSuccess = download(imapHelper);
         }
 
-        Log.v(TAG, "upload succeeded: ["+  String.valueOf(uploadSuccess)
+        Log.v(TAG, "upload succeeded: [" + String.valueOf(uploadSuccess)
                 + "] download succeeded: [" + String.valueOf(downloadSuccess) + "]");
 
         boolean success = uploadSuccess && downloadSuccess;
@@ -276,19 +265,26 @@
                 voicemail.getSourceData());
     }
 
-    private class SyncAllNetworkRequestCallback extends OmtpVvmNetworkRequestCallback {
-        Voicemail mVoicemail;
+    private class SyncNetworkRequestCallback extends VvmNetworkRequestCallback {
 
-        public SyncAllNetworkRequestCallback(Context context, PhoneAccountHandle phoneAccount,
+        Voicemail mVoicemail;
+        private String mAction;
+
+        public SyncNetworkRequestCallback(Context context, PhoneAccountHandle phoneAccount,
                 Voicemail voicemail, String action) {
-            super(context, phoneAccount, action);
+            super(context, phoneAccount);
+            mAction = action;
             mVoicemail = voicemail;
         }
 
         @Override
         public void onAvailable(Network network) {
+            super.onAvailable(network);
+            NetworkInfo info = getConnectivityManager().getNetworkInfo(network);
+            Log.d(TAG, "Network Type: " + info.getTypeName());
             doSync(network, this, mPhoneAccount, mVoicemail, mAction);
         }
+
     }
 
     private boolean upload(ImapHelper imapHelper) {
@@ -368,7 +364,7 @@
         long retryInterval = VisualVoicemailSettingsUtil.getVisualVoicemailRetryInterval(this,
                 phoneAccount);
 
-        Log.v(TAG, "Retrying "+ action + " in " + retryInterval + "ms");
+        Log.v(TAG, "Retrying " + action + " in " + retryInterval + "ms");
 
         AlarmManager alarmManager = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE);
         alarmManager.set(AlarmManager.RTC, System.currentTimeMillis() + retryInterval,
@@ -390,6 +386,7 @@
     }
 
     public class TranscriptionFetchedCallback {
+
         private Context mContext;
         private Voicemail mVoicemail;
 
diff --git a/src/com/android/phone/vvm/omtp/sync/VvmNetworkRequestCallback.java b/src/com/android/phone/vvm/omtp/sync/VvmNetworkRequestCallback.java
new file mode 100644
index 0000000..8bef9dc
--- /dev/null
+++ b/src/com/android/phone/vvm/omtp/sync/VvmNetworkRequestCallback.java
@@ -0,0 +1,149 @@
+/*
+ * 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.annotation.CallSuper;
+import android.content.Context;
+import android.net.ConnectivityManager;
+import android.net.Network;
+import android.net.NetworkCapabilities;
+import android.net.NetworkRequest;
+import android.os.Handler;
+import android.os.Looper;
+import android.telecom.PhoneAccountHandle;
+import android.util.Log;
+
+import com.android.phone.PhoneUtils;
+import com.android.phone.vvm.omtp.OmtpVvmCarrierConfigHelper;
+
+/**
+ * Base class for network request call backs for visual voicemail syncing with the Imap server. This
+ * handles retries and network requests.
+ */
+public abstract class VvmNetworkRequestCallback extends ConnectivityManager.NetworkCallback {
+
+    private static final String TAG = "VvmNetworkRequest";
+
+    // Timeout used to call ConnectivityManager.requestNetwork
+    private static final int NETWORK_REQUEST_TIMEOUT_MILLIS = 60 * 1000;
+
+    public static final String NETWORK_REQUEST_FAILED_TIMEOUT = "timeout";
+    public static final String NETWORK_REQUEST_FAILED_LOST = "lost";
+
+    protected Context mContext;
+    protected PhoneAccountHandle mPhoneAccount;
+    protected NetworkRequest mNetworkRequest;
+    private ConnectivityManager mConnectivityManager;
+
+    private boolean mRequestSent = false;
+    private boolean mResultReceived = false;
+
+    public VvmNetworkRequestCallback(Context context, PhoneAccountHandle phoneAccount) {
+        mContext = context;
+        mPhoneAccount = phoneAccount;
+        mNetworkRequest = getNetworkRequest(context, phoneAccount);
+    }
+
+    /**
+     * @return NetworkRequest for a proper transport type. Use only cellular network if the carrier
+     * requires it. Otherwise use whatever available.
+     */
+    private NetworkRequest getNetworkRequest(Context context, PhoneAccountHandle phoneAccount) {
+        int subId = PhoneUtils.getSubIdForPhoneAccountHandle(phoneAccount);
+        OmtpVvmCarrierConfigHelper carrierConfigHelper =
+                new OmtpVvmCarrierConfigHelper(context, subId);
+
+        NetworkRequest.Builder builder = new NetworkRequest.Builder()
+                .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
+
+        if (carrierConfigHelper.isCellularDataRequired()) {
+            Log.d(TAG, "Transport type: CELLULAR");
+            builder.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
+                    .setNetworkSpecifier(Integer.toString(subId));
+        } else {
+            Log.d(TAG, "Transport type: ANY");
+        }
+        return builder.build();
+    }
+
+    public NetworkRequest getNetworkRequest() {
+        return mNetworkRequest;
+    }
+
+    @Override
+    @CallSuper
+    public void onLost(Network network) {
+        Log.d(TAG, "onLost");
+        mResultReceived = true;
+        onFailed(NETWORK_REQUEST_FAILED_LOST);
+    }
+
+    @Override
+    @CallSuper
+    public void onAvailable(Network network) {
+        super.onAvailable(network);
+        mResultReceived = true;
+    }
+
+    @Override
+    @CallSuper
+    public void onUnavailable() {
+        mResultReceived = true;
+        onFailed(NETWORK_REQUEST_FAILED_TIMEOUT);
+    }
+
+    public void requestNetwork() {
+        if (mRequestSent == true) {
+            Log.e(TAG, "requestNetwork() called twice");
+            return;
+        }
+        mRequestSent = true;
+        getConnectivityManager().requestNetwork(getNetworkRequest(), this);
+        /**
+         * Somehow requestNetwork() with timeout doesn't work, and it's a hidden method.
+         * Implement our own timeout mechanism instead.
+         */
+        Handler handler = new Handler(Looper.getMainLooper());
+        handler.postDelayed(new Runnable() {
+            @Override
+            public void run() {
+                if (mResultReceived == false) {
+                    onFailed(NETWORK_REQUEST_FAILED_TIMEOUT);
+                }
+            }
+        }, NETWORK_REQUEST_TIMEOUT_MILLIS);
+    }
+
+    public void releaseNetwork() {
+        Log.d(TAG, "releaseNetwork");
+        getConnectivityManager().unregisterNetworkCallback(this);
+    }
+
+    public ConnectivityManager getConnectivityManager() {
+        if (mConnectivityManager == null) {
+            mConnectivityManager = (ConnectivityManager) mContext.getSystemService(
+                    Context.CONNECTIVITY_SERVICE);
+        }
+        return mConnectivityManager;
+    }
+
+    @CallSuper
+    public void onFailed(String reason) {
+        Log.d(TAG, "onFailed: " + reason);
+        // TODO: Notify the user sync has failed?
+        releaseNetwork();
+    }
+}