Merge changes from topic "catalyst-firmware-version" into main

* changes:
  Migrate "Build number" preference
  Migrate "Kernel version" preference
  Migrate "Baseband version" preference
diff --git a/res/layout/dialog_audio_sharing_loading_state.xml b/res/layout/dialog_audio_sharing_progress.xml
similarity index 100%
rename from res/layout/dialog_audio_sharing_loading_state.xml
rename to res/layout/dialog_audio_sharing_progress.xml
diff --git a/src/com/android/settings/bluetooth/BluetoothDevicePairingDetailBase.java b/src/com/android/settings/bluetooth/BluetoothDevicePairingDetailBase.java
index 86f090e..f1e12a4 100644
--- a/src/com/android/settings/bluetooth/BluetoothDevicePairingDetailBase.java
+++ b/src/com/android/settings/bluetooth/BluetoothDevicePairingDetailBase.java
@@ -72,7 +72,7 @@
     private final Handler mHandler = new Handler(Looper.getMainLooper());
     private final ExecutorService mExecutor = Executors.newSingleThreadExecutor();
     @Nullable
-    private AlertDialog mLoadingDialog = null;
+    private AlertDialog mProgressDialog = null;
     @VisibleForTesting
     boolean mShouldTriggerAudioSharingShareThenPairFlow = false;
     private CopyOnWriteArrayList<BluetoothDevice> mDevicesWithMetadataChangedListener =
@@ -89,7 +89,7 @@
     // In share then pair flow, we have to wait on this page till the device is connected.
     // The BluetoothDevicePreference summary will be blank for seconds between "Pairing..." and
     // "Connecting..." To help users better understand the process, we listen to metadata change
-    // as well and show a loading dialog with "Connecting to ...." once BluetoothDevice.getState()
+    // as well and show a progress dialog with "Connecting to ...." once BluetoothDevice.getState()
     // gets to BOND_BONDED.
     final BluetoothAdapter.OnMetadataChangedListener mMetadataListener =
             new BluetoothAdapter.OnMetadataChangedListener() {
@@ -97,7 +97,7 @@
                 public void onMetadataChanged(@NonNull BluetoothDevice device, int key,
                         @Nullable byte[] value) {
                     Log.d(getLogTag(), "onMetadataChanged device = " + device + ", key  = " + key);
-                    if (mShouldTriggerAudioSharingShareThenPairFlow && mLoadingDialog == null
+                    if (mShouldTriggerAudioSharingShareThenPairFlow && mProgressDialog == null
                             && device.getBondState() == BluetoothDevice.BOND_BONDED
                             && mSelectedList.contains(device)) {
                         triggerAudioSharingShareThenPairFlow(device);
@@ -355,7 +355,7 @@
                 return;
             }
             mJustBonded = device;
-            // Show connecting device loading state
+            // Show connecting device progress
             String aliasName = device.getAlias();
             String deviceName = TextUtils.isEmpty(aliasName) ? device.getAddress()
                     : aliasName;
@@ -387,9 +387,9 @@
     // TODO: use DialogFragment
     private void showConnectingDialog(@NonNull String message) {
         postOnMainThread(() -> {
-            if (mLoadingDialog != null) {
+            if (mProgressDialog != null) {
                 Log.d(getLogTag(), "showConnectingDialog, is already showing");
-                TextView textView = mLoadingDialog.findViewById(R.id.message);
+                TextView textView = mProgressDialog.findViewById(R.id.message);
                 if (textView != null && !message.equals(textView.getText().toString())) {
                     Log.d(getLogTag(), "showConnectingDialog, update message");
                     // TODO: use string res once finalized
@@ -401,7 +401,7 @@
             AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
             LayoutInflater inflater = LayoutInflater.from(builder.getContext());
             View customView = inflater.inflate(
-                    R.layout.dialog_audio_sharing_loading_state, /* root= */
+                    R.layout.dialog_audio_sharing_progress, /* root= */
                     null);
             TextView textView = customView.findViewById(R.id.message);
             if (textView != null) {
@@ -410,15 +410,15 @@
             }
             AlertDialog dialog = builder.setView(customView).setCancelable(false).create();
             dialog.setCanceledOnTouchOutside(false);
-            mLoadingDialog = dialog;
+            mProgressDialog = dialog;
             dialog.show();
         });
     }
 
     private void dismissConnectingDialog() {
         postOnMainThread(() -> {
-            if (mLoadingDialog != null) {
-                mLoadingDialog.dismiss();
+            if (mProgressDialog != null) {
+                mProgressDialog.dismiss();
             }
         });
     }
diff --git a/src/com/android/settings/bluetooth/BluetoothSliceBuilder.java b/src/com/android/settings/bluetooth/BluetoothSliceBuilder.java
index fd8ef1f..f4060d6 100644
--- a/src/com/android/settings/bluetooth/BluetoothSliceBuilder.java
+++ b/src/com/android/settings/bluetooth/BluetoothSliceBuilder.java
@@ -26,6 +26,7 @@
 import android.content.IntentFilter;
 import android.net.Uri;
 import android.provider.SettingsSlicesContract;
+import android.util.Log;
 
 import androidx.core.graphics.drawable.IconCompat;
 import androidx.slice.Slice;
@@ -36,10 +37,16 @@
 import com.android.settings.R;
 import com.android.settings.SubSettings;
 import com.android.settings.connecteddevice.BluetoothDashboardFragment;
+import com.android.settings.network.SatelliteRepository;
 import com.android.settings.slices.CustomSliceRegistry;
 import com.android.settings.slices.SliceBroadcastReceiver;
 import com.android.settings.slices.SliceBuilderUtils;
 
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
 /**
  * Utility class to build a Bluetooth Slice, and handle all associated actions.
  */
@@ -80,18 +87,34 @@
         final PendingIntent primaryAction = getPrimaryAction(context);
         final SliceAction primarySliceAction = SliceAction.createDeeplink(primaryAction, icon,
                 ListBuilder.ICON_IMAGE, title);
-        final SliceAction toggleSliceAction = SliceAction.createToggle(toggleAction,
-                null /* actionTitle */, isBluetoothEnabled);
 
+        RowBuilder rowBuilder = new RowBuilder();
+        rowBuilder.setTitle(title);
+        rowBuilder.setPrimaryAction(primarySliceAction);
+        if (!isSatelliteOn(context)) {
+            final SliceAction toggleSliceAction = SliceAction.createToggle(toggleAction,
+                    null /* actionTitle */, isBluetoothEnabled);
+            rowBuilder.addEndItem(toggleSliceAction);
+        }
         return new ListBuilder(context, CustomSliceRegistry.BLUETOOTH_URI, ListBuilder.INFINITY)
                 .setAccentColor(color)
-                .addRow(new RowBuilder()
-                        .setTitle(title)
-                        .addEndItem(toggleSliceAction)
-                        .setPrimaryAction(primarySliceAction))
+                .addRow(rowBuilder)
                 .build();
     }
 
+    private static boolean isSatelliteOn(Context context) {
+        boolean result = false;
+        SatelliteRepository satelliteRepository = new SatelliteRepository(context);
+        try {
+            result = satelliteRepository.requestIsSessionStarted(
+                    Executors.newSingleThreadExecutor()).get(3000, TimeUnit.MILLISECONDS);
+        } catch (InterruptedException | ExecutionException | TimeoutException e) {
+            Log.e(TAG, "Error to get satellite status : " + e);
+        }
+
+        return result;
+    }
+
     public static Intent getIntent(Context context) {
         final String screenTitle = context.getText(R.string.bluetooth_settings_title).toString();
         final Uri contentUri = new Uri.Builder().appendPath(
diff --git a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingRetryDialogFragment.java b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingErrorDialogFragment.java
similarity index 88%
rename from src/com/android/settings/connecteddevice/audiosharing/AudioSharingRetryDialogFragment.java
rename to src/com/android/settings/connecteddevice/audiosharing/AudioSharingErrorDialogFragment.java
index 822e053..95b9bc3 100644
--- a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingRetryDialogFragment.java
+++ b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingErrorDialogFragment.java
@@ -29,8 +29,8 @@
 import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
 import com.android.settingslib.bluetooth.BluetoothUtils;
 
-public class AudioSharingRetryDialogFragment extends InstrumentedDialogFragment {
-    private static final String TAG = "AudioSharingRetryDialog";
+public class AudioSharingErrorDialogFragment extends InstrumentedDialogFragment {
+    private static final String TAG = "AudioSharingErrorDialog";
 
     @Override
     public int getMetricsCategory() {
@@ -39,7 +39,7 @@
     }
 
     /**
-     * Display the {@link AudioSharingRetryDialogFragment} dialog.
+     * Display the {@link AudioSharingErrorDialogFragment} dialog.
      *
      * @param host The Fragment this dialog will be hosted.
      */
@@ -57,8 +57,8 @@
             Log.d(TAG, "Dialog is showing, return.");
             return;
         }
-        Log.d(TAG, "Show up the retry dialog.");
-        AudioSharingRetryDialogFragment dialogFrag = new AudioSharingRetryDialogFragment();
+        Log.d(TAG, "Show up the error dialog.");
+        AudioSharingErrorDialogFragment dialogFrag = new AudioSharingErrorDialogFragment();
         dialogFrag.show(manager, TAG);
     }
 
diff --git a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingLoadingStateDialogFragment.java b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingProgressDialogFragment.java
similarity index 91%
rename from src/com/android/settings/connecteddevice/audiosharing/AudioSharingLoadingStateDialogFragment.java
rename to src/com/android/settings/connecteddevice/audiosharing/AudioSharingProgressDialogFragment.java
index 8706590..53bfcf8 100644
--- a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingLoadingStateDialogFragment.java
+++ b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingProgressDialogFragment.java
@@ -40,8 +40,8 @@
 
 import java.util.concurrent.TimeUnit;
 
-public class AudioSharingLoadingStateDialogFragment extends InstrumentedDialogFragment {
-    private static final String TAG = "AudioSharingLoadingDlg";
+public class AudioSharingProgressDialogFragment extends InstrumentedDialogFragment {
+    private static final String TAG = "AudioSharingProgressDlg";
 
     private static final String BUNDLE_KEY_MESSAGE = "bundle_key_message";
     private static final long AUTO_DISMISS_TIME_THRESHOLD_MS = TimeUnit.SECONDS.toMillis(15);
@@ -58,7 +58,7 @@
     }
 
     /**
-     * Display the {@link AudioSharingLoadingStateDialogFragment} dialog.
+     * Display the {@link AudioSharingProgressDialogFragment} dialog.
      *
      * @param host    The Fragment this dialog will be hosted by.
      * @param message The content to be shown on the dialog.
@@ -85,16 +85,15 @@
             return;
         }
         sMessage = message;
-        Log.d(TAG, "Show up the loading dialog.");
+        Log.d(TAG, "Show up the progress dialog.");
         Bundle args = new Bundle();
         args.putString(BUNDLE_KEY_MESSAGE, message);
-        AudioSharingLoadingStateDialogFragment dialogFrag =
-                new AudioSharingLoadingStateDialogFragment();
+        AudioSharingProgressDialogFragment dialogFrag = new AudioSharingProgressDialogFragment();
         dialogFrag.setArguments(args);
         dialogFrag.show(manager, TAG);
     }
 
-    /** Dismiss the {@link AudioSharingLoadingStateDialogFragment} dialog. */
+    /** Dismiss the {@link AudioSharingProgressDialogFragment} dialog. */
     public static void dismiss(@Nullable Fragment host) {
         if (host == null || !BluetoothUtils.isAudioSharingEnabled()) return;
         final FragmentManager manager;
@@ -119,7 +118,7 @@
         String message = args.getString(BUNDLE_KEY_MESSAGE, "");
         AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
         LayoutInflater inflater = LayoutInflater.from(builder.getContext());
-        View customView = inflater.inflate(R.layout.dialog_audio_sharing_loading_state, /* root= */
+        View customView = inflater.inflate(R.layout.dialog_audio_sharing_progress, /* root= */
                 null);
         TextView textView = customView.findViewById(R.id.message);
         if (!Strings.isNullOrEmpty(message)) textView.setText(message);
diff --git a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingSwitchBarController.java b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingSwitchBarController.java
index 395647c..ebc8cec 100644
--- a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingSwitchBarController.java
+++ b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingSwitchBarController.java
@@ -41,7 +41,9 @@
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
+import androidx.annotation.UiThread;
 import androidx.annotation.VisibleForTesting;
+import androidx.fragment.app.DialogFragment;
 import androidx.fragment.app.Fragment;
 import androidx.lifecycle.DefaultLifecycleObserver;
 import androidx.lifecycle.LifecycleOwner;
@@ -69,7 +71,6 @@
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
-import java.util.Locale;
 import java.util.Map;
 import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.concurrent.Executor;
@@ -113,14 +114,21 @@
     private final Executor mExecutor;
     private final MetricsFeatureProvider mMetricsFeatureProvider;
     private final OnAudioSharingStateChangedListener mListener;
+    @VisibleForTesting IntentFilter mIntentFilter;
     private Map<Integer, List<BluetoothDevice>> mGroupedConnectedDevices = new HashMap<>();
     @Nullable private AudioSharingDeviceItem mTargetActiveItem;
     private List<AudioSharingDeviceItem> mDeviceItemsForSharing = new ArrayList<>();
-    @VisibleForTesting IntentFilter mIntentFilter;
     private final AtomicBoolean mCallbacksRegistered = new AtomicBoolean(false);
     private AtomicInteger mIntentHandleStage =
             new AtomicInteger(StartIntentHandleStage.TO_HANDLE.ordinal());
+    // The sinks in adding source process. We show the progress dialog based on this list.
     private CopyOnWriteArrayList<BluetoothDevice> mSinksInAdding = new CopyOnWriteArrayList<>();
+    // The primary/active sinks in adding source process.
+    // To avoid users advance to share then pair flow before the primary/active sinks successfully
+    // join the audio sharing, we will wait for the process complete for this list of sinks and then
+    // popup audio sharing dialog with options to pair new device.
+    private CopyOnWriteArrayList<BluetoothDevice> mSinksToWaitFor = new CopyOnWriteArrayList<>();
+    private AtomicBoolean mStoppingSharing = new AtomicBoolean(false);
 
     @VisibleForTesting
     BroadcastReceiver mReceiver =
@@ -153,6 +161,7 @@
                 public void onBroadcastStartFailed(int reason) {
                     Log.d(TAG, "onBroadcastStartFailed(), reason = " + reason);
                     updateSwitch();
+                    showErrorDialog();
                     mMetricsFeatureProvider.action(
                             mContext,
                             SettingsEnums.ACTION_AUDIO_SHARING_START_FAILED,
@@ -178,7 +187,10 @@
                                     + reason
                                     + ", broadcastId = "
                                     + broadcastId);
+                    mStoppingSharing.compareAndSet(true, false);
                     updateSwitch();
+                    AudioSharingUtils.postOnMainThread(mContext,
+                            () -> dismissStaleDialogsOtherThanErrorDialog());
                     AudioSharingUtils.toastMessage(
                             mContext,
                             mContext.getString(R.string.audio_sharing_sharing_stopped_label));
@@ -219,7 +231,7 @@
                                 TAG,
                                 "Skip handleOnBroadcastReady: null assistant or "
                                         + "sink has active local source.");
-                        cleanUp();
+                        cleanUpStatesForStartSharing();
                         return;
                     }
                     handleOnBroadcastReady();
@@ -264,17 +276,14 @@
                                     + source
                                     + ", reason = "
                                     + reason);
-                    mMetricsFeatureProvider.action(
-                            mContext,
-                            SettingsEnums.ACTION_AUDIO_SHARING_JOIN_FAILED,
-                            SettingsEnums.AUDIO_SHARING_SETTINGS);
-                    AudioSharingUtils.toastMessage(
-                            mContext,
-                            String.format(
-                                    Locale.US,
-                                    "Fail to add source to %s reason %d",
-                                    sink.getAddress(),
-                                    reason));
+                    if (mSinksInAdding.contains(sink)) {
+                        stopAudioSharing();
+                        showErrorDialog();
+                        mMetricsFeatureProvider.action(
+                                mContext,
+                                SettingsEnums.ACTION_AUDIO_SHARING_JOIN_FAILED,
+                                SettingsEnums.AUDIO_SHARING_SETTINGS);
+                    }
                 }
 
                 @Override
@@ -298,13 +307,33 @@
                         @NonNull BluetoothDevice sink,
                         int sourceId,
                         @NonNull BluetoothLeBroadcastReceiveState state) {
+                    if (mStoppingSharing.get()) {
+                        Log.d(TAG, "Skip onReceiveStateChanged, stopping broadcast");
+                        return;
+                    }
                     if (BluetoothUtils.isConnected(state)) {
                         if (mSinksInAdding.contains(sink)) {
                             mSinksInAdding.remove(sink);
                         }
-                        dismissLoadingStateDialogIfNeeded();
+                        dismissProgressDialogIfNeeded();
                         Log.d(TAG, "onReceiveStateChanged() connected, sink = " + sink
                                 + ", remaining sinks = " + mSinksInAdding);
+                        if (mSinksToWaitFor.contains(sink)) {
+                            mSinksToWaitFor.remove(sink);
+                            if (mSinksToWaitFor.isEmpty()) {
+                                // To avoid users advance to share then pair flow before the
+                                // primary/active sinks successfully join the audio sharing,
+                                // popup dialog till adding source complete for mSinksToWaitFor.
+                                Pair<Integer, Object>[] eventData =
+                                        AudioSharingUtils.buildAudioSharingDialogEventData(
+                                                SettingsEnums.AUDIO_SHARING_SETTINGS,
+                                                SettingsEnums.DIALOG_AUDIO_SHARING_ADD_DEVICE,
+                                                /* userTriggered= */ false,
+                                                /* deviceCountInSharing= */ 1,
+                                                /* candidateDeviceCount= */ 0);
+                                showAudioSharingDialog(eventData);
+                            }
+                        }
                     }
                 }
             };
@@ -411,6 +440,8 @@
                 return;
             }
             stopAudioSharing();
+            mMetricsFeatureProvider.action(
+                    mContext, SettingsEnums.ACTION_AUDIO_SHARING_MAIN_SWITCH_OFF);
         }
     }
 
@@ -542,7 +573,7 @@
             mSinksInAdding.clear();
             // TODO: use string res once finalized.
             AudioSharingUtils.postOnMainThread(mContext,
-                    () -> AudioSharingLoadingStateDialogFragment.show(mFragment,
+                    () -> AudioSharingProgressDialogFragment.show(mFragment,
                             "Starting audio stream..."));
             mMetricsFeatureProvider.action(
                     mContext,
@@ -553,9 +584,14 @@
 
     private void stopAudioSharing() {
         if (mBroadcast != null) {
-            mBroadcast.stopBroadcast(mBroadcast.getLatestBroadcastId());
-            mMetricsFeatureProvider.action(
-                    mContext, SettingsEnums.ACTION_AUDIO_SHARING_MAIN_SWITCH_OFF);
+            int broadcastId = mBroadcast.getLatestBroadcastId();
+            if (broadcastId != -1) {
+                mBroadcast.stopBroadcast(broadcastId);
+                mStoppingSharing.compareAndSet(false, true);
+                mSinksInAdding.clear();
+                mSinksToWaitFor.clear();
+            }
+            cleanUpStatesForStartSharing();
         }
     }
 
@@ -617,11 +653,22 @@
                         /* userTriggered= */ false,
                         /* deviceCountInSharing= */ targetActiveSinks.isEmpty() ? 0 : 1,
                         /* candidateDeviceCount= */ mDeviceItemsForSharing.size());
+        // Auto add primary/active sinks w/o user interactions.
         if (!targetActiveSinks.isEmpty() && mTargetActiveItem != null) {
             Log.d(TAG, "handleOnBroadcastReady: automatically add source to active sinks.");
             addSourceToTargetSinks(targetActiveSinks, mTargetActiveItem.getName());
+            // To avoid users advance to share then pair flow before the primary/active sinks
+            // successfully join the audio sharing, save the primary/active sinks in mSinksToWaitFor
+            // and popup dialog till adding source complete for these sinks.
+            if (mDeviceItemsForSharing.isEmpty()) {
+                mSinksToWaitFor.clear();
+                mSinksToWaitFor.addAll(targetActiveSinks);
+            }
             mMetricsFeatureProvider.action(mContext, SettingsEnums.ACTION_AUTO_JOIN_AUDIO_SHARING);
             mTargetActiveItem = null;
+            // When audio sharing page is brought up by intent with EXTRA_START_LE_AUDIO_SHARING
+            // == true, plus there is one active lea headset and one connected lea headset, we
+            // should auto add these sinks without user interactions.
             if (mIntentHandleStage.compareAndSet(
                     StartIntentHandleStage.HANDLE_AUTO_ADD.ordinal(),
                     StartIntentHandleStage.HANDLED.ordinal())
@@ -631,31 +678,42 @@
                 List<BluetoothDevice> targetSinks = mGroupedConnectedDevices.getOrDefault(
                         target.getGroupId(), ImmutableList.of());
                 addSourceToTargetSinks(targetSinks, target.getName());
-                cleanUp();
+                cleanUpStatesForStartSharing();
                 // TODO: Add metric for auto add by intent
                 return;
             }
         }
+        // Still mark intent as handled if early returned due to preconditions not met
         mIntentHandleStage.compareAndSet(
                 StartIntentHandleStage.HANDLE_AUTO_ADD.ordinal(),
                 StartIntentHandleStage.HANDLED.ordinal());
         if (mFragment == null) {
             Log.d(TAG, "handleOnBroadcastReady: dialog fail to show due to null fragment.");
-            dismissLoadingStateDialogIfNeeded();
-            cleanUp();
+            // Clean up states before early return.
+            dismissProgressDialogIfNeeded();
+            cleanUpStatesForStartSharing();
             return;
         }
-        showDialog(eventData);
+        // To avoid users advance to share then pair flow before the primary/active sinks
+        // successfully join the audio sharing, popup dialog till adding source complete for
+        // mSinksToWaitFor.
+        if (mSinksToWaitFor.isEmpty() && !mStoppingSharing.get()) {
+            showAudioSharingDialog(eventData);
+        }
     }
 
-    private void showDialog(Pair<Integer, Object>[] eventData) {
+    private void showAudioSharingDialog(Pair<Integer, Object>[] eventData) {
+        if (!BluetoothUtils.isBroadcasting(mBtManager)) {
+            Log.d(TAG, "Skip showAudioSharingDialog, broadcast is stopped");
+            return;
+        }
         AudioSharingDialogFragment.DialogEventListener listener =
                 new AudioSharingDialogFragment.DialogEventListener() {
                     @Override
                     public void onPositiveClick() {
-                        // Could go to other pages, dismiss the loading dialog.
-                        dismissLoadingStateDialogIfNeeded();
-                        cleanUp();
+                        // Could go to other pages, dismiss the progress dialog.
+                        dismissProgressDialogIfNeeded();
+                        cleanUpStatesForStartSharing();
                     }
 
                     @Override
@@ -663,14 +721,14 @@
                         List<BluetoothDevice> targetSinks = mGroupedConnectedDevices.getOrDefault(
                                 item.getGroupId(), ImmutableList.of());
                         addSourceToTargetSinks(targetSinks, item.getName());
-                        cleanUp();
+                        cleanUpStatesForStartSharing();
                     }
 
                     @Override
                     public void onCancelClick() {
-                        // Could go to other pages, dismiss the loading dialog.
-                        dismissLoadingStateDialogIfNeeded();
-                        cleanUp();
+                        // Could go to other pages, dismiss the progress dialog.
+                        dismissProgressDialogIfNeeded();
+                        cleanUpStatesForStartSharing();
                     }
                 };
         AudioSharingUtils.postOnMainThread(
@@ -684,6 +742,36 @@
                 });
     }
 
+    private void showErrorDialog() {
+        AudioSharingUtils.postOnMainThread(mContext,
+                () -> {
+                    // Remove all stale dialogs before showing error dialog
+                    dismissStaleDialogsOtherThanErrorDialog();
+                    AudioSharingErrorDialogFragment.show(mFragment);
+                });
+    }
+
+    @UiThread
+    private void dismissStaleDialogsOtherThanErrorDialog() {
+        List<Fragment> fragments = new ArrayList<Fragment>();
+        try {
+            if (mFragment != null) {
+                fragments =
+                        mFragment.getChildFragmentManager().getFragments();
+            }
+        } catch (Exception e) {
+            Log.e(TAG, "Fail to dismiss stale dialogs: " + e.getMessage());
+        }
+        for (Fragment fragment : fragments) {
+            if (fragment != null && fragment instanceof DialogFragment
+                    && !(fragment instanceof AudioSharingErrorDialogFragment)
+                    && ((DialogFragment) fragment).getDialog() != null) {
+                Log.d(TAG, "Remove stale dialog = " + fragment.getTag());
+                ((DialogFragment) fragment).dismiss();
+            }
+        }
+    }
+
     private static final class MainSwitchAccessibilityDelegate extends View.AccessibilityDelegate {
         @Override
         public boolean onRequestSendAccessibilityEvent(
@@ -742,25 +830,25 @@
     private void addSourceToTargetSinks(List<BluetoothDevice> targetActiveSinks,
             @NonNull String sinkName) {
         mSinksInAdding.addAll(targetActiveSinks);
-        AudioSharingUtils.addSourceToTargetSinks(targetActiveSinks, mBtManager);
         // TODO: move to res once finalized
-        String loadingMessage = "Sharing with " + sinkName + "...";
-        showLoadingStateDialog(loadingMessage);
+        String progressMessage = "Sharing with " + sinkName + "...";
+        showProgressDialog(progressMessage);
+        AudioSharingUtils.addSourceToTargetSinks(targetActiveSinks, mBtManager);
     }
 
-    private void showLoadingStateDialog(@NonNull String loadingMessage) {
+    private void showProgressDialog(@NonNull String progressMessage) {
         AudioSharingUtils.postOnMainThread(mContext,
-                () -> AudioSharingLoadingStateDialogFragment.show(mFragment, loadingMessage));
+                () -> AudioSharingProgressDialogFragment.show(mFragment, progressMessage));
     }
 
-    private void dismissLoadingStateDialogIfNeeded() {
+    private void dismissProgressDialogIfNeeded() {
         if (mSinksInAdding.isEmpty()) {
             AudioSharingUtils.postOnMainThread(mContext,
-                    () -> AudioSharingLoadingStateDialogFragment.dismiss(mFragment));
+                    () -> AudioSharingProgressDialogFragment.dismiss(mFragment));
         }
     }
 
-    private void cleanUp() {
+    private void cleanUpStatesForStartSharing() {
         mGroupedConnectedDevices.clear();
         mDeviceItemsForSharing.clear();
     }
diff --git a/src/com/android/settings/language/OnDeviceRecognitionPreferenceController.java b/src/com/android/settings/language/OnDeviceRecognitionPreferenceController.java
index cd9f266..d0dec64 100644
--- a/src/com/android/settings/language/OnDeviceRecognitionPreferenceController.java
+++ b/src/com/android/settings/language/OnDeviceRecognitionPreferenceController.java
@@ -20,7 +20,6 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
-import android.content.pm.UserInfo;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.text.TextUtils;
@@ -80,10 +79,7 @@
     }
 
     private void show(Preference preference) {
-        final List<UserHandle> userHandles = new ArrayList<>();
-        for (UserInfo userInfo : UserManager.get(mContext).getUsers()) {
-            userHandles.add(userInfo.getUserHandle());
-        }
+        final List<UserHandle> userHandles = UserManager.get(mContext).getEnabledProfiles();
 
         // Only a single profile is installed. Proceed with its settings.
         if (userHandles.size() == 1) {
diff --git a/src/com/android/settings/network/MobileNetworkListFragment.kt b/src/com/android/settings/network/MobileNetworkListFragment.kt
index d110779..3118088 100644
--- a/src/com/android/settings/network/MobileNetworkListFragment.kt
+++ b/src/com/android/settings/network/MobileNetworkListFragment.kt
@@ -89,7 +89,7 @@
             private val simRepositoryFactory: (Context) -> SimRepository = ::SimRepository
         ) : BaseSearchIndexProvider(R.xml.network_provider_sims_list) {
             public override fun isPageSearchEnabled(context: Context): Boolean =
-                simRepositoryFactory(context).showMobileNetworkPage()
+                simRepositoryFactory(context).canEnterMobileNetworkPage()
         }
     }
 }
diff --git a/src/com/android/settings/network/MobileNetworkSummaryController.kt b/src/com/android/settings/network/MobileNetworkSummaryController.kt
index 5980bbd..8cf9bec 100644
--- a/src/com/android/settings/network/MobileNetworkSummaryController.kt
+++ b/src/com/android/settings/network/MobileNetworkSummaryController.kt
@@ -57,7 +57,7 @@
     private var isAirplaneModeOn = false
 
     override fun getAvailabilityStatus() =
-        if (SimRepository(mContext).showMobileNetworkPage()) AVAILABLE
+        if (SimRepository(mContext).showMobileNetworkPageEntrance()) AVAILABLE
         else CONDITIONALLY_UNAVAILABLE
 
     override fun displayPreference(screen: PreferenceScreen) {
diff --git a/src/com/android/settings/network/SimOnboardingActivity.kt b/src/com/android/settings/network/SimOnboardingActivity.kt
index 25afb66..7fab9c9 100644
--- a/src/com/android/settings/network/SimOnboardingActivity.kt
+++ b/src/com/android/settings/network/SimOnboardingActivity.kt
@@ -53,8 +53,8 @@
 import androidx.lifecycle.LifecycleRegistry
 import com.android.settings.R
 import com.android.settings.SidecarFragment
+import com.android.settings.network.telephony.SimRepository
 import com.android.settings.network.telephony.SubscriptionActionDialogActivity
-import com.android.settings.network.telephony.SubscriptionRepository
 import com.android.settings.network.telephony.ToggleSubscriptionDialogActivity
 import com.android.settings.network.telephony.requireSubscriptionManager
 import com.android.settings.spa.SpaActivity.Companion.startSpaActivity
@@ -578,6 +578,10 @@
             subId: Int,
             isNewTask: Boolean = false,
         ) {
+            if (!SimRepository(context).canEnterMobileNetworkPage()) {
+                Log.i(TAG, "Unable to start SimOnboardingActivity due to missing permissions")
+                return
+            }
             val intent = Intent(context, SimOnboardingActivity::class.java).apply {
                 putExtra(SUB_ID, subId)
                 if(isNewTask) {
diff --git a/src/com/android/settings/network/TopLevelNetworkEntryPreferenceController.kt b/src/com/android/settings/network/TopLevelNetworkEntryPreferenceController.kt
index 1722f6a..11698a6 100644
--- a/src/com/android/settings/network/TopLevelNetworkEntryPreferenceController.kt
+++ b/src/com/android/settings/network/TopLevelNetworkEntryPreferenceController.kt
@@ -48,7 +48,7 @@
 
     override fun getSummary(): CharSequence {
         val summaryResId =
-            if (simRepository.showMobileNetworkPage()) {
+            if (simRepository.showMobileNetworkPageEntrance()) {
                 R.string.network_dashboard_summary_mobile
             } else {
                 R.string.network_dashboard_summary_no_mobile
diff --git a/src/com/android/settings/network/telephony/MobileNetworkSettingsSearchIndex.kt b/src/com/android/settings/network/telephony/MobileNetworkSettingsSearchIndex.kt
index 83e3a31..f850e1d 100644
--- a/src/com/android/settings/network/telephony/MobileNetworkSettingsSearchIndex.kt
+++ b/src/com/android/settings/network/telephony/MobileNetworkSettingsSearchIndex.kt
@@ -21,7 +21,6 @@
 import android.telephony.SubscriptionInfo
 import com.android.settings.R
 import com.android.settings.datausage.BillingCyclePreferenceController.Companion.BillingCycleSearchItem
-import com.android.settings.network.SubscriptionUtil
 import com.android.settings.network.telephony.CarrierSettingsVersionPreferenceController.Companion.CarrierSettingsVersionSearchItem
 import com.android.settings.network.telephony.DataUsagePreferenceController.Companion.DataUsageSearchItem
 import com.android.settings.network.telephony.MmsMessagePreferenceController.Companion.MmsMessageSearchItem
@@ -36,7 +35,6 @@
 import com.android.settings.spa.search.SpaSearchRepository.Companion.searchIndexProviderOf
 import com.android.settingslib.search.SearchIndexableData
 import com.android.settingslib.search.SearchIndexableRaw
-import com.android.settingslib.spaprivileged.framework.common.userManager
 import com.android.settingslib.spaprivileged.settingsprovider.settingsGlobalBoolean
 
 class MobileNetworkSettingsSearchIndex(
@@ -109,12 +107,8 @@
     companion object {
         /** suppress full page if user is not admin */
         @JvmStatic
-        fun isMobileNetworkSettingsSearchable(context: Context): Boolean {
-            val isAirplaneMode by context.settingsGlobalBoolean(Settings.Global.AIRPLANE_MODE_ON)
-            return SubscriptionUtil.isSimHardwareVisible(context) &&
-                !isAirplaneMode &&
-                context.userManager.isAdminUser
-        }
+        fun isMobileNetworkSettingsSearchable(context: Context): Boolean =
+            SimRepository(context).canEnterMobileNetworkPage()
 
         fun createSearchItems(context: Context): List<MobileNetworkSettingsSearchItem> =
             listOf(
diff --git a/src/com/android/settings/network/telephony/SimRepository.kt b/src/com/android/settings/network/telephony/SimRepository.kt
index ed3c8aa..baff5cb 100644
--- a/src/com/android/settings/network/telephony/SimRepository.kt
+++ b/src/com/android/settings/network/telephony/SimRepository.kt
@@ -18,13 +18,24 @@
 
 import android.content.Context
 import android.content.pm.PackageManager
+import android.os.UserManager
+import android.provider.Settings
 import com.android.settingslib.spaprivileged.framework.common.userManager
+import com.android.settingslib.spaprivileged.settingsprovider.settingsGlobalBoolean
 
-class SimRepository(context: Context) {
+class SimRepository(private val context: Context) {
     private val packageManager = context.packageManager
     private val userManager = context.userManager
 
-    /** Gets whether we show mobile network settings page to the current user. */
-    fun showMobileNetworkPage(): Boolean =
+    /** Gets whether show mobile network settings page entrance to the current user. */
+    fun showMobileNetworkPageEntrance(): Boolean =
         packageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY) && userManager.isAdminUser
+
+    /** Gets whether current user can enter mobile network settings page. */
+    fun canEnterMobileNetworkPage(): Boolean {
+        val isAirplaneMode by context.settingsGlobalBoolean(Settings.Global.AIRPLANE_MODE_ON)
+        return showMobileNetworkPageEntrance() &&
+            !isAirplaneMode &&
+            !userManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS)
+    }
 }
diff --git a/src/com/android/settings/notification/zen/ZenModeBackend.java b/src/com/android/settings/notification/zen/ZenModeBackend.java
index de641c5..c85b06b 100644
--- a/src/com/android/settings/notification/zen/ZenModeBackend.java
+++ b/src/com/android/settings/notification/zen/ZenModeBackend.java
@@ -458,7 +458,7 @@
     }
 
     private static List<String> getDefaultRuleIds() {
-        return ZenModeConfig.DEFAULT_RULE_IDS;
+        return ZenModeConfig.getDefaultRuleIds();
     }
 
     NotificationManager.Policy toNotificationPolicy(ZenPolicy policy) {
diff --git a/src/com/android/settings/sim/receivers/SimSlotChangeHandler.java b/src/com/android/settings/sim/receivers/SimSlotChangeHandler.java
index 6e28a0d..f808924 100644
--- a/src/com/android/settings/sim/receivers/SimSlotChangeHandler.java
+++ b/src/com/android/settings/sim/receivers/SimSlotChangeHandler.java
@@ -206,7 +206,12 @@
         if (hasActiveEsimSubscription()) {
             if (mTelMgr.isMultiSimSupported() == TelephonyManager.MULTISIM_ALLOWED) {
                 Log.i(TAG, "Enabled profile exists. DSDS condition satisfied.");
-                startDsdsDialogActivity();
+                if (Flags.isDualSimOnboardingEnabled()) {
+                    // enable dsds by sim onboarding flow
+                    handleRemovableSimInsertWhenDsds(removableSlotInfo);
+                } else {
+                    startDsdsDialogActivity();
+                }
             } else {
                 Log.i(TAG, "Enabled profile exists. DSDS condition not satisfied.");
                 startChooseSimActivity(true);
diff --git a/src/com/android/settings/spa/network/NetworkCellularGroupProvider.kt b/src/com/android/settings/spa/network/NetworkCellularGroupProvider.kt
index d736fe5..f60ba81 100644
--- a/src/com/android/settings/spa/network/NetworkCellularGroupProvider.kt
+++ b/src/com/android/settings/spa/network/NetworkCellularGroupProvider.kt
@@ -212,7 +212,7 @@
         const val fileName = "NetworkCellularGroupProvider"
 
         private fun isPageSearchable(context: Context) =
-            Flags.isDualSimOnboardingEnabled() && SimRepository(context).showMobileNetworkPage()
+            Flags.isDualSimOnboardingEnabled() && SimRepository(context).canEnterMobileNetworkPage()
     }
 }
 
diff --git a/src/com/android/settings/widget/TickButtonPreference.java b/src/com/android/settings/widget/TickButtonPreference.java
index 4778f8c..6bd17de 100644
--- a/src/com/android/settings/widget/TickButtonPreference.java
+++ b/src/com/android/settings/widget/TickButtonPreference.java
@@ -21,6 +21,8 @@
 import android.view.View;
 import android.widget.ImageView;
 
+import androidx.annotation.Nullable;
+import androidx.annotation.NonNull;
 import androidx.preference.PreferenceViewHolder;
 
 import com.android.settings.R;
@@ -35,6 +37,10 @@
         super(context);
     }
 
+    public TickButtonPreference(@NonNull Context context, @Nullable AttributeSet attrs) {
+        super(context, attrs);
+    }
+
     @Override
     public void onBindViewHolder(PreferenceViewHolder holder) {
         super.onBindViewHolder(holder);
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingRetryDialogFragmentTest.java b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingErrorDialogFragmentTest.java
similarity index 91%
rename from tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingRetryDialogFragmentTest.java
rename to tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingErrorDialogFragmentTest.java
index 4b0524b..fc38cd2 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingRetryDialogFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingErrorDialogFragmentTest.java
@@ -51,14 +51,14 @@
                 ShadowAlertDialogCompat.class,
                 ShadowBluetoothAdapter.class,
         })
-public class AudioSharingRetryDialogFragmentTest {
+public class AudioSharingErrorDialogFragmentTest {
     @Rule
     public final MockitoRule mocks = MockitoJUnit.rule();
     @Rule
     public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
 
     private Fragment mParent;
-    private AudioSharingRetryDialogFragment mFragment;
+    private AudioSharingErrorDialogFragment mFragment;
 
     @Before
     public void setUp() {
@@ -70,7 +70,7 @@
                 BluetoothStatusCodes.FEATURE_SUPPORTED);
         shadowBluetoothAdapter.setIsLeAudioBroadcastAssistantSupported(
                 BluetoothStatusCodes.FEATURE_SUPPORTED);
-        mFragment = new AudioSharingRetryDialogFragment();
+        mFragment = new AudioSharingErrorDialogFragment();
         mParent = new Fragment();
         FragmentController.setupFragment(
                 mParent, FragmentActivity.class, /* containerViewId= */ 0, /* bundle= */ null);
@@ -91,7 +91,7 @@
     @Test
     public void onCreateDialog_flagOff_dialogNotExist() {
         mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
-        AudioSharingRetryDialogFragment.show(mParent);
+        AudioSharingErrorDialogFragment.show(mParent);
         shadowMainLooper().idle();
         AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
         assertThat(dialog).isNull();
@@ -100,7 +100,7 @@
     @Test
     public void onCreateDialog_unattachedFragment_dialogNotExist() {
         mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
-        AudioSharingRetryDialogFragment.show(new Fragment());
+        AudioSharingErrorDialogFragment.show(new Fragment());
         shadowMainLooper().idle();
         AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
         assertThat(dialog).isNull();
@@ -109,7 +109,7 @@
     @Test
     public void onCreateDialog_flagOn_showDialog() {
         mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
-        AudioSharingRetryDialogFragment.show(mParent);
+        AudioSharingErrorDialogFragment.show(mParent);
         shadowMainLooper().idle();
         AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
         assertThat(dialog).isNotNull();
@@ -119,7 +119,7 @@
     @Test
     public void onCreateDialog_clickOk_dialogDismiss() {
         mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
-        AudioSharingRetryDialogFragment.show(mParent);
+        AudioSharingErrorDialogFragment.show(mParent);
         shadowMainLooper().idle();
         AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
         assertThat(dialog).isNotNull();
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingLoadingStateDialogFragmentTest.java b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingProgressDialogFragmentTest.java
similarity index 86%
rename from tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingLoadingStateDialogFragmentTest.java
rename to tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingProgressDialogFragmentTest.java
index ff15f52..b08e5c5 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingLoadingStateDialogFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingProgressDialogFragmentTest.java
@@ -52,7 +52,7 @@
                 ShadowAlertDialogCompat.class,
                 ShadowBluetoothAdapter.class,
         })
-public class AudioSharingLoadingStateDialogFragmentTest {
+public class AudioSharingProgressDialogFragmentTest {
     @Rule public final MockitoRule mocks = MockitoJUnit.rule();
     @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
 
@@ -60,7 +60,7 @@
     private static final String TEST_MESSAGE2 = "message2";
 
     private Fragment mParent;
-    private AudioSharingLoadingStateDialogFragment mFragment;
+    private AudioSharingProgressDialogFragment mFragment;
 
     @Before
     public void setUp() {
@@ -72,7 +72,7 @@
                 BluetoothStatusCodes.FEATURE_SUPPORTED);
         shadowBluetoothAdapter.setIsLeAudioBroadcastAssistantSupported(
                 BluetoothStatusCodes.FEATURE_SUPPORTED);
-        mFragment = new AudioSharingLoadingStateDialogFragment();
+        mFragment = new AudioSharingProgressDialogFragment();
         mParent = new Fragment();
         FragmentController.setupFragment(
                 mParent, FragmentActivity.class, /* containerViewId= */ 0, /* bundle= */ null);
@@ -93,7 +93,7 @@
     @Test
     public void onCreateDialog_flagOff_dialogNotExist() {
         mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
-        AudioSharingLoadingStateDialogFragment.show(mParent, TEST_MESSAGE1);
+        AudioSharingProgressDialogFragment.show(mParent, TEST_MESSAGE1);
         shadowMainLooper().idle();
         AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
         assertThat(dialog).isNull();
@@ -102,7 +102,7 @@
     @Test
     public void onCreateDialog_unattachedFragment_dialogNotExist() {
         mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
-        AudioSharingLoadingStateDialogFragment.show(new Fragment(), TEST_MESSAGE1);
+        AudioSharingProgressDialogFragment.show(new Fragment(), TEST_MESSAGE1);
         shadowMainLooper().idle();
         AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
         assertThat(dialog).isNull();
@@ -111,7 +111,7 @@
     @Test
     public void onCreateDialog_flagOn_showDialog() {
         mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
-        AudioSharingLoadingStateDialogFragment.show(mParent, TEST_MESSAGE1);
+        AudioSharingProgressDialogFragment.show(mParent, TEST_MESSAGE1);
         shadowMainLooper().idle();
         AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
         assertThat(dialog).isNotNull();
@@ -124,13 +124,13 @@
     @Test
     public void dismissDialog_succeed() {
         mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
-        AudioSharingLoadingStateDialogFragment.show(mParent, TEST_MESSAGE1);
+        AudioSharingProgressDialogFragment.show(mParent, TEST_MESSAGE1);
         shadowMainLooper().idle();
         AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
         assertThat(dialog).isNotNull();
         assertThat(dialog.isShowing()).isTrue();
 
-        AudioSharingLoadingStateDialogFragment.dismiss(mParent);
+        AudioSharingProgressDialogFragment.dismiss(mParent);
         shadowMainLooper().idle();
         assertThat(dialog.isShowing()).isFalse();
     }
@@ -138,13 +138,13 @@
     @Test
     public void showDialog_sameMessage_keepExistingDialog() {
         mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
-        AudioSharingLoadingStateDialogFragment.show(mParent, TEST_MESSAGE1);
+        AudioSharingProgressDialogFragment.show(mParent, TEST_MESSAGE1);
         shadowMainLooper().idle();
         AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
         assertThat(dialog).isNotNull();
         assertThat(dialog.isShowing()).isTrue();
 
-        AudioSharingLoadingStateDialogFragment.show(mParent, TEST_MESSAGE1);
+        AudioSharingProgressDialogFragment.show(mParent, TEST_MESSAGE1);
         shadowMainLooper().idle();
         assertThat(dialog.isShowing()).isTrue();
     }
@@ -152,7 +152,7 @@
     @Test
     public void showDialog_newMessage_keepAndUpdateDialog() {
         mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
-        AudioSharingLoadingStateDialogFragment.show(mParent, TEST_MESSAGE1);
+        AudioSharingProgressDialogFragment.show(mParent, TEST_MESSAGE1);
         shadowMainLooper().idle();
         AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
         assertThat(dialog).isNotNull();
@@ -161,7 +161,7 @@
         assertThat(view).isNotNull();
         assertThat(view.getText().toString()).isEqualTo(TEST_MESSAGE1);
 
-        AudioSharingLoadingStateDialogFragment.show(mParent, TEST_MESSAGE2);
+        AudioSharingProgressDialogFragment.show(mParent, TEST_MESSAGE2);
         shadowMainLooper().idle();
         assertThat(dialog.isShowing()).isTrue();
         assertThat(view.getText().toString()).isEqualTo(TEST_MESSAGE2);
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingSwitchBarControllerTest.java b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingSwitchBarControllerTest.java
index eb2083e..58696dc 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingSwitchBarControllerTest.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingSwitchBarControllerTest.java
@@ -146,6 +146,7 @@
     @Mock private LocalBluetoothLeBroadcastAssistant mAssistant;
     @Mock private VolumeControlProfile mVolumeControl;
     @Mock private BluetoothLeBroadcastMetadata mMetadata;
+    @Mock private BluetoothLeBroadcastReceiveState mState;
     @Mock private CompoundButton mBtnView;
     @Mock private CachedBluetoothDevice mCachedDevice1;
     @Mock private CachedBluetoothDevice mCachedDevice2;
@@ -499,7 +500,7 @@
 
         verify(mBroadcast).startPrivateBroadcast();
         List<Fragment> childFragments = mParentFragment.getChildFragmentManager().getFragments();
-        // No loading state dialog.
+        // No progress dialog.
         assertThat(childFragments).isEmpty();
 
         mController.mBroadcastCallback.onPlaybackStarted(0, 0);
@@ -519,10 +520,9 @@
                 mContext, FeatureFlagUtils.SETTINGS_NEED_CONNECTED_BLE_DEVICE_FOR_BROADCAST, true);
         when(mBtnView.isEnabled()).thenReturn(true);
         when(mAssistant.getAllConnectedDevices()).thenReturn(ImmutableList.of(mDevice2, mDevice1));
-        BluetoothLeBroadcastReceiveState state = mock(BluetoothLeBroadcastReceiveState.class);
-        when(state.getBroadcastId()).thenReturn(1);
+        when(mState.getBroadcastId()).thenReturn(1);
         when(mBroadcast.getLatestBroadcastId()).thenReturn(1);
-        when(mAssistant.getAllSources(mDevice2)).thenReturn(ImmutableList.of(state));
+        when(mAssistant.getAllSources(mDevice2)).thenReturn(ImmutableList.of(mState));
         when(mBroadcast.getLatestBluetoothLeBroadcastMetadata()).thenReturn(mMetadata);
         doNothing().when(mBroadcast).startPrivateBroadcast();
         mController.onCheckedChanged(mBtnView, /* isChecked= */ true);
@@ -531,7 +531,7 @@
         verify(mBroadcast).startPrivateBroadcast();
         List<Fragment> childFragments = mParentFragment.getChildFragmentManager().getFragments();
         assertThat(childFragments).comparingElementsUsing(CLAZZNAME_EQUALS).containsExactly(
-                AudioSharingLoadingStateDialogFragment.class.getName());
+                AudioSharingProgressDialogFragment.class.getName());
 
         mController.mBroadcastCallback.onPlaybackStarted(0, 0);
         shadowOf(Looper.getMainLooper()).idle();
@@ -549,27 +549,92 @@
     }
 
     @Test
-    public void onPlaybackStarted_showJoinAudioSharingDialog() {
+    public void onPlaybackStarted_singleActiveDevice_showJoinAudioSharingDialog() {
         FeatureFlagUtils.setEnabled(
                 mContext, FeatureFlagUtils.SETTINGS_NEED_CONNECTED_BLE_DEVICE_FOR_BROADCAST, true);
         when(mBtnView.isEnabled()).thenReturn(true);
-        when(mAssistant.getAllConnectedDevices()).thenReturn(ImmutableList.of(mDevice2, mDevice1));
+        when(mAssistant.getAllConnectedDevices()).thenReturn(ImmutableList.of(mDevice2));
         when(mAssistant.getAllSources(any(BluetoothDevice.class))).thenReturn(ImmutableList.of());
         doNothing().when(mBroadcast).startPrivateBroadcast();
-        when(mBroadcast.getLatestBluetoothLeBroadcastMetadata()).thenReturn(mMetadata);
         mController.onCheckedChanged(mBtnView, /* isChecked= */ true);
         shadowOf(Looper.getMainLooper()).idle();
 
         verify(mBroadcast).startPrivateBroadcast();
         List<Fragment> childFragments = mParentFragment.getChildFragmentManager().getFragments();
         assertThat(childFragments).comparingElementsUsing(CLAZZNAME_EQUALS).containsExactly(
-                AudioSharingLoadingStateDialogFragment.class.getName());
-        AudioSharingLoadingStateDialogFragment loadingFragment =
-                (AudioSharingLoadingStateDialogFragment) Iterables.getOnlyElement(childFragments);
+                AudioSharingProgressDialogFragment.class.getName());
+
+        when(mBroadcast.isEnabled(null)).thenReturn(true);
+        when(mBroadcast.getLatestBluetoothLeBroadcastMetadata()).thenReturn(mMetadata);
+        mController.mBroadcastCallback.onPlaybackStarted(0, 0);
+        shadowOf(Looper.getMainLooper()).idle();
+
+        verify(mFeatureFactory.metricsFeatureProvider)
+                .action(any(Context.class), eq(SettingsEnums.ACTION_AUTO_JOIN_AUDIO_SHARING));
+
+        when(mState.getBisSyncState()).thenReturn(ImmutableList.of(1L));
+        mController.mBroadcastAssistantCallback.onReceiveStateChanged(mDevice2, /* sourceId= */ 1,
+                mState);
+        shadowOf(Looper.getMainLooper()).idle();
+
+        childFragments = mParentFragment.getChildFragmentManager().getFragments();
+        assertThat(childFragments)
+                .comparingElementsUsing(CLAZZNAME_EQUALS)
+                .containsExactly(AudioSharingDialogFragment.class.getName());
+
+        Pair<Integer, Object>[] eventData = new Pair[0];
+        for (Fragment fragment : childFragments) {
+            if (fragment instanceof AudioSharingDialogFragment) {
+                eventData = ((AudioSharingDialogFragment) fragment).getEventData();
+                break;
+            }
+        }
+        assertThat(eventData)
+                .asList()
+                .containsExactly(
+                        Pair.create(
+                                AudioSharingUtils.MetricKey.METRIC_KEY_SOURCE_PAGE_ID.ordinal(),
+                                SettingsEnums.AUDIO_SHARING_SETTINGS),
+                        Pair.create(
+                                AudioSharingUtils.MetricKey.METRIC_KEY_PAGE_ID.ordinal(),
+                                SettingsEnums.DIALOG_AUDIO_SHARING_ADD_DEVICE),
+                        Pair.create(
+                                AudioSharingUtils.MetricKey.METRIC_KEY_USER_TRIGGERED.ordinal(), 0),
+                        Pair.create(
+                                AudioSharingUtils.MetricKey.METRIC_KEY_DEVICE_COUNT_IN_SHARING
+                                        .ordinal(),
+                                1),
+                        Pair.create(
+                                AudioSharingUtils.MetricKey.METRIC_KEY_CANDIDATE_DEVICE_COUNT
+                                        .ordinal(),
+                                0));
+
+        childFragments.forEach(fragment -> ((DialogFragment) fragment).dismiss());
+    }
+
+    @Test
+    public void onPlaybackStarted_oneActiveOnConnected_showJoinAudioSharingDialog() {
+        FeatureFlagUtils.setEnabled(
+                mContext, FeatureFlagUtils.SETTINGS_NEED_CONNECTED_BLE_DEVICE_FOR_BROADCAST, true);
+        when(mBtnView.isEnabled()).thenReturn(true);
+        when(mAssistant.getAllConnectedDevices()).thenReturn(ImmutableList.of(mDevice2, mDevice1));
+        when(mAssistant.getAllSources(any(BluetoothDevice.class))).thenReturn(ImmutableList.of());
+        doNothing().when(mBroadcast).startPrivateBroadcast();
+        mController.onCheckedChanged(mBtnView, /* isChecked= */ true);
+        shadowOf(Looper.getMainLooper()).idle();
+
+        verify(mBroadcast).startPrivateBroadcast();
+        List<Fragment> childFragments = mParentFragment.getChildFragmentManager().getFragments();
+        assertThat(childFragments).comparingElementsUsing(CLAZZNAME_EQUALS).containsExactly(
+                AudioSharingProgressDialogFragment.class.getName());
+        AudioSharingProgressDialogFragment progressFragment =
+                (AudioSharingProgressDialogFragment) Iterables.getOnlyElement(childFragments);
         // TODO: use string res once finalized
         String expectedMessage = "Starting audio stream...";
-        checkLoadingStateDialogMessage(loadingFragment, expectedMessage);
+        checkProgressDialogMessage(progressFragment, expectedMessage);
 
+        when(mBroadcast.isEnabled(null)).thenReturn(true);
+        when(mBroadcast.getLatestBluetoothLeBroadcastMetadata()).thenReturn(mMetadata);
         mController.mBroadcastCallback.onPlaybackStarted(0, 0);
         shadowOf(Looper.getMainLooper()).idle();
 
@@ -577,13 +642,13 @@
                 .action(any(Context.class), eq(SettingsEnums.ACTION_AUTO_JOIN_AUDIO_SHARING));
         // TODO: use string res once finalized
         expectedMessage = "Sharing with " + TEST_DEVICE_NAME2 + "...";
-        checkLoadingStateDialogMessage(loadingFragment, expectedMessage);
+        checkProgressDialogMessage(progressFragment, expectedMessage);
 
         childFragments = mParentFragment.getChildFragmentManager().getFragments();
         assertThat(childFragments)
                 .comparingElementsUsing(CLAZZNAME_EQUALS)
                 .containsExactly(AudioSharingDialogFragment.class.getName(),
-                        AudioSharingLoadingStateDialogFragment.class.getName());
+                        AudioSharingProgressDialogFragment.class.getName());
 
         Pair<Integer, Object>[] eventData = new Pair[0];
         for (Fragment fragment : childFragments) {
@@ -616,18 +681,19 @@
     }
 
     @Test
-    public void onPlaybackStarted_clickShareBtnOnDialog_addSource() {
+    public void onPlaybackStarted_oneActiveOnConnected_clickShareBtnOnDialog_addSource() {
         FeatureFlagUtils.setEnabled(
                 mContext, FeatureFlagUtils.SETTINGS_NEED_CONNECTED_BLE_DEVICE_FOR_BROADCAST, true);
         when(mBtnView.isEnabled()).thenReturn(true);
         when(mAssistant.getAllConnectedDevices()).thenReturn(ImmutableList.of(mDevice2, mDevice1));
         when(mAssistant.getAllSources(any(BluetoothDevice.class))).thenReturn(ImmutableList.of());
-        when(mBroadcast.getLatestBluetoothLeBroadcastMetadata()).thenReturn(mMetadata);
         doNothing().when(mBroadcast).startPrivateBroadcast();
         mController.onCheckedChanged(mBtnView, /* isChecked= */ true);
         shadowOf(Looper.getMainLooper()).idle();
 
         verify(mBroadcast).startPrivateBroadcast();
+        when(mBroadcast.isEnabled(null)).thenReturn(true);
+        when(mBroadcast.getLatestBluetoothLeBroadcastMetadata()).thenReturn(mMetadata);
         mController.mBroadcastCallback.onPlaybackStarted(0, 0);
         shadowOf(Looper.getMainLooper()).idle();
 
@@ -642,32 +708,33 @@
 
         verify(mAssistant).addSource(mDevice1, mMetadata, /* isGroupOp= */ false);
         assertThat(dialog.isShowing()).isFalse();
-        // Loading state dialog shows sharing state for the user chosen sink.
+        // Progress dialog shows sharing progress for the user chosen sink.
         List<Fragment> childFragments = mParentFragment.getChildFragmentManager().getFragments();
         assertThat(childFragments).comparingElementsUsing(CLAZZNAME_EQUALS).containsExactly(
-                AudioSharingLoadingStateDialogFragment.class.getName());
-        AudioSharingLoadingStateDialogFragment loadingFragment =
-                (AudioSharingLoadingStateDialogFragment) Iterables.getOnlyElement(childFragments);
+                AudioSharingProgressDialogFragment.class.getName());
+        AudioSharingProgressDialogFragment progressFragment =
+                (AudioSharingProgressDialogFragment) Iterables.getOnlyElement(childFragments);
         // TODO: use string res once finalized
         String expectedMessage = "Sharing with " + TEST_DEVICE_NAME1 + "...";
-        checkLoadingStateDialogMessage(loadingFragment, expectedMessage);
+        checkProgressDialogMessage(progressFragment, expectedMessage);
 
         childFragments.forEach(fragment -> ((DialogFragment) fragment).dismiss());
     }
 
     @Test
-    public void onPlaybackStarted_clickCancelBtnOnDialog_doNothing() {
+    public void onPlaybackStarted_oneActiveOnConnected_clickCancelBtnOnDialog_doNothing() {
         FeatureFlagUtils.setEnabled(
                 mContext, FeatureFlagUtils.SETTINGS_NEED_CONNECTED_BLE_DEVICE_FOR_BROADCAST, true);
         when(mBtnView.isEnabled()).thenReturn(true);
         when(mAssistant.getAllConnectedDevices()).thenReturn(ImmutableList.of(mDevice2, mDevice1));
         when(mAssistant.getAllSources(any(BluetoothDevice.class))).thenReturn(ImmutableList.of());
-        when(mBroadcast.getLatestBluetoothLeBroadcastMetadata()).thenReturn(mMetadata);
         doNothing().when(mBroadcast).startPrivateBroadcast();
         mController.onCheckedChanged(mBtnView, /* isChecked= */ true);
         shadowOf(Looper.getMainLooper()).idle();
 
         verify(mBroadcast).startPrivateBroadcast();
+        when(mBroadcast.isEnabled(null)).thenReturn(true);
+        when(mBroadcast.getLatestBluetoothLeBroadcastMetadata()).thenReturn(mMetadata);
         mController.mBroadcastCallback.onPlaybackStarted(0, 0);
         shadowOf(Looper.getMainLooper()).idle();
 
@@ -682,15 +749,15 @@
 
         verify(mAssistant, never()).addSource(mDevice1, mMetadata, /* isGroupOp= */ false);
         assertThat(dialog.isShowing()).isFalse();
-        // Loading state dialog shows sharing state for the auto add active sink.
+        // Progress dialog shows sharing progress for the auto add active sink.
         List<Fragment> childFragments = mParentFragment.getChildFragmentManager().getFragments();
         assertThat(childFragments).comparingElementsUsing(CLAZZNAME_EQUALS).containsExactly(
-                AudioSharingLoadingStateDialogFragment.class.getName());
-        AudioSharingLoadingStateDialogFragment loadingFragment =
-                (AudioSharingLoadingStateDialogFragment) Iterables.getOnlyElement(childFragments);
+                AudioSharingProgressDialogFragment.class.getName());
+        AudioSharingProgressDialogFragment progressFragment =
+                (AudioSharingProgressDialogFragment) Iterables.getOnlyElement(childFragments);
         // TODO: use string res once finalized
         String expectedMessage = "Sharing with " + TEST_DEVICE_NAME2 + "...";
-        checkLoadingStateDialogMessage(loadingFragment, expectedMessage);
+        checkProgressDialogMessage(progressFragment, expectedMessage);
 
         childFragments.forEach(fragment -> ((DialogFragment) fragment).dismiss());
     }
@@ -754,28 +821,63 @@
     }
 
     @Test
-    public void testAssistantCallbacks_onSourceAddFailed_logAction() {
+    public void testAssistantCallbacks_onSourceAddFailed_twoDevices_showErrorAndLogAction() {
+        FeatureFlagUtils.setEnabled(
+                mContext, FeatureFlagUtils.SETTINGS_NEED_CONNECTED_BLE_DEVICE_FOR_BROADCAST, true);
+        when(mBtnView.isEnabled()).thenReturn(true);
+        when(mAssistant.getAllConnectedDevices()).thenReturn(ImmutableList.of(mDevice2, mDevice1));
+        when(mAssistant.getAllSources(any(BluetoothDevice.class))).thenReturn(ImmutableList.of());
+        doNothing().when(mBroadcast).startPrivateBroadcast();
+        mController.onCheckedChanged(mBtnView, /* isChecked= */ true);
+        shadowOf(Looper.getMainLooper()).idle();
+
+        verify(mBroadcast).startPrivateBroadcast();
+
+        when(mBroadcast.isEnabled(null)).thenReturn(true);
+        when(mBroadcast.getLatestBluetoothLeBroadcastMetadata()).thenReturn(mMetadata);
+        mController.mBroadcastCallback.onPlaybackStarted(0, 0);
+        shadowOf(Looper.getMainLooper()).idle();
+
+        verify(mAssistant).addSource(mDevice2, mMetadata, /* isGroupOp= */ false);
+
+        AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
+        assertThat(dialog).isNotNull();
+        View btnView = dialog.findViewById(R.id.positive_btn);
+        assertThat(btnView).isNotNull();
+        btnView.performClick();
+        shadowMainLooper().idle();
+
+        verify(mAssistant).addSource(mDevice1, mMetadata, /* isGroupOp= */ false);
+        assertThat(dialog.isShowing()).isFalse();
+
         mController.mBroadcastAssistantCallback.onSourceAddFailed(
                 mDevice1, mMetadata, /* reason= */ 1);
+        shadowMainLooper().idle();
+
+        // Progress dialog shows sharing progress for the user chosen sink.
+        List<Fragment> childFragments = mParentFragment.getChildFragmentManager().getFragments();
+        assertThat(childFragments).comparingElementsUsing(CLAZZNAME_EQUALS).containsExactly(
+                AudioSharingErrorDialogFragment.class.getName());
         verify(mFeatureFactory.metricsFeatureProvider)
                 .action(
                         mContext,
                         SettingsEnums.ACTION_AUDIO_SHARING_JOIN_FAILED,
                         SettingsEnums.AUDIO_SHARING_SETTINGS);
+
+        childFragments.forEach(fragment -> ((DialogFragment) fragment).dismiss());
     }
 
     @Test
-    public void testAssistantCallbacks_onReceiveStateChanged_dismissLoadingDialog() {
-        AudioSharingLoadingStateDialogFragment.show(mParentFragment, TEST_DEVICE_NAME1);
+    public void testAssistantCallbacks_onReceiveStateChanged_dismissProgressDialog() {
+        AudioSharingProgressDialogFragment.show(mParentFragment, TEST_DEVICE_NAME1);
         shadowOf(Looper.getMainLooper()).idle();
         List<Fragment> childFragments = mParentFragment.getChildFragmentManager().getFragments();
         assertThat(childFragments).comparingElementsUsing(CLAZZNAME_EQUALS).containsExactly(
-                AudioSharingLoadingStateDialogFragment.class.getName());
+                AudioSharingProgressDialogFragment.class.getName());
 
-        BluetoothLeBroadcastReceiveState state = mock(BluetoothLeBroadcastReceiveState.class);
-        when(state.getBisSyncState()).thenReturn(ImmutableList.of(1L));
+        when(mState.getBisSyncState()).thenReturn(ImmutableList.of(1L));
         mController.mBroadcastAssistantCallback.onReceiveStateChanged(mDevice1, /* sourceId= */ 1,
-                state);
+                mState);
         shadowOf(Looper.getMainLooper()).idle();
         childFragments = mParentFragment.getChildFragmentManager().getFragments();
         assertThat(childFragments).isEmpty();
@@ -783,11 +885,9 @@
 
     @Test
     public void testAssistantCallbacks_doNothing() {
-        BluetoothLeBroadcastReceiveState state = mock(BluetoothLeBroadcastReceiveState.class);
-
         // Do nothing
         mController.mBroadcastAssistantCallback.onReceiveStateChanged(
-                mDevice1, /* sourceId= */ 1, state);
+                mDevice1, /* sourceId= */ 1, mState);
         mController.mBroadcastAssistantCallback.onSearchStarted(/* reason= */ 1);
         mController.mBroadcastAssistantCallback.onSearchStartFailed(/* reason= */ 1);
         mController.mBroadcastAssistantCallback.onSearchStopped(/* reason= */ 1);
@@ -923,13 +1023,13 @@
         List<Fragment> childFragments = parentFragment.getChildFragmentManager().getFragments();
         // Skip audio sharing dialog.
         assertThat(childFragments).comparingElementsUsing(CLAZZNAME_EQUALS).containsExactly(
-                AudioSharingLoadingStateDialogFragment.class.getName());
-        // The loading state dialog shows sharing state for the auto add second sink.
-        AudioSharingLoadingStateDialogFragment loadingFragment =
-                (AudioSharingLoadingStateDialogFragment) Iterables.getOnlyElement(childFragments);
+                AudioSharingProgressDialogFragment.class.getName());
+        // Progress dialog shows sharing progress for the auto add second sink.
+        AudioSharingProgressDialogFragment progressFragment =
+                (AudioSharingProgressDialogFragment) Iterables.getOnlyElement(childFragments);
         // TODO: use string res once finalized
         String expectedMessage = "Sharing with " + TEST_DEVICE_NAME1 + "...";
-        checkLoadingStateDialogMessage(loadingFragment, expectedMessage);
+        checkProgressDialogMessage(progressFragment, expectedMessage);
 
         childFragments.forEach(fragment -> ((DialogFragment) fragment).dismiss());
     }
@@ -944,7 +1044,7 @@
         verify(mAssistant).addSource(mDevice1, mMetadata, /* isGroupOp= */ false);
         List<Fragment> childFragments = mParentFragment.getChildFragmentManager().getFragments();
         assertThat(childFragments).comparingElementsUsing(CLAZZNAME_EQUALS).containsExactly(
-                AudioSharingLoadingStateDialogFragment.class.getName());
+                AudioSharingProgressDialogFragment.class.getName());
     }
 
     private Fragment setUpFragmentWithStartSharingIntent() {
@@ -964,12 +1064,12 @@
         return fragment;
     }
 
-    private void checkLoadingStateDialogMessage(
-            @NonNull AudioSharingLoadingStateDialogFragment fragment,
+    private void checkProgressDialogMessage(
+            @NonNull AudioSharingProgressDialogFragment fragment,
             @NonNull String expectedMessage) {
-        TextView loadingMessage = fragment.getDialog() == null ? null
+        TextView progressMessage = fragment.getDialog() == null ? null
                 : fragment.getDialog().findViewById(R.id.message);
-        assertThat(loadingMessage).isNotNull();
-        assertThat(loadingMessage.getText().toString()).isEqualTo(expectedMessage);
+        assertThat(progressMessage).isNotNull();
+        assertThat(progressMessage.getText().toString()).isEqualTo(expectedMessage);
     }
 }
diff --git a/tests/robotests/src/com/android/settings/notification/zen/ZenModeBackendTest.java b/tests/robotests/src/com/android/settings/notification/zen/ZenModeBackendTest.java
index 32bf9af..63da3c4 100644
--- a/tests/robotests/src/com/android/settings/notification/zen/ZenModeBackendTest.java
+++ b/tests/robotests/src/com/android/settings/notification/zen/ZenModeBackendTest.java
@@ -23,14 +23,18 @@
 import static org.mockito.Mockito.when;
 
 import android.app.AutomaticZenRule;
+import android.app.Flags;
 import android.app.NotificationManager;
 import android.app.NotificationManager.Policy;
 import android.content.Context;
 import android.database.Cursor;
+import android.platform.test.annotations.DisableFlags;
+import android.platform.test.flag.junit.SetFlagsRule;
 import android.provider.Settings;
 import android.service.notification.ZenModeConfig;
 
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
@@ -53,12 +57,15 @@
     private NotificationManager mNotificationManager;
 
     private static final String GENERIC_RULE_NAME = "test";
-    private static final String DEFAULT_ID_1 = ZenModeConfig.EVENTS_DEFAULT_RULE_ID;
+    private static final String DEFAULT_ID_1 = ZenModeConfig.EVENTS_OBSOLETE_RULE_ID;
     private static final String DEFAULT_ID_2 = ZenModeConfig.EVERY_NIGHT_DEFAULT_RULE_ID;
 
     private Context mContext;
     private ZenModeBackend mBackend;
 
+    @Rule
+    public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
     @Before
     public void setup() {
         MockitoAnnotations.initMocks(this);
@@ -161,6 +168,10 @@
     }
 
     @Test
+    // With MODES_UI the Events rule is not default and is sorted differently. Most likely this
+    // whole test class should be disabled since ZenModeBackend should never be used with
+    // MODES_UI. However the other tests pass, so...
+    @DisableFlags(Flags.FLAG_MODES_UI)
     public void updateState_checkRuleOrderingDescending_withDefaultRules() {
         final int NUM_RULES = 4;
 
@@ -168,8 +179,8 @@
                 true);
         Arrays.sort(rules, ZenModeBackend.RULE_COMPARATOR);
 
-        assertEquals(rules[0].getKey(), DEFAULT_ID_1);
-        assertEquals(rules[1].getKey(), DEFAULT_ID_2);
+        assertEquals(DEFAULT_ID_1, rules[0].getKey());
+        assertEquals(DEFAULT_ID_2, rules[1].getKey());
         // NON-DEFAULT RULES check ordering, most recent at the bottom/end
         for (int i = 0; i < NUM_RULES; i++) {
             assertEquals(GENERIC_RULE_NAME + (NUM_RULES - 1 - i), rules[i + 2].getKey());
diff --git a/tests/spa_unit/src/com/android/settings/network/MobileNetworkListFragmentTest.kt b/tests/spa_unit/src/com/android/settings/network/MobileNetworkListFragmentTest.kt
index 4bb5f2f..226f14f 100644
--- a/tests/spa_unit/src/com/android/settings/network/MobileNetworkListFragmentTest.kt
+++ b/tests/spa_unit/src/com/android/settings/network/MobileNetworkListFragmentTest.kt
@@ -36,7 +36,7 @@
 
     @Test
     fun isPageSearchEnabled_showMobileNetworkPage_returnTrue() {
-        mockSimRepository.stub { on { showMobileNetworkPage() } doReturn true }
+        mockSimRepository.stub { on { canEnterMobileNetworkPage() } doReturn true }
 
         val isEnabled = SearchIndexProvider { mockSimRepository }.isPageSearchEnabled(context)
 
@@ -45,7 +45,7 @@
 
     @Test
     fun isPageSearchEnabled_hideMobileNetworkPage_returnFalse() {
-        mockSimRepository.stub { on { showMobileNetworkPage() } doReturn false }
+        mockSimRepository.stub { on { canEnterMobileNetworkPage() } doReturn false }
 
         val isEnabled = SearchIndexProvider { mockSimRepository }.isPageSearchEnabled(context)
 
diff --git a/tests/spa_unit/src/com/android/settings/network/TopLevelNetworkEntryPreferenceControllerTest.kt b/tests/spa_unit/src/com/android/settings/network/TopLevelNetworkEntryPreferenceControllerTest.kt
index 27c9602..78d2941 100644
--- a/tests/spa_unit/src/com/android/settings/network/TopLevelNetworkEntryPreferenceControllerTest.kt
+++ b/tests/spa_unit/src/com/android/settings/network/TopLevelNetworkEntryPreferenceControllerTest.kt
@@ -71,7 +71,7 @@
 
     @Test
     fun getSummary_hasMobile_shouldReturnMobileSummary() {
-        mockSimRepository.stub { on { showMobileNetworkPage() } doReturn true }
+        mockSimRepository.stub { on { showMobileNetworkPageEntrance() } doReturn true }
 
         val summary = controller.summary
 
@@ -84,7 +84,7 @@
 
     @Test
     fun getSummary_noMobile_shouldReturnNoMobileSummary() {
-        mockSimRepository.stub { on { showMobileNetworkPage() } doReturn false }
+        mockSimRepository.stub { on { showMobileNetworkPageEntrance() } doReturn false }
 
         val summary = controller.summary
 
diff --git a/tests/spa_unit/src/com/android/settings/network/telephony/SimRepositoryTest.kt b/tests/spa_unit/src/com/android/settings/network/telephony/SimRepositoryTest.kt
index bbcac08..e80cc2f 100644
--- a/tests/spa_unit/src/com/android/settings/network/telephony/SimRepositoryTest.kt
+++ b/tests/spa_unit/src/com/android/settings/network/telephony/SimRepositoryTest.kt
@@ -37,50 +37,76 @@
 
     private val mockPackageManager = mock<PackageManager>()
 
-    private val context: Context = spy(ApplicationProvider.getApplicationContext()) {
-        on { userManager } doReturn mockUserManager
-        on { packageManager } doReturn mockPackageManager
-    }
+    private val context: Context =
+        spy(ApplicationProvider.getApplicationContext()) {
+            on { userManager } doReturn mockUserManager
+            on { packageManager } doReturn mockPackageManager
+        }
 
     private val repository = SimRepository(context)
 
     @Test
-    fun showMobileNetworkPage_adminUserAndHasTelephony_returnTrue() {
-        mockUserManager.stub {
-            on { isAdminUser } doReturn true
-        }
+    fun showMobileNetworkPageEntrance_adminUserAndHasTelephony_returnTrue() {
+        mockUserManager.stub { on { isAdminUser } doReturn true }
         mockPackageManager.stub {
             on { hasSystemFeature(PackageManager.FEATURE_TELEPHONY) } doReturn true
         }
 
-        val showMobileNetworkPage = repository.showMobileNetworkPage()
+        val showMobileNetworkPage = repository.showMobileNetworkPageEntrance()
 
         assertThat(showMobileNetworkPage).isTrue()
     }
 
     @Test
-    fun showMobileNetworkPage_notAdminUser_returnFalse() {
+    fun showMobileNetworkPageEntrance_notAdminUser_returnFalse() {
+        mockUserManager.stub { on { isAdminUser } doReturn false }
+        mockPackageManager.stub {
+            on { hasSystemFeature(PackageManager.FEATURE_TELEPHONY) } doReturn true
+        }
+
+        val showMobileNetworkPage = repository.showMobileNetworkPageEntrance()
+
+        assertThat(showMobileNetworkPage).isFalse()
+    }
+
+    @Test
+    fun showMobileNetworkPageEntrance_noTelephony_returnFalse() {
+        mockUserManager.stub { on { isAdminUser } doReturn true }
+        mockPackageManager.stub {
+            on { hasSystemFeature(PackageManager.FEATURE_TELEPHONY) } doReturn false
+        }
+
+        val showMobileNetworkPage = repository.showMobileNetworkPageEntrance()
+
+        assertThat(showMobileNetworkPage).isFalse()
+    }
+
+    @Test
+    fun canEnterMobileNetworkPage_allowConfigMobileNetwork_returnTrue() {
         mockUserManager.stub {
-            on { isAdminUser } doReturn false
+            on { isAdminUser } doReturn true
+            on { hasUserRestriction(UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS) } doReturn false
         }
         mockPackageManager.stub {
             on { hasSystemFeature(PackageManager.FEATURE_TELEPHONY) } doReturn true
         }
 
-        val showMobileNetworkPage = repository.showMobileNetworkPage()
+        val showMobileNetworkPage = repository.canEnterMobileNetworkPage()
 
-        assertThat(showMobileNetworkPage).isFalse()
+        assertThat(showMobileNetworkPage).isTrue()
     }
 
-    @Test fun showMobileNetworkPage_noTelephony_returnFalse() {
+    @Test
+    fun canEnterMobileNetworkPage_disallowConfigMobileNetwork_returnFalse() {
         mockUserManager.stub {
             on { isAdminUser } doReturn true
+            on { hasUserRestriction(UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS) } doReturn true
         }
         mockPackageManager.stub {
-            on { hasSystemFeature(PackageManager.FEATURE_TELEPHONY) } doReturn false
+            on { hasSystemFeature(PackageManager.FEATURE_TELEPHONY) } doReturn true
         }
 
-        val showMobileNetworkPage = repository.showMobileNetworkPage()
+        val showMobileNetworkPage = repository.canEnterMobileNetworkPage()
 
         assertThat(showMobileNetworkPage).isFalse()
     }