Merge "Fix network can't handle simultaneously SS request for both subs" into main
diff --git a/src/com/android/settings/sim/smartForwarding/DisableSmartForwardingTask.java b/src/com/android/settings/sim/smartForwarding/DisableSmartForwardingTask.java
index a1035dc..8448319 100644
--- a/src/com/android/settings/sim/smartForwarding/DisableSmartForwardingTask.java
+++ b/src/com/android/settings/sim/smartForwarding/DisableSmartForwardingTask.java
@@ -23,6 +23,14 @@
 import android.telephony.TelephonyManager;
 import android.util.Log;
 
+import com.android.settings.sim.smartForwarding.EnableSmartForwardingTask.UpdateCommand;
+
+import com.google.common.util.concurrent.SettableFuture;
+
+import java.util.ArrayList;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+
 public class DisableSmartForwardingTask implements Runnable {
     private final TelephonyManager tm;
     private final boolean[] callWaitingStatus;
@@ -37,22 +45,123 @@
 
     @Override
     public void run() {
-        for (int i = 0; i < tm.getActiveModemCount(); i++) {
-            int subId = getSubId(i);
-            if (callWaitingStatus != null
-                    && subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
-                Log.d(TAG, "Restore call waiting to " + callWaitingStatus[i]);
-                tm.createForSubscriptionId(subId)
-                        .setCallWaitingEnabled(callWaitingStatus[i], null, null);
+        FlowController controller = new FlowController();
+        if (controller.init()) {
+            controller.startProcess();
+        }
+    }
+
+    class FlowController {
+        private final ArrayList<UpdateCommand> mSteps = new ArrayList<>();
+
+        /* package */ boolean init() {
+            if (tm == null) {
+                Log.e(TAG, "TelephonyManager is null");
+                return false;
             }
 
-            if (callForwardingInfo != null
-                    && callForwardingInfo[i] != null
-                    && subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
-                Log.d(TAG, "Restore call forwarding to " + callForwardingInfo[i]);
-                tm.createForSubscriptionId(subId)
-                        .setCallForwarding(callForwardingInfo[i], null, null);
+            if (callWaitingStatus == null || callForwardingInfo == null) {
+                Log.e(TAG, "CallWaitingStatus or CallForwardingInfo array is null");
+                return false;
             }
+
+            int slotCount = tm.getActiveModemCount();
+            if (callWaitingStatus.length != slotCount || callForwardingInfo.length != slotCount) {
+                Log.e(TAG, "The length of CallWaitingStatus and CallForwardingInfo array"
+                        + " should be the same as phone count.");
+                return false;
+            }
+
+            Executor executor = Executors.newSingleThreadExecutor();
+
+            for (int i = 0; i < slotCount; i++) {
+                int subId = getSubId(i);
+                if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
+                    continue;
+                }
+
+                mSteps.add(new RestoreCallWaitingCommand(
+                        tm, executor, callWaitingStatus[i], subId));
+
+                if (callForwardingInfo[i] != null) {
+                    mSteps.add(new RestoreCallForwardingCommand(
+                            tm, executor, callForwardingInfo[i], subId));
+                }
+            }
+
+            return true;
+        }
+
+        /* package */ void startProcess() {
+            int index = 0;
+
+            while (index < mSteps.size()) {
+                UpdateCommand currentStep = mSteps.get(index);
+                Log.d(TAG, "processing : " + currentStep);
+
+                try {
+                    currentStep.process();
+                    index++;
+                } catch (Exception e) {
+                    Log.e(TAG, "Failed on : " + currentStep, e);
+                }
+            }
+        }
+    }
+
+    class RestoreCallForwardingCommand extends UpdateCommand<Integer> {
+        private SettableFuture<Boolean> mResultFuture = SettableFuture.create();
+        private CallForwardingInfo mCallForwardingInfo;
+
+        /* package */ RestoreCallForwardingCommand(TelephonyManager tm, Executor executor,
+                CallForwardingInfo mCallForwardingInfo, int subId) {
+            super(tm, executor, subId);
+            this.mCallForwardingInfo = mCallForwardingInfo;
+        }
+
+        @Override
+        public boolean process() throws Exception {
+            Log.d(TAG, "Restore call forwarding to " + mCallForwardingInfo);
+            tm.createForSubscriptionId(subId).setCallForwarding(mCallForwardingInfo, executor,
+                    this::updateStatusCallBack);
+            return mResultFuture.get();
+        }
+
+        @Override
+        void onRestore() {
+        }
+
+        private void updateStatusCallBack(int result) {
+            Log.d(TAG, "updateStatusCallBack for CallForwarding: " + result);
+            mResultFuture.set(true);
+        }
+    }
+
+    class RestoreCallWaitingCommand extends UpdateCommand<Integer> {
+        private SettableFuture<Boolean> mResultFuture = SettableFuture.create();
+        private boolean mCallWaitingStatus;
+
+        /* package */ RestoreCallWaitingCommand(TelephonyManager tm, Executor executor,
+                boolean mCallWaitingStatus, int subId) {
+            super(tm, executor, subId);
+            this.mCallWaitingStatus = mCallWaitingStatus;
+        }
+
+        @Override
+        public boolean process() throws Exception {
+            Log.d(TAG, "Restore call waiting to " + mCallWaitingStatus);
+            tm.createForSubscriptionId(subId).setCallWaitingEnabled(mCallWaitingStatus, executor,
+                    this::updateStatusCallBack);
+            return mResultFuture.get();
+        }
+
+        @Override
+        void onRestore() {
+        }
+
+        private void updateStatusCallBack(int result) {
+            Log.d(TAG, "updateStatusCallBack for CallWaiting: " + result);
+            mResultFuture.set(true);
         }
     }
 
diff --git a/src/com/android/settings/sim/smartForwarding/SmartForwardingActivity.java b/src/com/android/settings/sim/smartForwarding/SmartForwardingActivity.java
index 95ac999..4f05a8b 100644
--- a/src/com/android/settings/sim/smartForwarding/SmartForwardingActivity.java
+++ b/src/com/android/settings/sim/smartForwarding/SmartForwardingActivity.java
@@ -85,12 +85,7 @@
 
     public void enableSmartForwarding(String[] phoneNumber) {
         // Pop-up ongoing dialog
-        ProgressDialog dialog = new ProgressDialog(this);
-        dialog.setTitle(R.string.smart_forwarding_ongoing_title);
-        dialog.setIndeterminate(true);
-        dialog.setMessage(getText(R.string.smart_forwarding_ongoing_text));
-        dialog.setCancelable(false);
-        dialog.show();
+        ProgressDialog dialog = showOngoingDialog();
 
         // Enable feature
         ListenableFuture<FeatureResult> enableTask =
@@ -140,6 +135,9 @@
         boolean[] callWaitingStatus = getAllSlotCallWaitingStatus(this, tm);
         CallForwardingInfo[] callForwardingInfo = getAllSlotCallForwardingStatus(this, sm, tm);
 
+        // Pop-up ongoing dialog
+        ProgressDialog dialog = showOngoingDialog();
+
         // Disable feature
         ListenableFuture disableTask = service.submit(new DisableSmartForwardingTask(
                 tm, callWaitingStatus, callForwardingInfo));
@@ -147,11 +145,13 @@
             @Override
             public void onSuccess(Object result) {
                 clearAllBackupData(SmartForwardingActivity.this, sm, tm);
+                dialog.dismiss();
             }
 
             @Override
             public void onFailure(Throwable t) {
                 Log.e(TAG, "Disable Feature exception" + t);
+                dialog.dismiss();
             }
         }, ContextCompat.getMainExecutor(this));
     }
@@ -174,4 +174,15 @@
                 .create();
         mDialog.show();
     }
+
+    private ProgressDialog showOngoingDialog() {
+        ProgressDialog dialog = new ProgressDialog(this);
+        dialog.setTitle(R.string.smart_forwarding_ongoing_title);
+        dialog.setIndeterminate(true);
+        dialog.setMessage(getText(R.string.smart_forwarding_ongoing_text));
+        dialog.setCancelable(false);
+        dialog.show();
+
+        return dialog;
+    }
 }