Merge "Developer option crashed when Bluetooth feature disabled" into main
diff --git a/src/com/android/settings/bluetooth/OWNERS b/src/com/android/settings/bluetooth/OWNERS
index 0a3dec9..4edd1e4 100644
--- a/src/com/android/settings/bluetooth/OWNERS
+++ b/src/com/android/settings/bluetooth/OWNERS
@@ -1,8 +1,4 @@
 # Default reviewers for this and subdirectories.
-hughchen@google.com
-timhypeng@google.com
-siyuanh@google.com
-robertluo@google.com
 yiyishen@google.com
 yqian@google.com
 chelseahao@google.com
diff --git a/src/com/android/settings/connecteddevice/OWNERS b/src/com/android/settings/connecteddevice/OWNERS
index 5215a8f..4edd1e4 100644
--- a/src/com/android/settings/connecteddevice/OWNERS
+++ b/src/com/android/settings/connecteddevice/OWNERS
@@ -1,7 +1,4 @@
 # Default reviewers for this and subdirectories.
-hughchen@google.com
-timhypeng@google.com
-robertluo@google.com
 yiyishen@google.com
 yqian@google.com
 chelseahao@google.com
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;
+    }
 }
diff --git a/src/com/android/settings/sim/smartForwarding/SmartForwardingFragment.java b/src/com/android/settings/sim/smartForwarding/SmartForwardingFragment.java
index a95eb38..f847147 100644
--- a/src/com/android/settings/sim/smartForwarding/SmartForwardingFragment.java
+++ b/src/com/android/settings/sim/smartForwarding/SmartForwardingFragment.java
@@ -48,8 +48,7 @@
     public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
         setPreferencesFromResource(R.xml.smart_forwarding_switch, rootKey);
 
-        String title = getResources().getString(R.string.smart_forwarding_title);
-        getActivity().getActionBar().setTitle(title);
+        getActivity().setTitle(R.string.smart_forwarding_title);
 
         TwoStatePreference smartForwardingSwitch = findPreference(KEY_SMART_FORWARDING_SWITCH);
         if (turnOffSwitch) {
diff --git a/src/com/android/settings/users/OWNERS b/src/com/android/settings/users/OWNERS
new file mode 100644
index 0000000..6afd0ad
--- /dev/null
+++ b/src/com/android/settings/users/OWNERS
@@ -0,0 +1 @@
+include platform/frameworks/base:/MULTIUSER_OWNERS
diff --git a/src/com/android/settings/wifi/WifiConfigInfo.java b/src/com/android/settings/wifi/WifiConfigInfo.java
index 0de3063..16a4446 100644
--- a/src/com/android/settings/wifi/WifiConfigInfo.java
+++ b/src/com/android/settings/wifi/WifiConfigInfo.java
@@ -37,6 +37,7 @@
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
+        WifiUtils.setupEdgeToEdge(this);
 
         mWifiManager = (WifiManager) getSystemService(WIFI_SERVICE);
         setContentView(R.layout.wifi_config_info);
diff --git a/src/com/android/settings/wifi/WifiStatusTest.java b/src/com/android/settings/wifi/WifiStatusTest.java
index b4f3ab6..b9b1d70 100644
--- a/src/com/android/settings/wifi/WifiStatusTest.java
+++ b/src/com/android/settings/wifi/WifiStatusTest.java
@@ -115,6 +115,7 @@
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
+        WifiUtils.setupEdgeToEdge(this);
 
         mWifiManager = (WifiManager) getSystemService(WIFI_SERVICE);
 
diff --git a/src/com/android/settings/wifi/WifiUtils.java b/src/com/android/settings/wifi/WifiUtils.java
index 68d8beb..e307bcf 100644
--- a/src/com/android/settings/wifi/WifiUtils.java
+++ b/src/com/android/settings/wifi/WifiUtils.java
@@ -16,6 +16,8 @@
 
 package com.android.settings.wifi;
 
+import android.app.ActionBar;
+import android.app.Activity;
 import android.app.admin.DevicePolicyManager;
 import android.content.ComponentName;
 import android.content.ContentResolver;
@@ -32,8 +34,13 @@
 import android.provider.Settings;
 import android.text.TextUtils;
 import android.util.Log;
+import android.util.TypedValue;
 
+import androidx.annotation.NonNull;
 import androidx.annotation.VisibleForTesting;
+import androidx.core.graphics.Insets;
+import androidx.core.view.ViewCompat;
+import androidx.core.view.WindowInsetsCompat;
 
 import com.android.settings.R;
 import com.android.settings.Utils;
@@ -308,4 +315,34 @@
     public static void setCanShowWifiHotspotCached(Boolean cached) {
         sCanShowWifiHotspotCached = cached;
     }
+
+    /**
+     * Enable new edge to edge feature.
+     *
+     * @param activity the Activity need to setup the edge to edge feature.
+     */
+    public static void setupEdgeToEdge(@NonNull Activity activity) {
+        final ActionBar actionBar = activity.getActionBar();
+        if (actionBar == null) {
+            return;
+        }
+
+        final TypedValue typedValue = new TypedValue();
+        if (activity.getTheme().resolveAttribute(
+                com.android.internal.R.attr.actionBarSize, typedValue, true)) {
+            ViewCompat.setOnApplyWindowInsetsListener(activity.findViewById(android.R.id.content),
+                    (v, windowInsets) -> {
+                        Insets insets = windowInsets.getInsets(
+                                WindowInsetsCompat.Type.systemBars() |
+                                WindowInsetsCompat.Type.ime());
+
+                        // Apply the insets paddings to the view.
+                        v.setPadding(insets.left, insets.top, insets.right, insets.bottom);
+
+                        // Return CONSUMED if you don't want the window insets to keep being
+                        // passed down to descendant views.
+                        return WindowInsetsCompat.CONSUMED;
+                    });
+        }
+    }
 }
diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowCrossProfileApps.java b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowCrossProfileApps.java
index 64a5f11..c52fe2f 100644
--- a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowCrossProfileApps.java
+++ b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowCrossProfileApps.java
@@ -19,9 +19,8 @@
 import android.Manifest;
 import android.content.Context;
 import android.content.pm.CrossProfileApps;
-import android.content.pm.ICrossProfileApps;
-import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
+import android.content.pm.PackageInfo;
 
 import androidx.annotation.NonNull;
 
@@ -35,15 +34,7 @@
 @Implements(CrossProfileApps.class)
 public class ShadowCrossProfileApps extends org.robolectric.shadows.ShadowCrossProfileApps {
     private static final Set<String> configurableInteractAcrossProfilePackages = new HashSet<>();
-    private Context mContext;
-    private PackageManager mPackageManager;
 
-    @Implementation
-    protected void __constructor__(Context context, ICrossProfileApps service) {
-        super.__constructor__(context, service);
-        this.mContext = context;
-        this.mPackageManager = context.getPackageManager();
-    }
     public void addCrossProfilePackage(String packageName) {
         configurableInteractAcrossProfilePackages.add(packageName);
     }
@@ -57,7 +48,9 @@
     protected boolean canUserAttemptToConfigureInteractAcrossProfiles(@NonNull String packageName) {
         PackageInfo packageInfo;
         try {
-            packageInfo = mPackageManager.getPackageInfo(packageName, /* flags= */ 0);
+            packageInfo = getContext().getPackageManager().getPackageInfo(
+                packageName,
+                /* flags= */ 0);
         } catch (PackageManager.NameNotFoundException e) {
             return false;
         }