diff --git a/res/values/strings.xml b/res/values/strings.xml index 56d13a22209..64bcc89279d 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -7979,7 +7979,7 @@ Do Not Disturb - Priority Modes + Modes Minimize distractions and take control of your attention with modes for sleep, work, driving, and everything in between. @@ -7993,18 +7993,18 @@ Set a schedule - + Schedule based on - + Day and time - + \"9 AM - 5 PM weekdays\" - + Calendar events - + {count, plural, offset:2 =0 {} @@ -8015,7 +8015,7 @@ } - + {count, plural, =0 {} @@ -8024,40 +8024,40 @@ } - + ON - + %1$s%2$s - + Not set - + Disabled - + Create a mode - + Custom - + Turn on now - + Turn off - + Mode not found Limit interruptions - + Block interruptions and distractions - + Set up %1$s @@ -8075,7 +8075,7 @@ Delete - + Rename @@ -8096,11 +8096,11 @@ When to turn on automatically - + Event schedule - + Turn on during events for - + Where invite reply is @@ -8139,9 +8139,9 @@ Allow visual signals - + Notification filters - + More settings @@ -8859,12 +8859,12 @@ It can reply to messages and take action on buttons in notifications, including snoozing or dismissing notifications and answering calls. Change settings It can turn Do Not Disturb on or off and change related settings. - It can manage and activate Priority Modes, and change related settings. + It can manage and activate Modes, and change related settings. If you turn off notification access for %1$s, Do Not Disturb access may also be turned off. - If you turn off notification access for %1$s, Priority Modes access may also be turned off. + If you turn off notification access for %1$s, Modes access may also be turned off. Turn off Cancel @@ -9042,14 +9042,14 @@ No installed apps have requested Do Not Disturb access - - Priority Modes access + + Modes access - - Allow Priority Modes access + + Allow Modes access - No installed apps have requested Priority Modes access + No installed apps have requested Modes access You haven\'t allowed notifications from this app @@ -9392,11 +9392,11 @@ other {{app_1}, {app_2}, and # more can interrupt} } - + %s (Work) Calculating\u2026 - + +%d @@ -9501,76 +9501,76 @@ Change to always interrupt - + Edit mode - + Create a mode - + Custom mode - + Mode name - + Calendar events - + Bedtime routine - + While driving - + App settings - + Info and settings in %1$s - + Managed by %1$s - + Disable %1$s? - + This mode will never turn on when disabled - + Disable - + Enable %1$s? - + This mode may turn on automatically based on its settings - + Enable - + Set a mode that follows a regular schedule - + Set a mode to sync with calendar events and invite responses - + Design a calming sleep routine. Set alarms, dim the screen, and block notifications. - + Prioritize safety on the road for a focused and distraction-free drive - + Block distractions or interruptions from your device to gain focus - + Eliminate all distractions for a quiet environment - + Personalize device experiences and settings for different users - + Minimize interruptions by only allowing important people and apps to reach you - + Set a mode that follows a regular schedule - + Keep your device in sync with your day’s events - + Wake up feeling like 100% - + Put safety first while on the road - + Gain focus to get in the zone - + For moments when courtesy counts - + Guided usage to help you stay in good hands - + Take control of your attention @@ -10172,16 +10172,16 @@ All Do Not Disturb rules created by this app will be removed. - - Allow access to Priority Modes for %1$s? + + Allow access to Modes for %1$s? - - The app will be able to turn on/off Do Not Disturb, manage and activate Priority Modes, and make changes to related settings. + + The app will be able to turn on/off Do Not Disturb, manage and activate Modes, and make changes to related settings. - - Revoke access Priority Modes for %1$s? + + Revoke access Modes for %1$s? - + All modes created by this app will be removed. diff --git a/src/com/android/settings/bluetooth/AvailableMediaBluetoothDeviceUpdater.java b/src/com/android/settings/bluetooth/AvailableMediaBluetoothDeviceUpdater.java index bb56c509373..22a39c8686a 100644 --- a/src/com/android/settings/bluetooth/AvailableMediaBluetoothDeviceUpdater.java +++ b/src/com/android/settings/bluetooth/AvailableMediaBluetoothDeviceUpdater.java @@ -26,6 +26,7 @@ import com.android.settings.connecteddevice.DevicePreferenceCallback; import com.android.settingslib.bluetooth.BluetoothUtils; import com.android.settingslib.bluetooth.CachedBluetoothDevice; import com.android.settingslib.bluetooth.LocalBluetoothManager; +import com.android.settingslib.utils.ThreadUtils; /** Controller to maintain available media Bluetooth devices */ public class AvailableMediaBluetoothDeviceUpdater extends BluetoothDeviceUpdater @@ -135,7 +136,9 @@ public class AvailableMediaBluetoothDeviceUpdater extends BluetoothDeviceUpdater @Override public boolean onPreferenceClick(Preference preference) { mMetricsFeatureProvider.logClickedPreference(preference, mMetricsCategory); - mDevicePreferenceCallback.onDeviceClick(preference); + var unused = + ThreadUtils.postOnBackgroundThread( + () -> mDevicePreferenceCallback.onDeviceClick(preference)); return true; } diff --git a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDevicePreferenceController.java b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDevicePreferenceController.java index d6ad4bc3c7b..8b4c7f267bb 100644 --- a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDevicePreferenceController.java +++ b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDevicePreferenceController.java @@ -59,6 +59,7 @@ import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant; import com.android.settingslib.bluetooth.LocalBluetoothManager; import com.android.settingslib.bluetooth.LocalBluetoothProfileManager; import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; +import com.android.settingslib.utils.ThreadUtils; import java.util.Locale; import java.util.concurrent.Executor; @@ -287,7 +288,8 @@ public class AudioSharingDevicePreferenceController extends BasePreferenceContro if (AudioSharingUtils.isAudioSharingProfileReady(mProfileManager)) { if (!mIntentHandled.get()) { Log.d(TAG, "displayPreference: profile ready, handleDeviceClickFromIntent"); - handleDeviceClickFromIntent(); + var unused = + ThreadUtils.postOnBackgroundThread(() -> handleDeviceClickFromIntent()); mIntentHandled.set(true); } } diff --git a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDialogHandler.java b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDialogHandler.java index 6f55a137ba2..396144ab16c 100644 --- a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDialogHandler.java +++ b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDialogHandler.java @@ -25,6 +25,7 @@ import android.bluetooth.BluetoothLeBroadcast; import android.bluetooth.BluetoothLeBroadcastMetadata; import android.bluetooth.BluetoothLeBroadcastReceiveState; import android.content.Context; +import android.media.AudioManager; import android.os.Bundle; import android.util.Log; import android.util.Pair; @@ -64,6 +65,7 @@ public class AudioSharingDialogHandler { @Nullable private final CachedBluetoothDeviceManager mDeviceManager; @Nullable private final LocalBluetoothLeBroadcast mBroadcast; @Nullable private final LocalBluetoothLeBroadcastAssistant mAssistant; + @Nullable private final AudioManager mAudioManager; private final MetricsFeatureProvider mMetricsFeatureProvider; private boolean mIsStoppingBroadcast = false; @@ -157,6 +159,7 @@ public class AudioSharingDialogHandler { mLocalBtManager != null ? mLocalBtManager.getProfileManager().getLeAudioBroadcastAssistantProfile() : null; + mAudioManager = context.getSystemService(AudioManager.class); mMetricsFeatureProvider = FeatureFactory.getFeatureFactory().getMetricsFeatureProvider(); } @@ -178,6 +181,22 @@ public class AudioSharingDialogHandler { public void handleDeviceConnected( @NonNull CachedBluetoothDevice cachedDevice, boolean userTriggered) { String anonymizedAddress = cachedDevice.getDevice().getAnonymizedAddress(); + if (mAudioManager != null) { + int audioMode = mAudioManager.getMode(); + if (audioMode == AudioManager.MODE_RINGTONE + || audioMode == AudioManager.MODE_IN_CALL + || audioMode == AudioManager.MODE_IN_COMMUNICATION) { + Log.d(TAG, "Skip handleDeviceConnected, audio mode = " + audioMode); + // TODO: add metric for this case + if (userTriggered) { + // If this method is called with user triggered, e.g. manual click on the + // "Connected devices" page, we need call setActive for the device, since user + // intend to switch active device for the call. + cachedDevice.setActive(); + } + return; + } + } boolean isBroadcasting = isBroadcasting(); boolean isLeAudioSupported = AudioSharingUtils.isLeAudioSupported(cachedDevice); if (!isLeAudioSupported) { diff --git a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingSwitchBarController.java b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingSwitchBarController.java index 8e091885213..c0d67ccbb7a 100644 --- a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingSwitchBarController.java +++ b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingSwitchBarController.java @@ -201,6 +201,19 @@ public class AudioSharingSwitchBarController extends BasePreferenceController + reason + ", broadcastId = " + broadcastId); + if (mAssistant == null + || mAssistant.getAllConnectedDevices().stream() + .anyMatch( + device -> BluetoothUtils + .hasActiveLocalBroadcastSourceForBtDevice( + device, mBtManager))) { + Log.d( + TAG, + "Skip handleOnBroadcastReady: null assistant or " + + "sink has active local source."); + cleanUp(); + return; + } handleOnBroadcastReady(); } @@ -554,8 +567,7 @@ public class AudioSharingSwitchBarController extends BasePreferenceController mGroupedConnectedDevices.getOrDefault( mDeviceItemsForSharing.get(0).getGroupId(), ImmutableList.of()), mBtManager); - mGroupedConnectedDevices.clear(); - mDeviceItemsForSharing.clear(); + cleanUp(); // TODO: Add metric for auto add by intent return; } @@ -565,8 +577,7 @@ public class AudioSharingSwitchBarController extends BasePreferenceController StartIntentHandleStage.HANDLED.ordinal()); if (mFragment == null) { Log.d(TAG, "handleOnBroadcastReady: dialog fail to show due to null fragment."); - mGroupedConnectedDevices.clear(); - mDeviceItemsForSharing.clear(); + cleanUp(); return; } showDialog(eventData); @@ -581,14 +592,12 @@ public class AudioSharingSwitchBarController extends BasePreferenceController mGroupedConnectedDevices.getOrDefault( item.getGroupId(), ImmutableList.of()), mBtManager); - mGroupedConnectedDevices.clear(); - mDeviceItemsForSharing.clear(); + cleanUp(); } @Override public void onCancelClick() { - mGroupedConnectedDevices.clear(); - mDeviceItemsForSharing.clear(); + cleanUp(); } }; AudioSharingUtils.postOnMainThread( @@ -657,6 +666,11 @@ public class AudioSharingSwitchBarController extends BasePreferenceController }); } + private void cleanUp() { + mGroupedConnectedDevices.clear(); + mDeviceItemsForSharing.clear(); + } + private enum StartIntentHandleStage { TO_HANDLE, HANDLE_AUTO_ADD, diff --git a/src/com/android/settings/network/apn/ApnRepository.kt b/src/com/android/settings/network/apn/ApnRepository.kt index 843371501b7..7ed0c865127 100644 --- a/src/com/android/settings/network/apn/ApnRepository.kt +++ b/src/com/android/settings/network/apn/ApnRepository.kt @@ -21,10 +21,10 @@ import android.content.Context import android.database.Cursor import android.net.Uri import android.provider.Telephony -import android.telephony.SubscriptionManager import android.telephony.TelephonyManager import android.util.Log import com.android.settings.R +import com.android.settings.network.telephony.telephonyManager import com.android.settingslib.utils.ThreadUtils import java.util.Locale @@ -178,12 +178,11 @@ fun isItemExist(apnData: ApnData, context: Context): String? { } fun Context.getApnIdMap(subId: Int): Map { - val subInfo = getSystemService(SubscriptionManager::class.java)!! - .getActiveSubscriptionInfo(subId) - val carrierId = subInfo.carrierId + val telephonyManager = telephonyManager(subId) + val carrierId = telephonyManager.simSpecificCarrierId return if (carrierId != TelephonyManager.UNKNOWN_CARRIER_ID) { mapOf(Telephony.Carriers.CARRIER_ID to carrierId) } else { - mapOf(Telephony.Carriers.NUMERIC to subInfo.mccString + subInfo.mncString) + mapOf(Telephony.Carriers.NUMERIC to telephonyManager.simOperator) }.also { Log.d(TAG, "[$subId] New APN item with id: $it") } } diff --git a/src/com/android/settings/network/telephony/MobileNetworkSettings.java b/src/com/android/settings/network/telephony/MobileNetworkSettings.java index a5cdb954664..91874c4f5ac 100644 --- a/src/com/android/settings/network/telephony/MobileNetworkSettings.java +++ b/src/com/android/settings/network/telephony/MobileNetworkSettings.java @@ -41,6 +41,7 @@ import android.view.View; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; +import androidx.lifecycle.LifecycleOwner; import androidx.lifecycle.ViewModelProvider; import androidx.preference.Preference; @@ -66,6 +67,8 @@ import com.android.settingslib.mobile.dataservice.SubscriptionInfoEntity; import com.android.settingslib.search.SearchIndexable; import com.android.settingslib.utils.ThreadUtils; +import kotlin.Unit; + import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -359,6 +362,16 @@ public class MobileNetworkSettings extends AbstractMobileNetworkSettings impleme public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); collectAirplaneModeAndFinishIfOn(this); + + LifecycleOwner viewLifecycleOwner = getViewLifecycleOwner(); + new SubscriptionRepository(requireContext()) + .collectSubscriptionVisible(mSubId, viewLifecycleOwner, (isVisible) -> { + if (!isVisible) { + Log.d(LOG_TAG, "Due to subscription not visible, closes page"); + finishFragment(); + } + return Unit.INSTANCE; + }); } @Override @@ -532,11 +545,6 @@ public class MobileNetworkSettings extends AbstractMobileNetworkSettings impleme Log.d(LOG_TAG, "Set subInfo to default subInfo."); } } - if (mSubscriptionInfoEntity == null && getActivity() != null) { - // If the current subId is not existed, finish it. - finishFragment(); - return; - } onSubscriptionDetailChanged(); } } diff --git a/src/com/android/settings/network/telephony/SubscriptionRepository.kt b/src/com/android/settings/network/telephony/SubscriptionRepository.kt index cc8c8b47b2d..26ea9b3fc42 100644 --- a/src/com/android/settings/network/telephony/SubscriptionRepository.kt +++ b/src/com/android/settings/network/telephony/SubscriptionRepository.kt @@ -50,6 +50,31 @@ class SubscriptionRepository(private val context: Context) { fun getSelectableSubscriptionInfoList(): List = context.getSelectableSubscriptionInfoList() + /** Flow of whether the subscription visible for the given [subId]. */ + fun isSubscriptionVisibleFlow(subId: Int): Flow { + return subscriptionsChangedFlow() + .map { + val subInfo = + subscriptionManager.availableSubscriptionInfoList?.firstOrNull { subInfo -> + subInfo.subscriptionId == subId + } + subInfo != null && + SubscriptionUtil.isSubscriptionVisible(subscriptionManager, context, subInfo) + } + .conflate() + .onEach { Log.d(TAG, "[$subId] isSubscriptionVisibleFlow: $it") } + .flowOn(Dispatchers.Default) + } + + /** TODO: Move this to UI layer, when UI layer migrated to Kotlin. */ + fun collectSubscriptionVisible( + subId: Int, + lifecycleOwner: LifecycleOwner, + action: (Boolean) -> Unit, + ) { + isSubscriptionVisibleFlow(subId).collectLatestWithLifecycle(lifecycleOwner, action = action) + } + /** Flow of whether the subscription enabled for the given [subId]. */ fun isSubscriptionEnabledFlow(subId: Int): Flow { if (!SubscriptionManager.isValidSubscriptionId(subId)) return flowOf(false) diff --git a/src/com/android/settings/network/telephony/WifiCallingPreferenceController.kt b/src/com/android/settings/network/telephony/WifiCallingPreferenceController.kt index e04763a88c1..9b68970d750 100644 --- a/src/com/android/settings/network/telephony/WifiCallingPreferenceController.kt +++ b/src/com/android/settings/network/telephony/WifiCallingPreferenceController.kt @@ -81,6 +81,12 @@ open class WifiCallingPreferenceController @JvmOverloads constructor( } override fun onViewCreated(viewLifecycleOwner: LifecycleOwner) { + if (!SubscriptionManager.isValidSubscriptionId(subId)) { + // Sub id could invalid, if this page is opened from external action and no sim is + // active. + // Ignore this case, since this page will be finished soon. + return + } wifiCallingRepositoryFactory(subId).wifiCallingReadyFlow() .collectLatestWithLifecycle(viewLifecycleOwner) { isReady -> preference.isVisible = isReady diff --git a/src/com/android/settings/notification/modes/ZenModeScheduleChooserDialog.java b/src/com/android/settings/notification/modes/ZenModeScheduleChooserDialog.java index d129aad6ad6..370199a6292 100644 --- a/src/com/android/settings/notification/modes/ZenModeScheduleChooserDialog.java +++ b/src/com/android/settings/notification/modes/ZenModeScheduleChooserDialog.java @@ -81,6 +81,17 @@ public class ZenModeScheduleChooserDialog extends InstrumentedDialogFragment { dialog.show(parent.getParentFragmentManager(), TAG); } + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + if (mOptionListener == null) { + // Probably the dialog fragment was recreated after its activity being destroyed. + // It's pointless to re-show the dialog if we can't do anything when its options are + // selected, so we don't. + dismiss(); + } + } + @NonNull @Override public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) { diff --git a/src/com/android/settings/notification/modes/ZenModesListAddModeTypeChooserDialog.java b/src/com/android/settings/notification/modes/ZenModesListAddModeTypeChooserDialog.java index e7905a8f936..0bf9c5bd472 100644 --- a/src/com/android/settings/notification/modes/ZenModesListAddModeTypeChooserDialog.java +++ b/src/com/android/settings/notification/modes/ZenModesListAddModeTypeChooserDialog.java @@ -70,6 +70,17 @@ public class ZenModesListAddModeTypeChooserDialog extends InstrumentedDialogFrag dialog.show(parent.getParentFragmentManager(), TAG); } + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + if (mChooseModeTypeListener == null) { + // Probably the dialog fragment was recreated after its activity being destroyed. + // It's pointless to re-show the dialog if we can't do anything when its options are + // selected, so we don't. + dismiss(); + } + } + @NonNull @Override public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) { diff --git a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDialogHandlerTest.java b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDialogHandlerTest.java index 4933c430c15..ad6dd7f0754 100644 --- a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDialogHandlerTest.java +++ b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDialogHandlerTest.java @@ -39,6 +39,7 @@ import android.bluetooth.BluetoothLeBroadcastReceiveState; import android.bluetooth.BluetoothStatusCodes; import android.content.Context; import android.content.Intent; +import android.media.AudioManager; import android.os.Bundle; import android.os.Looper; import android.platform.test.flag.junit.SetFlagsRule; @@ -113,6 +114,7 @@ public class AudioSharingDialogHandlerTest { @Mock private CachedBluetoothDeviceManager mCacheManager; @Mock private LocalBluetoothLeBroadcast mBroadcast; @Mock private LocalBluetoothLeBroadcastAssistant mAssistant; + @Mock private AudioManager mAudioManager; @Mock private CachedBluetoothDevice mCachedDevice1; @Mock private CachedBluetoothDevice mCachedDevice2; @Mock private CachedBluetoothDevice mCachedDevice3; @@ -152,6 +154,8 @@ public class AudioSharingDialogHandlerTest { when(mLocalBtManager.getProfileManager()).thenReturn(mLocalBtProfileManager); when(mLocalBtProfileManager.getLeAudioBroadcastProfile()).thenReturn(mBroadcast); when(mLocalBtProfileManager.getLeAudioBroadcastAssistantProfile()).thenReturn(mAssistant); + when(mContext.getSystemService(AudioManager.class)).thenReturn(mAudioManager); + when(mAudioManager.getMode()).thenReturn(AudioManager.MODE_NORMAL); List bisSyncState = new ArrayList<>(); bisSyncState.add(1L); when(mState.getBisSyncState()).thenReturn(bisSyncState); @@ -187,6 +191,18 @@ public class AudioSharingDialogHandlerTest { ShadowBluetoothUtils.reset(); } + @Test + public void handleUserTriggeredDeviceConnected_inCall_setActive() { + when(mAudioManager.getMode()).thenReturn(AudioManager.MODE_IN_CALL); + setUpBroadcast(true); + ImmutableList deviceList = ImmutableList.of(mDevice1); + when(mAssistant.getAllConnectedDevices()).thenReturn(deviceList); + when(mAssistant.getAllSources(any())).thenReturn(ImmutableList.of()); + mHandler.handleDeviceConnected(mCachedDevice1, /* userTriggered= */ true); + shadowOf(Looper.getMainLooper()).idle(); + verify(mCachedDevice1).setActive(); + } + @Test public void handleUserTriggeredNonLeaDeviceConnected_noSharing_setActive() { setUpBroadcast(false); @@ -403,6 +419,18 @@ public class AudioSharingDialogHandlerTest { verify(mAssistant).addSource(mDevice1, mMetadata, /* isGroupOp= */ false); } + @Test + public void handleDeviceConnected_inCall_doNothing() { + when(mAudioManager.getMode()).thenReturn(AudioManager.MODE_IN_CALL); + setUpBroadcast(true); + when(mAssistant.getAllConnectedDevices()).thenReturn(ImmutableList.of()); + mHandler.handleDeviceConnected(mCachedDevice2, /* userTriggered= */ false); + shadowOf(Looper.getMainLooper()).idle(); + verify(mCachedDevice2, never()).setActive(); + List childFragments = mParentFragment.getChildFragmentManager().getFragments(); + assertThat(childFragments).isEmpty(); + } + @Test public void handleNonLeaDeviceConnected_noSharing_doNothing() { setUpBroadcast(false); 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 558bc10bace..5073119d197 100644 --- a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingSwitchBarControllerTest.java +++ b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingSwitchBarControllerTest.java @@ -443,6 +443,7 @@ public class AudioSharingSwitchBarControllerTest { 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 = @@ -468,12 +469,38 @@ public class AudioSharingSwitchBarControllerTest { assertThat(childFragments).isEmpty(); } + @Test + public void onPlaybackStarted_hasLocalSource_noDialog() { + 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)); + BluetoothLeBroadcastReceiveState state = mock(BluetoothLeBroadcastReceiveState.class); + when(state.getBroadcastId()).thenReturn(1); + when(mBroadcast.getLatestBroadcastId()).thenReturn(1); + when(mAssistant.getAllSources(mDevice2)).thenReturn(ImmutableList.of(state)); + when(mBroadcast.getLatestBluetoothLeBroadcastMetadata()).thenReturn(mMetadata); + doNothing().when(mBroadcast).startPrivateBroadcast(); + mController.onCheckedChanged(mBtnView, /* isChecked= */ true); + verify(mBroadcast).startPrivateBroadcast(); + mController.mBroadcastCallback.onPlaybackStarted(0, 0); + shadowOf(Looper.getMainLooper()).idle(); + + verify(mAssistant, never()).addSource(any(), any(), anyBoolean()); + verify(mFeatureFactory.metricsFeatureProvider, never()) + .action(any(Context.class), eq(SettingsEnums.ACTION_AUTO_JOIN_AUDIO_SHARING)); + + List childFragments = mParentFragment.getChildFragmentManager().getFragments(); + assertThat(childFragments).isEmpty(); + } + @Test public void onPlaybackStarted_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); when(mBroadcast.getLatestBluetoothLeBroadcastMetadata()).thenReturn(mMetadata); @@ -519,6 +546,7 @@ public class AudioSharingSwitchBarControllerTest { 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); @@ -545,6 +573,7 @@ public class AudioSharingSwitchBarControllerTest { 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); diff --git a/tests/spa_unit/src/com/android/settings/network/apn/ApnRepositoryTest.kt b/tests/spa_unit/src/com/android/settings/network/apn/ApnRepositoryTest.kt index 415531882a2..d2f16d75bbb 100644 --- a/tests/spa_unit/src/com/android/settings/network/apn/ApnRepositoryTest.kt +++ b/tests/spa_unit/src/com/android/settings/network/apn/ApnRepositoryTest.kt @@ -21,8 +21,6 @@ import android.content.Context import android.database.MatrixCursor import android.net.Uri import android.provider.Telephony -import android.telephony.SubscriptionInfo -import android.telephony.SubscriptionManager import android.telephony.TelephonyManager import androidx.test.core.app.ApplicationProvider import androidx.test.ext.junit.runners.AndroidJUnit4 @@ -40,19 +38,15 @@ class ApnRepositoryTest { private val contentResolver = mock() - private val mockSubscriptionInfo = mock { - on { mccString } doReturn MCC - on { mncString } doReturn MNC - } + private val mockTelephonyManager = + mock { on { createForSubscriptionId(SUB_ID) } doReturn mock } - private val mockSubscriptionManager = mock { - on { getActiveSubscriptionInfo(SUB_ID) } doReturn mockSubscriptionInfo - } + private val context: Context = + spy(ApplicationProvider.getApplicationContext()) { + on { contentResolver } doReturn contentResolver + on { getSystemService(TelephonyManager::class.java) } doReturn mockTelephonyManager + } - private val context: Context = spy(ApplicationProvider.getApplicationContext()) { - on { contentResolver } doReturn contentResolver - on { getSystemService(SubscriptionManager::class.java) } doReturn mockSubscriptionManager - } private val uri = mock {} @Test @@ -91,9 +85,7 @@ class ApnRepositoryTest { @Test fun getApnIdMap_knownCarrierId() { - mockSubscriptionInfo.stub { - on { carrierId } doReturn CARRIER_ID - } + mockTelephonyManager.stub { on { simSpecificCarrierId } doReturn CARRIER_ID } val idMap = context.getApnIdMap(SUB_ID) @@ -102,19 +94,19 @@ class ApnRepositoryTest { @Test fun getApnIdMap_unknownCarrierId() { - mockSubscriptionInfo.stub { - on { carrierId } doReturn TelephonyManager.UNKNOWN_CARRIER_ID + mockTelephonyManager.stub { + on { simSpecificCarrierId } doReturn TelephonyManager.UNKNOWN_CARRIER_ID + on { simOperator } doReturn SIM_OPERATOR } val idMap = context.getApnIdMap(SUB_ID) - assertThat(idMap).containsExactly(Telephony.Carriers.NUMERIC, MCC + MNC) + assertThat(idMap).containsExactly(Telephony.Carriers.NUMERIC, SIM_OPERATOR) } private companion object { const val SUB_ID = 2 const val CARRIER_ID = 10 - const val MCC = "310" - const val MNC = "101" + const val SIM_OPERATOR = "310101" } } diff --git a/tests/spa_unit/src/com/android/settings/network/telephony/SubscriptionRepositoryTest.kt b/tests/spa_unit/src/com/android/settings/network/telephony/SubscriptionRepositoryTest.kt index f75c14a6d37..5dbc5340745 100644 --- a/tests/spa_unit/src/com/android/settings/network/telephony/SubscriptionRepositoryTest.kt +++ b/tests/spa_unit/src/com/android/settings/network/telephony/SubscriptionRepositoryTest.kt @@ -189,6 +189,32 @@ class SubscriptionRepositoryTest { assertThat(subInfos.map { it.subscriptionId }).containsExactly(SUB_ID_3_NOT_IN_SLOT) } + @Test + fun isSubscriptionVisibleFlow_available_returnTrue() = runBlocking { + mockSubscriptionManager.stub { + on { getAvailableSubscriptionInfoList() } doReturn + listOf(SubscriptionInfo.Builder().apply { setId(SUB_ID_IN_SLOT_0) }.build()) + } + + val isVisible = + repository.isSubscriptionVisibleFlow(SUB_ID_IN_SLOT_0).firstWithTimeoutOrNull() + + assertThat(isVisible).isTrue() + } + + @Test + fun isSubscriptionVisibleFlow_unavailable_returnFalse() = runBlocking { + mockSubscriptionManager.stub { + on { getAvailableSubscriptionInfoList() } doReturn + listOf(SubscriptionInfo.Builder().apply { setId(SUB_ID_IN_SLOT_0) }.build()) + } + + val isVisible = + repository.isSubscriptionVisibleFlow(SUB_ID_IN_SLOT_1).firstWithTimeoutOrNull() + + assertThat(isVisible).isFalse() + } + @Test fun phoneNumberFlow() = runBlocking { mockSubscriptionManager.stub {