diff --git a/res/layout/dialog_custom_body_audio_sharing.xml b/res/layout/dialog_custom_body_audio_sharing.xml index 528bfbb43a7..ba7f6431baa 100644 --- a/res/layout/dialog_custom_body_audio_sharing.xml +++ b/res/layout/dialog_custom_body_audio_sharing.xml @@ -44,6 +44,7 @@ android:layout_height="wrap_content" android:layout_gravity="center" android:contentDescription="@null" + android:paddingBottom="24dp" android:visibility="gone" /> + + mAllOfCachedDevices; + private Set mCachedDeviceGroup; private Map> mProfileDeviceMap = new HashMap>(); private boolean mIsLeContactSharingEnabled = false; @@ -105,7 +105,7 @@ public class BluetoothDetailsProfilesController extends BluetoothDetailsControll mManager = manager; mProfileManager = mManager.getProfileManager(); mCachedDevice = device; - mAllOfCachedDevices = Utils.getAllOfCachedBluetoothDevices(mManager, mCachedDevice); + mCachedDeviceGroup = Utils.findAllCachedBluetoothDevicesByGroupId(mManager, mCachedDevice); } @Override @@ -310,10 +310,10 @@ public class BluetoothDetailsProfilesController extends BluetoothDetailsControll private List getProfiles() { List result = new ArrayList<>(); mProfileDeviceMap.clear(); - if (mAllOfCachedDevices == null || mAllOfCachedDevices.isEmpty()) { + if (mCachedDeviceGroup == null || mCachedDeviceGroup.isEmpty()) { return result; } - for (CachedBluetoothDevice cachedItem : mAllOfCachedDevices) { + for (CachedBluetoothDevice cachedItem : mCachedDeviceGroup) { List tmpResult = cachedItem.getUiAccessibleProfiles(); for (LocalBluetoothProfile profile : tmpResult) { if (mProfileDeviceMap.containsKey(profile.toString())) { @@ -514,7 +514,7 @@ public class BluetoothDetailsProfilesController extends BluetoothDetailsControll @Override public void onPause() { - for (CachedBluetoothDevice item : mAllOfCachedDevices) { + for (CachedBluetoothDevice item : mCachedDeviceGroup) { item.unregisterCallback(this); } mProfileManager.removeServiceListener(this); @@ -523,7 +523,7 @@ public class BluetoothDetailsProfilesController extends BluetoothDetailsControll @Override public void onResume() { updateLeAudioConfig(); - for (CachedBluetoothDevice item : mAllOfCachedDevices) { + for (CachedBluetoothDevice item : mCachedDeviceGroup) { item.registerCallback(this); } mProfileManager.addServiceListener(this); @@ -545,11 +545,11 @@ public class BluetoothDetailsProfilesController extends BluetoothDetailsControll @Override public void onDeviceAttributesChanged() { - for (CachedBluetoothDevice item : mAllOfCachedDevices) { + for (CachedBluetoothDevice item : mCachedDeviceGroup) { item.unregisterCallback(this); } - mAllOfCachedDevices = Utils.getAllOfCachedBluetoothDevices(mManager, mCachedDevice); - for (CachedBluetoothDevice item : mAllOfCachedDevices) { + mCachedDeviceGroup = Utils.findAllCachedBluetoothDevicesByGroupId(mManager, mCachedDevice); + for (CachedBluetoothDevice item : mCachedDeviceGroup) { item.registerCallback(this); } diff --git a/src/com/android/settings/bluetooth/BluetoothDevicePreference.java b/src/com/android/settings/bluetooth/BluetoothDevicePreference.java index ac0c63bc6de..209c900927e 100644 --- a/src/com/android/settings/bluetooth/BluetoothDevicePreference.java +++ b/src/com/android/settings/bluetooth/BluetoothDevicePreference.java @@ -46,6 +46,7 @@ import com.android.settings.R; import com.android.settings.overlay.FeatureFactory; import com.android.settings.widget.GearPreference; import com.android.settingslib.bluetooth.CachedBluetoothDevice; +import com.android.settingslib.bluetooth.LocalBluetoothManager; import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; import com.android.settingslib.utils.ThreadUtils; @@ -55,6 +56,7 @@ import java.util.HashSet; import java.util.Set; import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Collectors; /** * BluetoothDevicePreference is the preference type used to display each remote @@ -76,7 +78,10 @@ public final class BluetoothDevicePreference extends GearPreference { } private final CachedBluetoothDevice mCachedDevice; + private Set mCachedDeviceGroup; + private final UserManager mUserManager; + private final LocalBluetoothManager mLocalBtManager; private Set mBluetoothDevices; @VisibleForTesting @@ -113,6 +118,21 @@ public final class BluetoothDevicePreference extends GearPreference { @Override public void onDeviceAttributesChanged() { onPreferenceAttributesChanged(); + Set newCachedDeviceGroup = new HashSet<>( + Utils.findAllCachedBluetoothDevicesByGroupId(mLocalBtManager, mCachedDevice)); + if (!mCachedDeviceGroup.equals(newCachedDeviceGroup)) { + for (CachedBluetoothDevice cachedBluetoothDevice : mCachedDeviceGroup) { + cachedBluetoothDevice.unregisterCallback(this); + } + unregisterMetadataChangedListener(); + + mCachedDeviceGroup = newCachedDeviceGroup; + + for (CachedBluetoothDevice cachedBluetoothDevice : mCachedDeviceGroup) { + cachedBluetoothDevice.registerCallback(getContext().getMainExecutor(), this); + } + registerMetadataChangedListener(); + } } } @@ -121,6 +141,7 @@ public final class BluetoothDevicePreference extends GearPreference { super(context, null); mResources = getContext().getResources(); mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE); + mLocalBtManager = Utils.getLocalBluetoothManager(context); mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); mShowDevicesWithoutNames = showDeviceWithoutNames; @@ -131,6 +152,8 @@ public final class BluetoothDevicePreference extends GearPreference { } mCachedDevice = cachedDevice; + mCachedDeviceGroup = new HashSet<>( + Utils.findAllCachedBluetoothDevicesByGroupId(mLocalBtManager, mCachedDevice)); mCallback = new BluetoothDevicePreferenceCallback(); mId = sNextId.getAndIncrement(); mType = type; @@ -164,7 +187,9 @@ public final class BluetoothDevicePreference extends GearPreference { protected void onPrepareForRemoval() { super.onPrepareForRemoval(); if (!mIsCallbackRemoved) { - mCachedDevice.unregisterCallback(mCallback); + for (CachedBluetoothDevice cachedBluetoothDevice : mCachedDeviceGroup) { + cachedBluetoothDevice.unregisterCallback(mCallback); + } unregisterMetadataChangedListener(); mIsCallbackRemoved = true; } @@ -178,7 +203,9 @@ public final class BluetoothDevicePreference extends GearPreference { public void onAttached() { super.onAttached(); if (mIsCallbackRemoved) { - mCachedDevice.registerCallback(mCallback); + for (CachedBluetoothDevice cachedBluetoothDevice : mCachedDeviceGroup) { + cachedBluetoothDevice.registerCallback(getContext().getMainExecutor(), mCallback); + } registerMetadataChangedListener(); mIsCallbackRemoved = false; } @@ -189,7 +216,9 @@ public final class BluetoothDevicePreference extends GearPreference { public void onDetached() { super.onDetached(); if (!mIsCallbackRemoved) { - mCachedDevice.unregisterCallback(mCallback); + for (CachedBluetoothDevice cachedBluetoothDevice : mCachedDeviceGroup) { + cachedBluetoothDevice.unregisterCallback(mCallback); + } unregisterMetadataChangedListener(); mIsCallbackRemoved = true; } @@ -200,16 +229,11 @@ public final class BluetoothDevicePreference extends GearPreference { Log.d(TAG, "No mBluetoothAdapter"); return; } - if (mBluetoothDevices == null) { - mBluetoothDevices = new HashSet<>(); - } - mBluetoothDevices.clear(); - if (mCachedDevice.getDevice() != null) { - mBluetoothDevices.add(mCachedDevice.getDevice()); - } - for (CachedBluetoothDevice cbd : mCachedDevice.getMemberDevice()) { - mBluetoothDevices.add(cbd.getDevice()); - } + + mBluetoothDevices = mCachedDeviceGroup.stream() + .map(CachedBluetoothDevice::getDevice) + .collect(Collectors.toCollection(HashSet::new)); + if (mBluetoothDevices.isEmpty()) { Log.d(TAG, "No BT device to register."); return; diff --git a/src/com/android/settings/bluetooth/LeAudioBluetoothDetailsHeaderController.java b/src/com/android/settings/bluetooth/LeAudioBluetoothDetailsHeaderController.java index 4be4d63d7c3..a5e9cde2d17 100644 --- a/src/com/android/settings/bluetooth/LeAudioBluetoothDetailsHeaderController.java +++ b/src/com/android/settings/bluetooth/LeAudioBluetoothDetailsHeaderController.java @@ -47,7 +47,7 @@ import com.android.settingslib.core.lifecycle.events.OnStart; import com.android.settingslib.core.lifecycle.events.OnStop; import com.android.settingslib.widget.LayoutPreference; -import java.util.List; +import java.util.Set; /** * This class adds a header with device name and status (connected/disconnected, etc.). @@ -90,7 +90,7 @@ public class LeAudioBluetoothDetailsHeaderController extends BasePreferenceContr LayoutPreference mLayoutPreference; LocalBluetoothManager mManager; private CachedBluetoothDevice mCachedDevice; - private List mAllOfCachedDevices; + private Set mCachedDeviceGroup; @VisibleForTesting Handler mHandler = new Handler(Looper.getMainLooper()); @VisibleForTesting @@ -128,7 +128,7 @@ public class LeAudioBluetoothDetailsHeaderController extends BasePreferenceContr return; } mIsRegisterCallback = true; - for (CachedBluetoothDevice item : mAllOfCachedDevices) { + for (CachedBluetoothDevice item : mCachedDeviceGroup) { item.registerCallback(this); } refresh(); @@ -139,7 +139,7 @@ public class LeAudioBluetoothDetailsHeaderController extends BasePreferenceContr if (!mIsRegisterCallback) { return; } - for (CachedBluetoothDevice item : mAllOfCachedDevices) { + for (CachedBluetoothDevice item : mCachedDeviceGroup) { item.unregisterCallback(this); } @@ -155,7 +155,7 @@ public class LeAudioBluetoothDetailsHeaderController extends BasePreferenceContr mCachedDevice = cachedBluetoothDevice; mManager = bluetoothManager; mProfileManager = bluetoothManager.getProfileManager(); - mAllOfCachedDevices = Utils.getAllOfCachedBluetoothDevices(mManager, mCachedDevice); + mCachedDeviceGroup = Utils.findAllCachedBluetoothDevicesByGroupId(mManager, mCachedDevice); } @VisibleForTesting @@ -230,7 +230,7 @@ public class LeAudioBluetoothDetailsHeaderController extends BasePreferenceContr // Init the battery layouts. hideAllOfBatteryLayouts(); LeAudioProfile leAudioProfile = mProfileManager.getLeAudioProfile(); - if (mAllOfCachedDevices.isEmpty()) { + if (mCachedDeviceGroup.isEmpty()) { Log.e(TAG, "There is no LeAudioProfile."); return; } @@ -244,7 +244,7 @@ public class LeAudioBluetoothDetailsHeaderController extends BasePreferenceContr return; } - for (CachedBluetoothDevice cachedDevice : mAllOfCachedDevices) { + for (CachedBluetoothDevice cachedDevice : mCachedDeviceGroup) { int deviceId = leAudioProfile.getAudioLocation(cachedDevice.getDevice()); Log.d(TAG, "LeAudioDevices:" + cachedDevice.getDevice().getAnonymizedAddress() + ", deviceId:" + deviceId); @@ -300,15 +300,15 @@ public class LeAudioBluetoothDetailsHeaderController extends BasePreferenceContr @Override public void onDeviceAttributesChanged() { - for (CachedBluetoothDevice item : mAllOfCachedDevices) { + for (CachedBluetoothDevice item : mCachedDeviceGroup) { item.unregisterCallback(this); } - mAllOfCachedDevices = Utils.getAllOfCachedBluetoothDevices(mManager, mCachedDevice); - for (CachedBluetoothDevice item : mAllOfCachedDevices) { + mCachedDeviceGroup = Utils.findAllCachedBluetoothDevicesByGroupId(mManager, mCachedDevice); + for (CachedBluetoothDevice item : mCachedDeviceGroup) { item.registerCallback(this); } - if (!mAllOfCachedDevices.isEmpty()) { + if (!mCachedDeviceGroup.isEmpty()) { refresh(); } } diff --git a/src/com/android/settings/bluetooth/Utils.java b/src/com/android/settings/bluetooth/Utils.java index f6288b2c85c..b1d9de7bd3d 100644 --- a/src/com/android/settings/bluetooth/Utils.java +++ b/src/com/android/settings/bluetooth/Utils.java @@ -48,8 +48,9 @@ import com.android.settingslib.utils.ThreadUtils; import com.google.common.base.Supplier; -import java.util.ArrayList; +import java.util.HashSet; import java.util.List; +import java.util.Set; import java.util.concurrent.ExecutionException; import java.util.concurrent.FutureTask; @@ -239,12 +240,12 @@ public final class Utils { * @param cachedBluetoothDevice The main cachedBluetoothDevice. * @return all cachedBluetoothDevices with the same groupId. */ - public static List getAllOfCachedBluetoothDevices( + public static Set findAllCachedBluetoothDevicesByGroupId( LocalBluetoothManager localBtMgr, CachedBluetoothDevice cachedBluetoothDevice) { - List cachedBluetoothDevices = new ArrayList<>(); + Set cachedBluetoothDevices = new HashSet<>(); if (cachedBluetoothDevice == null) { - Log.e(TAG, "getAllOfCachedBluetoothDevices: no cachedBluetoothDevice"); + Log.e(TAG, "findAllCachedBluetoothDevicesByGroupId: no cachedBluetoothDevice"); return cachedBluetoothDevices; } int deviceGroupId = cachedBluetoothDevice.getGroupId(); @@ -254,7 +255,7 @@ public final class Utils { } if (localBtMgr == null) { - Log.e(TAG, "getAllOfCachedBluetoothDevices: no LocalBluetoothManager"); + Log.e(TAG, "findAllCachedBluetoothDevicesByGroupId: no LocalBluetoothManager"); return cachedBluetoothDevices; } CachedBluetoothDevice mainDevice = @@ -262,16 +263,14 @@ public final class Utils { .filter(cachedDevice -> cachedDevice.getGroupId() == deviceGroupId) .findFirst().orElse(null); if (mainDevice == null) { - Log.e(TAG, "getAllOfCachedBluetoothDevices: groupId = " + deviceGroupId + Log.e(TAG, "findAllCachedBluetoothDevicesByGroupId: groupId = " + deviceGroupId + ", no main device."); return cachedBluetoothDevices; } cachedBluetoothDevice = mainDevice; cachedBluetoothDevices.add(cachedBluetoothDevice); - for (CachedBluetoothDevice member : cachedBluetoothDevice.getMemberDevice()) { - cachedBluetoothDevices.add(member); - } - Log.d(TAG, "getAllOfCachedBluetoothDevices: groupId = " + deviceGroupId + cachedBluetoothDevices.addAll(cachedBluetoothDevice.getMemberDevice()); + Log.d(TAG, "findAllCachedBluetoothDevicesByGroupId: groupId = " + deviceGroupId + " , cachedBluetoothDevice = " + cachedBluetoothDevice + " , deviceList = " + cachedBluetoothDevices); return cachedBluetoothDevices; diff --git a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDialogFragment.java b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDialogFragment.java index 6f62ed9d4fc..1ae541ca01d 100644 --- a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDialogFragment.java +++ b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDialogFragment.java @@ -30,6 +30,9 @@ import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentManager; import com.android.settings.R; +import com.android.settings.bluetooth.BluetoothPairingDetail; +import com.android.settings.connecteddevice.audiosharing.audiostreams.AudioStreamsQrCodeFragment; +import com.android.settings.core.SubSettingLauncher; import com.android.settings.core.instrumentation.InstrumentedDialogFragment; import com.android.settingslib.bluetooth.BluetoothUtils; @@ -130,9 +133,27 @@ public class AudioSharingDialogFragment extends InstrumentedDialogFragment { builder.setTitle(R.string.audio_sharing_share_dialog_title) .setCustomImage(R.drawable.audio_sharing_guidance) .setCustomMessage(R.string.audio_sharing_dialog_connect_device_content) - .setNegativeButton( - R.string.audio_sharing_close_button_label, - (dig, which) -> onCancelClick()); + .setCustomPositiveButton( + R.string.audio_sharing_pair_button_label, + v -> { + dismiss(); + new SubSettingLauncher(getContext()) + .setDestination(BluetoothPairingDetail.class.getName()) + .setSourceMetricsCategory(getMetricsCategory()) + .launch(); + logDialogPositiveBtnClick(); + }) + .setCustomNegativeButton( + R.string.audio_sharing_qrcode_button_label, + v -> { + dismiss(); + new SubSettingLauncher(getContext()) + .setTitleRes(R.string.audio_streams_qr_code_page_title) + .setDestination(AudioStreamsQrCodeFragment.class.getName()) + .setSourceMetricsCategory(getMetricsCategory()) + .launch(); + logDialogNegativeBtnClick(); + }); } else if (deviceItems.size() == 1) { AudioSharingDeviceItem deviceItem = Iterables.getOnlyElement(deviceItems); builder.setTitle( @@ -145,11 +166,7 @@ public class AudioSharingDialogFragment extends InstrumentedDialogFragment { v -> { if (sListener != null) { sListener.onItemClick(deviceItem); - mMetricsFeatureProvider.action( - getContext(), - SettingsEnums - .ACTION_AUDIO_SHARING_DIALOG_POSITIVE_BTN_CLICKED, - sEventData); + logDialogPositiveBtnClick(); } dismiss(); }) @@ -165,6 +182,7 @@ public class AudioSharingDialogFragment extends InstrumentedDialogFragment { (AudioSharingDeviceItem item) -> { if (sListener != null) { sListener.onItemClick(item); + logDialogPositiveBtnClick(); } dismiss(); }, @@ -178,11 +196,22 @@ public class AudioSharingDialogFragment extends InstrumentedDialogFragment { private void onCancelClick() { if (sListener != null) { sListener.onCancelClick(); - mMetricsFeatureProvider.action( - getContext(), - SettingsEnums.ACTION_AUDIO_SHARING_DIALOG_NEGATIVE_BTN_CLICKED, - sEventData); + logDialogNegativeBtnClick(); } dismiss(); } + + private void logDialogPositiveBtnClick() { + mMetricsFeatureProvider.action( + getContext(), + SettingsEnums.ACTION_AUDIO_SHARING_DIALOG_POSITIVE_BTN_CLICKED, + sEventData); + } + + private void logDialogNegativeBtnClick() { + mMetricsFeatureProvider.action( + getContext(), + SettingsEnums.ACTION_AUDIO_SHARING_DIALOG_NEGATIVE_BTN_CLICKED, + sEventData); + } } diff --git a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDialogHandler.java b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDialogHandler.java index 4ee405d0f35..14c19decb6f 100644 --- a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDialogHandler.java +++ b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDialogHandler.java @@ -499,7 +499,7 @@ public class AudioSharingDialogHandler { private void removeSourceForGroup( int groupId, Map> groupedDevices) { if (mAssistant == null) { - Log.d(TAG, "Fail to add source due to null profiles, group = " + groupId); + Log.d(TAG, "Fail to remove source due to null profiles, group = " + groupId); return; } if (!groupedDevices.containsKey(groupId)) { diff --git a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingReceiver.java b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingReceiver.java index b43a544e4d6..371613f461d 100644 --- a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingReceiver.java +++ b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingReceiver.java @@ -81,9 +81,15 @@ public class AudioSharingReceiver extends BroadcastReceiver { break; case ACTION_LE_AUDIO_SHARING_STOP: LocalBluetoothManager manager = Utils.getLocalBtManager(context); - AudioSharingUtils.stopBroadcasting(manager); - metricsFeatureProvider.action( - context, SettingsEnums.ACTION_STOP_AUDIO_SHARING_FROM_NOTIFICATION); + if (BluetoothUtils.isBroadcasting(manager)) { + AudioSharingUtils.stopBroadcasting(manager); + metricsFeatureProvider.action( + context, SettingsEnums.ACTION_STOP_AUDIO_SHARING_FROM_NOTIFICATION); + } else { + cancelSharingNotification(context); + metricsFeatureProvider.action( + context, SettingsEnums.ACTION_CANCEL_AUDIO_SHARING_NOTIFICATION); + } break; default: Log.w(TAG, "Received unexpected intent " + intent.getAction()); diff --git a/src/com/android/settings/datetime/AutoTimePreferenceController.java b/src/com/android/settings/datetime/AutoTimePreferenceController.java index 434eba9651e..2942acb1956 100644 --- a/src/com/android/settings/datetime/AutoTimePreferenceController.java +++ b/src/com/android/settings/datetime/AutoTimePreferenceController.java @@ -39,6 +39,11 @@ public class AutoTimePreferenceController extends TogglePreferenceController { public AutoTimePreferenceController(Context context, String preferenceKey) { super(context, preferenceKey); mTimeManager = context.getSystemService(TimeManager.class); + // This is a no-op implementation of UpdateTimeAndDateCallback to avoid a NPE when + // setTimeAndDateCallback() isn't called, e.g. for slices and other cases where the + // controller is instantiated outside of the context of the real Date & Time settings + // screen. + mCallback = (c) -> {}; } public void setDateAndTimeCallback(UpdateTimeAndDateCallback callback) { diff --git a/src/com/android/settings/datetime/AutoTimeZonePreferenceController.java b/src/com/android/settings/datetime/AutoTimeZonePreferenceController.java index 011cc9717cf..3a1f995aaf2 100644 --- a/src/com/android/settings/datetime/AutoTimeZonePreferenceController.java +++ b/src/com/android/settings/datetime/AutoTimeZonePreferenceController.java @@ -40,6 +40,11 @@ public class AutoTimeZonePreferenceController extends TogglePreferenceController public AutoTimeZonePreferenceController(Context context, String preferenceKey) { super(context, preferenceKey); mTimeManager = context.getSystemService(TimeManager.class); + // This is a no-op implementation of UpdateTimeAndDateCallback to avoid a NPE when + // setTimeAndDateCallback() isn't called, e.g. for slices and other cases where the + // controller is instantiated outside of the context of the real Date & Time settings + // screen. + mCallback = (c) -> {}; } /** diff --git a/src/com/android/settings/datetime/TimeFormatPreferenceController.java b/src/com/android/settings/datetime/TimeFormatPreferenceController.java index 22f7509fb7f..19805ad03dd 100644 --- a/src/com/android/settings/datetime/TimeFormatPreferenceController.java +++ b/src/com/android/settings/datetime/TimeFormatPreferenceController.java @@ -43,6 +43,11 @@ public class TimeFormatPreferenceController extends TogglePreferenceController { public TimeFormatPreferenceController(Context context, String key) { super(context, key); mDummyDate = Calendar.getInstance(); + // This is a no-op implementation of UpdateTimeAndDateCallback to avoid a NPE when + // setTimeAndDateCallback() isn't called, e.g. for slices and other cases where the + // controller is instantiated outside of the context of the real Date & Time settings + // screen. + mUpdateTimeAndDateCallback = (c) -> {}; } /** diff --git a/src/com/android/settings/fuelgauge/datasaver/DynamicDenylistManager.java b/src/com/android/settings/fuelgauge/datasaver/DynamicDenylistManager.java index b77d5eb6ddf..ecb2a48fe89 100644 --- a/src/com/android/settings/fuelgauge/datasaver/DynamicDenylistManager.java +++ b/src/com/android/settings/fuelgauge/datasaver/DynamicDenylistManager.java @@ -78,6 +78,11 @@ public class DynamicDenylistManager { return; } + if (mNetworkPolicyManager == null) { + Log.w(TAG, "syncPolicyIfNeeded: invalid mNetworkPolicyManager"); + return; + } + final SharedPreferences.Editor editor = getManualDenylistPref().edit(); final int[] existedUids = mNetworkPolicyManager .getUidsWithPolicy(POLICY_REJECT_METERED_BACKGROUND); @@ -91,6 +96,11 @@ public class DynamicDenylistManager { /** Set policy flags for specific UID. */ public void setUidPolicyLocked(int uid, int policy) { + if (mNetworkPolicyManager == null) { + Log.w(TAG, "setUidPolicyLocked: invalid mNetworkPolicyManager"); + return; + } + Log.i(TAG, "setUidPolicyLocked: uid=" + uid + " policy=" + policy); synchronized (mLock) { mNetworkPolicyManager.setUidPolicy(uid, policy); @@ -100,7 +110,7 @@ public class DynamicDenylistManager { /** Suggest a list of package to set as POLICY_REJECT. */ public void setDenylist(Set denylistTargetUids) { - if (denylistTargetUids == null) { + if (denylistTargetUids == null || mNetworkPolicyManager == null) { return; } final Set manualDenylistUids = getDenylistAllUids(getManualDenylistPref()); @@ -164,6 +174,12 @@ public class DynamicDenylistManager { Log.w(TAG, "resetDenylistIfNeeded: invalid conditions"); return; } + + if (mNetworkPolicyManager == null) { + Log.w(TAG, "setUidPolicyLocked: invalid mNetworkPolicyManager"); + return; + } + synchronized (mLock) { final int[] uids = mNetworkPolicyManager .getUidsWithPolicy(POLICY_REJECT_METERED_BACKGROUND); diff --git a/src/com/android/settings/network/telephony/EnabledNetworkModePreferenceController.java b/src/com/android/settings/network/telephony/EnabledNetworkModePreferenceController.java index e92d9995f99..7d5230db2b6 100644 --- a/src/com/android/settings/network/telephony/EnabledNetworkModePreferenceController.java +++ b/src/com/android/settings/network/telephony/EnabledNetworkModePreferenceController.java @@ -19,9 +19,11 @@ package com.android.settings.network.telephony; import static androidx.lifecycle.Lifecycle.Event.ON_START; import static androidx.lifecycle.Lifecycle.Event.ON_STOP; +import static com.android.settings.network.telephony.EnabledNetworkModePreferenceControllerHelperKt.getNetworkModePreferenceType; import static com.android.settings.network.telephony.EnabledNetworkModePreferenceControllerHelperKt.setAllowedNetworkTypes; import android.content.Context; +import android.content.res.Resources; import android.os.PersistableBundle; import android.telephony.CarrierConfigManager; import android.telephony.SubscriptionInfo; @@ -44,6 +46,7 @@ import androidx.preference.PreferenceScreen; import com.android.internal.telephony.flags.Flags; import com.android.settings.R; +import com.android.settings.core.BasePreferenceController; import com.android.settings.network.AllowedNetworkTypesListener; import com.android.settings.network.CarrierConfigCache; import com.android.settings.network.SubscriptionsChangeListener; @@ -61,16 +64,17 @@ import java.util.stream.Stream; * Preference controller for "Enabled network mode" */ public class EnabledNetworkModePreferenceController extends - TelephonyBasePreferenceController implements + BasePreferenceController implements ListPreference.OnPreferenceChangeListener, LifecycleObserver, SubscriptionsChangeListener.SubscriptionsChangeListenerClient { private static final String LOG_TAG = "EnabledNetworkMode"; + + private int mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; private AllowedNetworkTypesListener mAllowedNetworkTypesListener; private Preference mPreference; private PreferenceScreen mPreferenceScreen; private TelephonyManager mTelephonyManager; - private CarrierConfigCache mCarrierConfigCache; private PreferenceEntriesBuilder mBuilder; private SubscriptionsChangeListener mSubscriptionsListener; private int mCallState = TelephonyManager.CALL_STATE_IDLE; @@ -81,36 +85,16 @@ public class EnabledNetworkModePreferenceController extends public EnabledNetworkModePreferenceController(Context context, String key) { super(context, key); mSubscriptionsListener = new SubscriptionsChangeListener(context, this); - mCarrierConfigCache = CarrierConfigCache.getInstance(context); if (mTelephonyCallback == null) { mTelephonyCallback = new PhoneCallStateTelephonyCallback(); } } @Override - public int getAvailabilityStatus(int subId) { - boolean visible; - - final PersistableBundle carrierConfig = mCarrierConfigCache.getConfigForSubId(subId); - if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { - visible = false; - } else if (carrierConfig == null - || !CarrierConfigManager.isConfigForIdentifiedCarrier(carrierConfig)) { - visible = false; - } else if (carrierConfig.getBoolean( - CarrierConfigManager.KEY_HIDE_CARRIER_NETWORK_SETTINGS_BOOL) - || carrierConfig.getBoolean( - CarrierConfigManager.KEY_HIDE_PREFERRED_NETWORK_TYPE_BOOL)) { - visible = false; - } else if (carrierConfig.getBoolean(CarrierConfigManager.KEY_WORLD_PHONE_BOOL)) { - visible = false; - } else if (!isCallStateIdle()) { - return AVAILABLE_UNSEARCHABLE; - } else { - visible = true; - } - - return visible ? AVAILABLE : CONDITIONALLY_UNAVAILABLE; + public int getAvailabilityStatus() { + return getNetworkModePreferenceType(mContext, mSubId) + == NetworkModePreferenceType.EnabledNetworkMode + ? AVAILABLE : CONDITIONALLY_UNAVAILABLE; } protected boolean isCallStateIdle() { @@ -953,9 +937,14 @@ public class EnabledNetworkModePreferenceController extends } } + /** + * Returns the resources associated with Subscription. + * + * @return Resources associated with Subscription. + */ @VisibleForTesting - PhoneCallStateTelephonyCallback getTelephonyCallback() { - return mTelephonyCallback; + Resources getResourcesForSubId() { + return SubscriptionManager.getResourcesForSubId(mContext, mSubId); } @Override diff --git a/src/com/android/settings/network/telephony/EnabledNetworkModePreferenceControllerHelper.kt b/src/com/android/settings/network/telephony/EnabledNetworkModePreferenceControllerHelper.kt index eab5d747147..d297e1ce262 100644 --- a/src/com/android/settings/network/telephony/EnabledNetworkModePreferenceControllerHelper.kt +++ b/src/com/android/settings/network/telephony/EnabledNetworkModePreferenceControllerHelper.kt @@ -16,9 +16,15 @@ package com.android.settings.network.telephony +import android.content.Context +import android.telephony.CarrierConfigManager +import android.telephony.SubscriptionManager import android.telephony.TelephonyManager import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.lifecycleScope +import com.android.settings.R +import com.android.settings.network.telephony.MobileNetworkSettingsSearchIndex.MobileNetworkSettingsSearchItem +import com.android.settings.network.telephony.MobileNetworkSettingsSearchIndex.MobileNetworkSettingsSearchResult import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch @@ -33,3 +39,62 @@ fun TelephonyManager.setAllowedNetworkTypes( ) } } + +enum class NetworkModePreferenceType { + EnabledNetworkMode, + PreferredNetworkMode, + None, +} + +fun getNetworkModePreferenceType(context: Context, subId: Int): NetworkModePreferenceType { + if (!SubscriptionManager.isValidSubscriptionId(subId)) return NetworkModePreferenceType.None + data class Config( + val carrierConfigApplied: Boolean, + val hideCarrierNetworkSettings: Boolean, + val hidePreferredNetworkType: Boolean, + val worldPhone: Boolean, + ) + + val config = + CarrierConfigRepository(context).transformConfig(subId) { + Config( + carrierConfigApplied = + getBoolean(CarrierConfigManager.KEY_CARRIER_CONFIG_APPLIED_BOOL), + hideCarrierNetworkSettings = + getBoolean(CarrierConfigManager.KEY_HIDE_CARRIER_NETWORK_SETTINGS_BOOL), + hidePreferredNetworkType = + getBoolean(CarrierConfigManager.KEY_HIDE_PREFERRED_NETWORK_TYPE_BOOL), + worldPhone = getBoolean(CarrierConfigManager.KEY_WORLD_PHONE_BOOL), + ) + } + + return when { + !config.carrierConfigApplied || + config.hideCarrierNetworkSettings || + config.hidePreferredNetworkType -> NetworkModePreferenceType.None + config.worldPhone -> NetworkModePreferenceType.PreferredNetworkMode + else -> NetworkModePreferenceType.EnabledNetworkMode + } +} + +class PreferredNetworkModeSearchItem(private val context: Context) : + MobileNetworkSettingsSearchItem { + private val title: String = context.getString(R.string.preferred_network_mode_title) + + override fun getSearchResult(subId: Int): MobileNetworkSettingsSearchResult? = + when (getNetworkModePreferenceType(context, subId)) { + NetworkModePreferenceType.PreferredNetworkMode -> + MobileNetworkSettingsSearchResult( + key = "preferred_network_mode_key", + title = title, + ) + + NetworkModePreferenceType.EnabledNetworkMode -> + MobileNetworkSettingsSearchResult( + key = "enabled_networks_key", + title = title, + ) + + else -> null + } +} diff --git a/src/com/android/settings/network/telephony/MmsMessagePreferenceController.kt b/src/com/android/settings/network/telephony/MmsMessagePreferenceController.kt index c929d5ca897..220218c9473 100644 --- a/src/com/android/settings/network/telephony/MmsMessagePreferenceController.kt +++ b/src/com/android/settings/network/telephony/MmsMessagePreferenceController.kt @@ -20,11 +20,13 @@ import android.content.Context import android.telephony.SubscriptionManager import android.telephony.TelephonyManager import android.telephony.data.ApnSetting +import androidx.annotation.VisibleForTesting import androidx.lifecycle.LifecycleOwner import androidx.preference.PreferenceScreen import com.android.settings.R import com.android.settings.Settings.MobileNetworkActivity.EXTRA_MMS_MESSAGE import com.android.settings.core.TogglePreferenceController +import com.android.settings.network.telephony.MobileNetworkSettingsSearchIndex.MobileNetworkSettingsSearchResult import com.android.settings.network.telephony.MobileNetworkSettingsSearchIndex.MobileNetworkSettingsSearchItem import com.android.settingslib.spa.framework.util.collectLatestWithLifecycle import kotlinx.coroutines.flow.combine @@ -109,7 +111,7 @@ constructor( } class MmsMessageSearchItem( - context: Context, + private val context: Context, private val getDefaultDataSubId: () -> Int = { SubscriptionManager.getDefaultDataSubscriptionId() }, @@ -117,12 +119,18 @@ constructor( private var telephonyManager: TelephonyManager = context.getSystemService(TelephonyManager::class.java)!! - override val key: String = EXTRA_MMS_MESSAGE - override val title: String = context.getString(R.string.mms_message_title) - - override fun isAvailable(subId: Int): Boolean = + @VisibleForTesting + fun isAvailable(subId: Int): Boolean = getAvailabilityStatus( telephonyManager.createForSubscriptionId(subId), subId, getDefaultDataSubId) + + override fun getSearchResult(subId: Int): MobileNetworkSettingsSearchResult? { + if (!isAvailable(subId)) return null + return MobileNetworkSettingsSearchResult( + key = EXTRA_MMS_MESSAGE, + title = context.getString(R.string.mms_message_title), + ) + } } } } diff --git a/src/com/android/settings/network/telephony/MobileNetworkSettingsSearchIndex.kt b/src/com/android/settings/network/telephony/MobileNetworkSettingsSearchIndex.kt index 4e97d318033..58661f0e4fb 100644 --- a/src/com/android/settings/network/telephony/MobileNetworkSettingsSearchIndex.kt +++ b/src/com/android/settings/network/telephony/MobileNetworkSettingsSearchIndex.kt @@ -39,15 +39,14 @@ class MobileNetworkSettingsSearchIndex( private val searchItemsFactory: (context: Context) -> List = ::createSearchItems, ) { + data class MobileNetworkSettingsSearchResult( + val key: String, + val title: String, + val keywords: String? = null, + ) + interface MobileNetworkSettingsSearchItem { - val key: String - - val title: String - - val keywords: String? - get() = null - - fun isAvailable(subId: Int): Boolean + fun getSearchResult(subId: Int): MobileNetworkSettingsSearchResult? } fun createSearchIndexableData(): SearchIndexableData { @@ -71,13 +70,15 @@ class MobileNetworkSettingsSearchIndex( searchItem: MobileNetworkSettingsSearchItem, subInfos: List ): List = - subInfos - .filter { searchItem.isAvailable(it.subscriptionId) } - .map { subInfo -> searchIndexableRaw(context, searchItem, subInfo) } + subInfos.mapNotNull { subInfo -> + searchItem.getSearchResult(subInfo.subscriptionId)?.let { searchResult -> + searchIndexableRaw(context, searchResult, subInfo) + } + } private fun searchIndexableRaw( context: Context, - searchItem: MobileNetworkSettingsSearchItem, + searchResult: MobileNetworkSettingsSearchResult, subInfo: SubscriptionInfo, ): SearchIndexableRaw { val key = @@ -85,7 +86,7 @@ class MobileNetworkSettingsSearchIndex( .setFragment( SpaSearchLandingFragment.newBuilder() .setFragmentName(MobileNetworkSettings::class.java.name) - .setPreferenceKey(searchItem.key) + .setPreferenceKey(searchResult.key) .putArguments( Settings.EXTRA_SUB_ID, BundleValue.newBuilder().setIntValue(subInfo.subscriptionId).build())) @@ -94,8 +95,8 @@ class MobileNetworkSettingsSearchIndex( return createSearchIndexableRaw( context = context, spaSearchLandingKey = key, - itemTitle = searchItem.title, - keywords = searchItem.keywords, + itemTitle = searchResult.title, + keywords = searchResult.keywords, indexableClass = MobileNetworkSettings::class.java, pageTitle = "$simsTitle > ${subInfo.displayName}", ) @@ -115,6 +116,7 @@ class MobileNetworkSettingsSearchIndex( listOf( MmsMessageSearchItem(context), NrAdvancedCallingSearchItem(context), + PreferredNetworkModeSearchItem(context), RoamingSearchItem(context), WifiCallingSearchItem(context), ) diff --git a/src/com/android/settings/network/telephony/NrAdvancedCallingPreferenceController.kt b/src/com/android/settings/network/telephony/NrAdvancedCallingPreferenceController.kt index 5c94e848270..0d8766e4df0 100644 --- a/src/com/android/settings/network/telephony/NrAdvancedCallingPreferenceController.kt +++ b/src/com/android/settings/network/telephony/NrAdvancedCallingPreferenceController.kt @@ -25,6 +25,7 @@ import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.res.stringResource import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.android.settings.R +import com.android.settings.network.telephony.MobileNetworkSettingsSearchIndex.MobileNetworkSettingsSearchResult import com.android.settings.network.telephony.MobileNetworkSettingsSearchIndex.MobileNetworkSettingsSearchItem import com.android.settings.spa.preference.ComposePreferenceController import com.android.settingslib.spa.widget.preference.SwitchPreference @@ -79,12 +80,17 @@ class NrAdvancedCallingPreferenceController @JvmOverloads constructor( companion object { class NrAdvancedCallingSearchItem(private val context: Context) : MobileNetworkSettingsSearchItem { - override val key = "nr_advanced_calling" - override val title: String = context.getString(R.string.nr_advanced_calling_title) - override val keywords: String = context.getString(R.string.keywords_nr_advanced_calling) - override fun isAvailable(subId: Int): Boolean = - VoNrRepository(context, subId).isVoNrAvailable() + fun isAvailable(subId: Int): Boolean = VoNrRepository(context, subId).isVoNrAvailable() + + override fun getSearchResult(subId: Int): MobileNetworkSettingsSearchResult? { + if (!isAvailable(subId)) return null + return MobileNetworkSettingsSearchResult( + key = "nr_advanced_calling", + title = context.getString(R.string.nr_advanced_calling_title), + keywords = context.getString(R.string.keywords_nr_advanced_calling), + ) + } } } } diff --git a/src/com/android/settings/network/telephony/PreferredNetworkModePreferenceController.java b/src/com/android/settings/network/telephony/PreferredNetworkModePreferenceController.java index bdfeace1be6..210cd879966 100644 --- a/src/com/android/settings/network/telephony/PreferredNetworkModePreferenceController.java +++ b/src/com/android/settings/network/telephony/PreferredNetworkModePreferenceController.java @@ -16,6 +16,8 @@ package com.android.settings.network.telephony; +import static com.android.settings.network.telephony.EnabledNetworkModePreferenceControllerHelperKt.getNetworkModePreferenceType; + import android.content.Context; import android.os.PersistableBundle; import android.telephony.CarrierConfigManager; @@ -27,16 +29,18 @@ import androidx.preference.ListPreference; import androidx.preference.Preference; import com.android.settings.R; +import com.android.settings.core.BasePreferenceController; import com.android.settings.network.CarrierConfigCache; import com.android.settings.network.telephony.TelephonyConstants.TelephonyManagerConstants; /** * Preference controller for "Preferred network mode" */ -public class PreferredNetworkModePreferenceController extends TelephonyBasePreferenceController +public class PreferredNetworkModePreferenceController extends BasePreferenceController implements ListPreference.OnPreferenceChangeListener { private static final String TAG = "PrefNetworkModeCtrl"; + private int mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; private CarrierConfigCache mCarrierConfigCache; private TelephonyManager mTelephonyManager; private boolean mIsGlobalCdma; @@ -47,25 +51,10 @@ public class PreferredNetworkModePreferenceController extends TelephonyBasePrefe } @Override - public int getAvailabilityStatus(int subId) { - final PersistableBundle carrierConfig = mCarrierConfigCache.getConfigForSubId(subId); - boolean visible; - if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { - visible = false; - } else if (carrierConfig == null) { - visible = false; - } else if (carrierConfig.getBoolean( - CarrierConfigManager.KEY_HIDE_CARRIER_NETWORK_SETTINGS_BOOL) - || carrierConfig.getBoolean( - CarrierConfigManager.KEY_HIDE_PREFERRED_NETWORK_TYPE_BOOL)) { - visible = false; - } else if (carrierConfig.getBoolean(CarrierConfigManager.KEY_WORLD_PHONE_BOOL)) { - visible = true; - } else { - visible = false; - } - - return visible ? AVAILABLE : CONDITIONALLY_UNAVAILABLE; + public int getAvailabilityStatus() { + return getNetworkModePreferenceType(mContext, mSubId) + == NetworkModePreferenceType.PreferredNetworkMode + ? AVAILABLE : CONDITIONALLY_UNAVAILABLE; } @Override diff --git a/src/com/android/settings/network/telephony/RoamingPreferenceController.kt b/src/com/android/settings/network/telephony/RoamingPreferenceController.kt index 7633677dcb4..a5ac7d66640 100644 --- a/src/com/android/settings/network/telephony/RoamingPreferenceController.kt +++ b/src/com/android/settings/network/telephony/RoamingPreferenceController.kt @@ -29,6 +29,7 @@ import androidx.compose.ui.res.stringResource import androidx.fragment.app.FragmentManager import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.android.settings.R +import com.android.settings.network.telephony.MobileNetworkSettingsSearchIndex.MobileNetworkSettingsSearchResult import com.android.settings.network.telephony.MobileNetworkSettingsSearchIndex.MobileNetworkSettingsSearchItem import com.android.settings.spa.preference.ComposePreferenceController import com.android.settingslib.spa.widget.preference.SwitchPreferenceModel @@ -98,16 +99,21 @@ constructor( companion object { private const val DIALOG_TAG = "MobileDataDialog" - class RoamingSearchItem(context: Context) : MobileNetworkSettingsSearchItem { - override val key = "button_roaming_key" - override val title: String = context.getString(R.string.roaming) - + class RoamingSearchItem(private val context: Context) : MobileNetworkSettingsSearchItem { private val carrierConfigRepository = CarrierConfigRepository(context) - override fun isAvailable(subId: Int): Boolean = + fun isAvailable(subId: Int): Boolean = SubscriptionManager.isValidSubscriptionId(subId) && !carrierConfigRepository.getBoolean( subId, CarrierConfigManager.KEY_FORCE_HOME_NETWORK_BOOL) + + override fun getSearchResult(subId: Int): MobileNetworkSettingsSearchResult? { + if (!isAvailable(subId)) return null + return MobileNetworkSettingsSearchResult( + key = "button_roaming_key", + title = context.getString(R.string.roaming), + ) + } } } } diff --git a/src/com/android/settings/network/telephony/TelephonyBasePreferenceController.java b/src/com/android/settings/network/telephony/TelephonyBasePreferenceController.java index 3972f3900f3..ee1552083ea 100644 --- a/src/com/android/settings/network/telephony/TelephonyBasePreferenceController.java +++ b/src/com/android/settings/network/telephony/TelephonyBasePreferenceController.java @@ -17,9 +17,6 @@ package com.android.settings.network.telephony; import android.content.Context; -import android.content.res.Resources; -import android.os.PersistableBundle; -import android.telephony.CarrierConfigManager; import android.telephony.SubscriptionManager; import com.android.settings.core.BasePreferenceController; @@ -59,29 +56,4 @@ public abstract class TelephonyBasePreferenceController extends BasePreferenceCo public void unsetAvailabilityStatus() { mSetSessionCount.getAndDecrement(); } - - /** - * Get carrier config based on specific subscription id. - * - * @param subId is the subscription id - * @return {@link PersistableBundle} of carrier config, or {@code null} when carrier config - * is not available. - */ - public PersistableBundle getCarrierConfigForSubId(int subId) { - if (!SubscriptionManager.isValidSubscriptionId(subId)) { - return null; - } - final CarrierConfigManager carrierConfigMgr = - mContext.getSystemService(CarrierConfigManager.class); - return carrierConfigMgr.getConfigForSubId(subId); - } - - /** - * Returns the resources associated with Subscription. - * - * @return Resources associated with Subscription. - */ - public Resources getResourcesForSubId() { - return SubscriptionManager.getResourcesForSubId(mContext, mSubId); - } } diff --git a/src/com/android/settings/network/telephony/WifiCallingPreferenceController.kt b/src/com/android/settings/network/telephony/WifiCallingPreferenceController.kt index 7e8e58cceb5..e04763a88c1 100644 --- a/src/com/android/settings/network/telephony/WifiCallingPreferenceController.kt +++ b/src/com/android/settings/network/telephony/WifiCallingPreferenceController.kt @@ -27,6 +27,7 @@ import androidx.preference.Preference import androidx.preference.PreferenceScreen import com.android.settings.R import com.android.settings.core.BasePreferenceController +import com.android.settings.network.telephony.MobileNetworkSettingsSearchIndex.MobileNetworkSettingsSearchResult import com.android.settings.network.telephony.MobileNetworkSettingsSearchIndex.MobileNetworkSettingsSearchItem import com.android.settings.network.telephony.wificalling.WifiCallingRepository import com.android.settingslib.spa.framework.util.collectLatestWithLifecycle @@ -132,12 +133,17 @@ open class WifiCallingPreferenceController @JvmOverloads constructor( class WifiCallingSearchItem( private val context: Context, ) : MobileNetworkSettingsSearchItem { - override val key: String = "wifi_calling" - override val title: String = context.getString(R.string.wifi_calling_settings_title) - - override fun isAvailable(subId: Int): Boolean = runBlocking { + private fun isAvailable(subId: Int): Boolean = runBlocking { WifiCallingRepository(context, subId).wifiCallingReadyFlow().first() } + + override fun getSearchResult(subId: Int): MobileNetworkSettingsSearchResult? { + if (!isAvailable(subId)) return null + return MobileNetworkSettingsSearchResult( + key = "wifi_calling", + title = context.getString(R.string.wifi_calling_settings_title), + ) + } } } } diff --git a/src/com/android/settings/password/SetNewPasswordActivity.java b/src/com/android/settings/password/SetNewPasswordActivity.java index 0ba52eab132..36756f91081 100644 --- a/src/com/android/settings/password/SetNewPasswordActivity.java +++ b/src/com/android/settings/password/SetNewPasswordActivity.java @@ -124,9 +124,7 @@ public class SetNewPasswordActivity extends Activity implements SetNewPasswordCo @Override public void launchChooseLock(Bundle chooseLockFingerprintExtras) { - final boolean isInSetupWizard = WizardManagerHelper.isAnySetupWizard(getIntent()); - Intent intent = isInSetupWizard ? new Intent(this, SetupChooseLockGeneric.class) - : new Intent(this, ChooseLockGeneric.class); + final Intent intent = new Intent(this, SetupChooseLockGeneric.class); intent.setAction(mNewPasswordAction); intent.putExtras(chooseLockFingerprintExtras); intent.putExtra(EXTRA_KEY_CHOOSE_LOCK_SCREEN_TITLE, diff --git a/src/com/android/settings/users/UserSettings.java b/src/com/android/settings/users/UserSettings.java index 0cf01e311e1..c387d9e461d 100644 --- a/src/com/android/settings/users/UserSettings.java +++ b/src/com/android/settings/users/UserSettings.java @@ -919,7 +919,7 @@ public class UserSettings extends SettingsPreferenceFragment d = mCreateUserDialogController.createDialog( getActivity(), this::startActivityForResult, - UserManager.isMultipleAdminEnabled(), + canCreateAdminUser(), (userName, userIcon, isAdmin) -> { mPendingUserIcon = userIcon; mPendingUserName = userName; @@ -937,6 +937,19 @@ public class UserSettings extends SettingsPreferenceFragment return d; } + /** + * Checks if the creation of a new admin user is allowed. + * @return {@code true} if creating a new admin is allowed, {@code false} otherwise. + */ + private boolean canCreateAdminUser() { + if (Flags.unicornModeRefactoringForHsumReadOnly()) { + return UserManager.isMultipleAdminEnabled() + && !mUserManager.hasUserRestriction(UserManager.DISALLOW_GRANT_ADMIN); + } else { + return UserManager.isMultipleAdminEnabled(); + } + } + @Override public int getDialogMetricsCategory(int dialogId) { switch (dialogId) { diff --git a/src/com/android/settings/wifi/dpp/WifiQrCode.java b/src/com/android/settings/wifi/dpp/WifiQrCode.java index 9b93480fd68..78e06253882 100644 --- a/src/com/android/settings/wifi/dpp/WifiQrCode.java +++ b/src/com/android/settings/wifi/dpp/WifiQrCode.java @@ -46,6 +46,7 @@ import android.util.Log; * */ public class WifiQrCode { + private static final String TAG = "WifiQrCode"; static final String SCHEME_DPP = "DPP"; static final String SCHEME_ZXING_WIFI_NETWORK_CONFIG = "WIFI"; static final String PREFIX_DPP = "DPP:"; @@ -119,13 +120,13 @@ public class WifiQrCode { try { wifiQrCode = new WifiQrCode(qrCode); } catch(IllegalArgumentException e) { + Log.e(TAG, "Failed to create WifiQrCode!", e); return null; } - - if (SCHEME_DPP.equals(wifiQrCode.getScheme())) { - return wifiQrCode; + if (wifiQrCode.getScheme() != UriParserResults.URI_SCHEME_DPP) { + Log.e(TAG, "wifiQrCode scheme is not DPP!"); + return null; } - - return null; + return wifiQrCode; } } diff --git a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDevicePreferenceTest.java b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDevicePreferenceTest.java index 03113421d3f..ba90ccf63d0 100644 --- a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDevicePreferenceTest.java +++ b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDevicePreferenceTest.java @@ -18,10 +18,10 @@ package com.android.settings.bluetooth; import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; -import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -32,22 +32,31 @@ import android.content.Context; import android.graphics.drawable.Drawable; import android.os.UserManager; import android.util.Pair; -import android.view.ContextThemeWrapper; + +import androidx.test.core.app.ApplicationProvider; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.settings.R; import com.android.settings.testutils.FakeFeatureFactory; import com.android.settings.testutils.shadow.ShadowAlertDialogCompat; +import com.android.settings.testutils.shadow.ShadowBluetoothUtils; import com.android.settingslib.bluetooth.CachedBluetoothDevice; +import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager; +import com.android.settingslib.bluetooth.LocalBluetoothManager; import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; + import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; import org.mockito.Mock; -import org.mockito.MockitoAnnotations; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; import org.robolectric.util.ReflectionHelpers; @@ -57,18 +66,21 @@ import java.util.Comparator; import java.util.List; @RunWith(RobolectricTestRunner.class) -@Config(shadows = {ShadowAlertDialogCompat.class}) +@Config(shadows = {ShadowAlertDialogCompat.class, + com.android.settings.testutils.shadow.ShadowBluetoothUtils.class}) public class BluetoothDevicePreferenceTest { private static final boolean SHOW_DEVICES_WITHOUT_NAMES = true; - private static final String MAC_ADDRESS = "04:52:C7:0B:D8:3C"; - private static final String MAC_ADDRESS_2 = "05:52:C7:0B:D8:3C"; - private static final String MAC_ADDRESS_3 = "06:52:C7:0B:D8:3C"; - private static final String MAC_ADDRESS_4 = "07:52:C7:0B:D8:3C"; + private static final String TEST_MAC_ADDRESS = "04:52:C7:0B:D8:3C"; + private static final String TEST_MAC_ADDRESS_1 = "05:52:C7:0B:D8:3C"; + private static final String TEST_MAC_ADDRESS_2 = "06:52:C7:0B:D8:3C"; + private static final String TEST_MAC_ADDRESS_3 = "07:52:C7:0B:D8:3C"; private static final Comparator COMPARATOR = Comparator.naturalOrder(); private static final String FAKE_DESCRIPTION = "fake_description"; + private static final int TEST_DEVICE_GROUP_ID = 1; - private Context mContext; + @Rule + public final MockitoRule mockito = MockitoJUnit.rule(); @Mock private CachedBluetoothDevice mCachedBluetoothDevice; @Mock @@ -89,35 +101,37 @@ public class BluetoothDevicePreferenceTest { private Drawable mDrawable; @Mock private BluetoothAdapter mBluetoothAdapter; + @Mock + private LocalBluetoothManager mLocalBluetoothManager; + @Mock + private CachedBluetoothDeviceManager mDeviceManager; + private Context mContext = ApplicationProvider.getApplicationContext(); private FakeFeatureFactory mFakeFeatureFactory; private MetricsFeatureProvider mMetricsFeatureProvider; + private BluetoothDevicePreference mPreference; private List mPreferenceList = new ArrayList<>(); @Before public void setUp() { - MockitoAnnotations.initMocks(this); - Context context = spy(RuntimeEnvironment.application.getApplicationContext()); - mContext = new ContextThemeWrapper(context, R.style.Theme_Settings); + mContext.setTheme(R.style.Theme_Settings); mFakeFeatureFactory = FakeFeatureFactory.setupForTest(); mMetricsFeatureProvider = mFakeFeatureFactory.getMetricsFeatureProvider(); - when(mCachedBluetoothDevice.getAddress()).thenReturn(MAC_ADDRESS); - when(mCachedBluetoothDevice.getDrawableWithDescription()) - .thenReturn(new Pair<>(mDrawable, FAKE_DESCRIPTION)); - when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice); - when(mCachedDevice1.getAddress()).thenReturn(MAC_ADDRESS_2); - when(mCachedDevice1.getDrawableWithDescription()) - .thenReturn(new Pair<>(mDrawable, FAKE_DESCRIPTION)); - when(mCachedDevice1.getDevice()).thenReturn(mBluetoothDevice1); - when(mCachedDevice2.getAddress()).thenReturn(MAC_ADDRESS_3); - when(mCachedDevice2.getDrawableWithDescription()) - .thenReturn(new Pair<>(mDrawable, FAKE_DESCRIPTION)); - when(mCachedDevice2.getDevice()).thenReturn(mBluetoothDevice2); - when(mCachedDevice3.getAddress()).thenReturn(MAC_ADDRESS_4); - when(mCachedDevice3.getDrawableWithDescription()) - .thenReturn(new Pair<>(mDrawable, FAKE_DESCRIPTION)); - when(mCachedDevice3.getDevice()).thenReturn(mBluetoothDevice3); + ShadowBluetoothUtils.sLocalBluetoothManager = mLocalBluetoothManager; + mLocalBluetoothManager = Utils.getLocalBtManager(mContext); + when(mLocalBluetoothManager.getCachedDeviceManager()).thenReturn(mDeviceManager); + prepareCachedBluetoothDevice(mCachedBluetoothDevice, TEST_MAC_ADDRESS, + new Pair<>(mDrawable, FAKE_DESCRIPTION), TEST_DEVICE_GROUP_ID, mBluetoothDevice); + prepareCachedBluetoothDevice(mCachedDevice1, TEST_MAC_ADDRESS_1, + new Pair<>(mDrawable, FAKE_DESCRIPTION), TEST_DEVICE_GROUP_ID, mBluetoothDevice1); + prepareCachedBluetoothDevice(mCachedDevice2, TEST_MAC_ADDRESS_2, + new Pair<>(mDrawable, FAKE_DESCRIPTION), TEST_DEVICE_GROUP_ID, mBluetoothDevice2); + prepareCachedBluetoothDevice(mCachedDevice3, TEST_MAC_ADDRESS_3, + new Pair<>(mDrawable, FAKE_DESCRIPTION), TEST_DEVICE_GROUP_ID, mBluetoothDevice3); + when(mDeviceManager.getCachedDevicesCopy()).thenReturn( + ImmutableList.of(mCachedBluetoothDevice)); + mPreference = new BluetoothDevicePreference(mContext, mCachedBluetoothDevice, SHOW_DEVICES_WITHOUT_NAMES, BluetoothDevicePreference.SortType.TYPE_DEFAULT); mPreference.mBluetoothAdapter = mBluetoothAdapter; @@ -301,7 +315,8 @@ public class BluetoothDevicePreferenceTest { // callback is not removed. mPreference.onAttached(); - verify(mCachedBluetoothDevice, times(1)).registerCallback(any()); + verify(mCachedBluetoothDevice, times(1)).registerCallback(eq(mContext.getMainExecutor()), + any()); verify(mBluetoothAdapter, times(1)).addOnMetadataChangedListener(any(), any(), any()); } @@ -313,7 +328,99 @@ public class BluetoothDevicePreferenceTest { mPreference.onAttached(); verify(mCachedBluetoothDevice, times(1)).unregisterCallback(any()); - verify(mCachedBluetoothDevice, times(2)).registerCallback(any()); + verify(mCachedBluetoothDevice, times(2)).registerCallback(eq(mContext.getMainExecutor()), + any()); verify(mBluetoothAdapter, times(2)).addOnMetadataChangedListener(any(), any(), any()); } + + @Test + public void onDeviceAttributesChanged_updatePreference() { + when(mCachedBluetoothDevice.getName()).thenReturn("Name"); + mPreference.onAttached(); + final String updatedName = "updatedName"; + when(mCachedBluetoothDevice.getName()).thenReturn(updatedName); + + getCachedBluetoothDeviceCallback().onDeviceAttributesChanged(); + + assertThat(mPreference.getTitle().toString()).isEqualTo(updatedName); + } + + @Test + public void onAttached_memberDevicesAdded_registerAllCallback() { + when(mCachedBluetoothDevice.getMemberDevice()).thenReturn( + ImmutableSet.of(mCachedDevice1, mCachedDevice2, mCachedDevice3)); + when(mDeviceManager.getCachedDevicesCopy()).thenReturn( + ImmutableList.of(mCachedBluetoothDevice, mCachedDevice1, mCachedDevice2, + mCachedDevice3)); + mPreference = new BluetoothDevicePreference(mContext, mCachedBluetoothDevice, + SHOW_DEVICES_WITHOUT_NAMES, BluetoothDevicePreference.SortType.TYPE_DEFAULT); + + mPreference.onAttached(); + + verify(mCachedBluetoothDevice).registerCallback(eq(mContext.getMainExecutor()), any()); + verify(mCachedDevice1).registerCallback(eq(mContext.getMainExecutor()), any()); + verify(mCachedDevice2).registerCallback(eq(mContext.getMainExecutor()), any()); + verify(mCachedDevice3).registerCallback(eq(mContext.getMainExecutor()), any()); + } + + @Test + public void onDetached_memberDevicesAdded_unregisterAllCallback() { + when(mCachedBluetoothDevice.getMemberDevice()).thenReturn( + ImmutableSet.of(mCachedDevice1, mCachedDevice2, mCachedDevice3)); + when(mDeviceManager.getCachedDevicesCopy()).thenReturn( + ImmutableList.of(mCachedBluetoothDevice, mCachedDevice1, mCachedDevice2, + mCachedDevice3)); + mPreference = new BluetoothDevicePreference(mContext, mCachedBluetoothDevice, + SHOW_DEVICES_WITHOUT_NAMES, BluetoothDevicePreference.SortType.TYPE_DEFAULT); + + mPreference.onAttached(); + mPreference.onDetached(); + + verify(mCachedBluetoothDevice).unregisterCallback(any()); + verify(mCachedDevice1).unregisterCallback(any()); + verify(mCachedDevice2).unregisterCallback(any()); + verify(mCachedDevice3).unregisterCallback(any()); + } + + @Test + public void onDeviceAttributesChanged_memberDevicesChanged_registerOnlyExistDeviceCallback() { + when(mCachedBluetoothDevice.getMemberDevice()).thenReturn( + ImmutableSet.of(mCachedDevice1, mCachedDevice2, mCachedDevice3)); + when(mDeviceManager.getCachedDevicesCopy()).thenReturn( + ImmutableList.of(mCachedBluetoothDevice, mCachedDevice1, mCachedDevice2, + mCachedDevice3)); + mPreference = new BluetoothDevicePreference(mContext, mCachedBluetoothDevice, + SHOW_DEVICES_WITHOUT_NAMES, BluetoothDevicePreference.SortType.TYPE_DEFAULT); + mPreference.onAttached(); + when(mCachedBluetoothDevice.getMemberDevice()).thenReturn( + ImmutableSet.of(mCachedDevice1, mCachedDevice2)); + when(mDeviceManager.getCachedDevicesCopy()).thenReturn( + ImmutableList.of(mCachedBluetoothDevice, mCachedDevice1, mCachedDevice2)); + + getCachedBluetoothDeviceCallback().onDeviceAttributesChanged(); + + verify(mCachedBluetoothDevice, times(2)).registerCallback(eq(mContext.getMainExecutor()), + any()); + verify(mCachedDevice1, times(2)).registerCallback(eq(mContext.getMainExecutor()), any()); + verify(mCachedDevice2, times(2)).registerCallback(eq(mContext.getMainExecutor()), any()); + verify(mCachedDevice3, times(1)).registerCallback(eq(mContext.getMainExecutor()), any()); + } + + private void prepareCachedBluetoothDevice(CachedBluetoothDevice cachedDevice, String address, + Pair drawableWithDescription, int groupId, + BluetoothDevice bluetoothDevice) { + when(cachedDevice.getAddress()).thenReturn(address); + when(cachedDevice.getDrawableWithDescription()).thenReturn(drawableWithDescription); + when(cachedDevice.getGroupId()).thenReturn(groupId); + when(cachedDevice.getDevice()).thenReturn(bluetoothDevice); + } + + private CachedBluetoothDevice.Callback getCachedBluetoothDeviceCallback() { + ArgumentCaptor callbackCaptor = ArgumentCaptor.forClass( + CachedBluetoothDevice.Callback.class); + verify(mCachedBluetoothDevice).registerCallback(eq(mContext.getMainExecutor()), + callbackCaptor.capture()); + + return callbackCaptor.getValue(); + } } diff --git a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDialogFragmentTest.java b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDialogFragmentTest.java index 20c225c09bf..7227f37998b 100644 --- a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDialogFragmentTest.java +++ b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDialogFragmentTest.java @@ -93,7 +93,6 @@ public class AudioSharingDialogFragmentTest { new Pair[] {TEST_EVENT_DATA}; private Fragment mParent; - private AudioSharingDialogFragment mFragment; private FakeFeatureFactory mFeatureFactory; @Before @@ -107,7 +106,6 @@ public class AudioSharingDialogFragmentTest { shadowBluetoothAdapter.setIsLeAudioBroadcastAssistantSupported( BluetoothStatusCodes.FEATURE_SUPPORTED); mFeatureFactory = FakeFeatureFactory.setupForTest(); - mFragment = new AudioSharingDialogFragment(); mParent = new Fragment(); FragmentController.setupFragment( mParent, FragmentActivity.class, /* containerViewId= */ 0, /* bundle= */ null); @@ -120,7 +118,8 @@ public class AudioSharingDialogFragmentTest { @Test public void getMetricsCategory_correctValue() { - assertThat(mFragment.getMetricsCategory()) + AudioSharingDialogFragment fragment = new AudioSharingDialogFragment(); + assertThat(fragment.getMetricsCategory()) .isEqualTo(SettingsEnums.DIALOG_AUDIO_SHARING_ADD_DEVICE); } @@ -145,7 +144,7 @@ public class AudioSharingDialogFragmentTest { } @Test - public void onCreateDialog_flagOn_noConnectedDevice() { + public void onCreateDialog_flagOn_noExtraConnectedDevice() { mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING); AudioSharingDialogFragment.show( mParent, new ArrayList<>(), EMPTY_EVENT_LISTENER, TEST_EVENT_DATA_LIST); @@ -157,42 +156,67 @@ public class AudioSharingDialogFragmentTest { assertThat(description).isNotNull(); ImageView image = dialog.findViewById(R.id.description_image); assertThat(image).isNotNull(); - Button shareBtn = dialog.findViewById(R.id.positive_btn); - assertThat(shareBtn).isNotNull(); - Button cancelBtn = dialog.findViewById(R.id.negative_btn); - assertThat(cancelBtn).isNotNull(); + Button positiveBtn = dialog.findViewById(R.id.positive_btn); + assertThat(positiveBtn).isNotNull(); + Button negativeBtn = dialog.findViewById(R.id.negative_btn); + assertThat(negativeBtn).isNotNull(); assertThat(dialog.isShowing()).isTrue(); assertThat(description.getVisibility()).isEqualTo(View.VISIBLE); assertThat(description.getText().toString()) .isEqualTo(mParent.getString(R.string.audio_sharing_dialog_connect_device_content)); assertThat(image.getVisibility()).isEqualTo(View.VISIBLE); - assertThat(shareBtn.getVisibility()).isEqualTo(View.GONE); - assertThat(cancelBtn.getVisibility()).isEqualTo(View.GONE); + assertThat(positiveBtn.getVisibility()).isEqualTo(View.VISIBLE); + assertThat(positiveBtn.getText().toString()) + .isEqualTo(mParent.getString(R.string.audio_sharing_pair_button_label)); + assertThat(negativeBtn.getVisibility()).isEqualTo(View.VISIBLE); + assertThat(negativeBtn.getText().toString()) + .isEqualTo(mParent.getString(R.string.audio_sharing_qrcode_button_label)); } @Test - public void onCreateDialog_noConnectedDevice_dialogDismiss() { + public void onCreateDialog_noExtraConnectedDevice_pairNewDevice() { mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING); AudioSharingDialogFragment.show( mParent, new ArrayList<>(), EMPTY_EVENT_LISTENER, TEST_EVENT_DATA_LIST); shadowMainLooper().idle(); AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog(); assertThat(dialog).isNotNull(); - View btnView = dialog.findViewById(android.R.id.button2); - assertThat(btnView).isNotNull(); - btnView.performClick(); + Button pairBtn = dialog.findViewById(R.id.positive_btn); + assertThat(pairBtn).isNotNull(); + pairBtn.performClick(); shadowMainLooper().idle(); + verify(mFeatureFactory.metricsFeatureProvider) + .action( + any(Context.class), + eq(SettingsEnums.ACTION_AUDIO_SHARING_DIALOG_POSITIVE_BTN_CLICKED), + eq(TEST_EVENT_DATA)); assertThat(dialog.isShowing()).isFalse(); + } + + @Test + public void onCreateDialog_noExtraConnectedDevice_showQRCode() { + mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING); + AudioSharingDialogFragment.show( + mParent, new ArrayList<>(), EMPTY_EVENT_LISTENER, TEST_EVENT_DATA_LIST); + shadowMainLooper().idle(); + AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog(); + assertThat(dialog).isNotNull(); + Button qrCodeBtn = dialog.findViewById(R.id.negative_btn); + assertThat(qrCodeBtn).isNotNull(); + qrCodeBtn.performClick(); + shadowMainLooper().idle(); + verify(mFeatureFactory.metricsFeatureProvider) .action( any(Context.class), eq(SettingsEnums.ACTION_AUDIO_SHARING_DIALOG_NEGATIVE_BTN_CLICKED), eq(TEST_EVENT_DATA)); + assertThat(dialog.isShowing()).isFalse(); } @Test - public void onCreateDialog_flagOn_singleConnectedDevice() { + public void onCreateDialog_flagOn_singleExtraConnectedDevice() { mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING); ArrayList list = new ArrayList<>(); list.add(TEST_DEVICE_ITEM1); @@ -207,10 +231,10 @@ public class AudioSharingDialogFragmentTest { assertThat(description).isNotNull(); ImageView image = dialog.findViewById(R.id.description_image); assertThat(image).isNotNull(); - Button shareBtn = dialog.findViewById(R.id.positive_btn); - assertThat(shareBtn).isNotNull(); - Button cancelBtn = dialog.findViewById(R.id.negative_btn); - assertThat(cancelBtn).isNotNull(); + Button positiveBtn = dialog.findViewById(R.id.positive_btn); + assertThat(positiveBtn).isNotNull(); + Button negativeBtn = dialog.findViewById(R.id.negative_btn); + assertThat(negativeBtn).isNotNull(); assertThat(dialog.isShowing()).isTrue(); assertThat(title.getText().toString()) .isEqualTo( @@ -220,12 +244,16 @@ public class AudioSharingDialogFragmentTest { assertThat(description.getText().toString()) .isEqualTo(mParent.getString(R.string.audio_sharing_dialog_share_content)); assertThat(image.getVisibility()).isEqualTo(View.GONE); - assertThat(shareBtn.getVisibility()).isEqualTo(View.VISIBLE); - assertThat(cancelBtn.getVisibility()).isEqualTo(View.VISIBLE); + assertThat(positiveBtn.getVisibility()).isEqualTo(View.VISIBLE); + assertThat(positiveBtn.getText().toString()) + .isEqualTo(mParent.getString(R.string.audio_sharing_share_button_label)); + assertThat(negativeBtn.getVisibility()).isEqualTo(View.VISIBLE); + assertThat(negativeBtn.getText().toString()) + .isEqualTo(mParent.getString(R.string.audio_sharing_no_thanks_button_label)); } @Test - public void onCreateDialog_singleConnectedDevice_dialogDismiss() { + public void onCreateDialog_singleExtraConnectedDevice_dialogDismiss() { mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING); ArrayList list = new ArrayList<>(); list.add(TEST_DEVICE_ITEM1); @@ -248,7 +276,7 @@ public class AudioSharingDialogFragmentTest { } @Test - public void onCreateDialog_singleConnectedDevice_shareClicked() { + public void onCreateDialog_singleExtraConnectedDevice_shareClicked() { mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING); ArrayList list = new ArrayList<>(); list.add(TEST_DEVICE_ITEM1); @@ -285,7 +313,7 @@ public class AudioSharingDialogFragmentTest { } @Test - public void onCreateDialog_flagOn_multipleConnectedDevice() { + public void onCreateDialog_flagOn_multipleExtraConnectedDevice() { mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING); ArrayList list = new ArrayList<>(); list.add(TEST_DEVICE_ITEM1); @@ -313,12 +341,14 @@ public class AudioSharingDialogFragmentTest { assertThat(image.getVisibility()).isEqualTo(View.GONE); assertThat(shareBtn.getVisibility()).isEqualTo(View.GONE); assertThat(cancelBtn.getVisibility()).isEqualTo(View.VISIBLE); + assertThat(cancelBtn.getText().toString()) + .isEqualTo(mParent.getString(com.android.settings.R.string.cancel)); assertThat(recyclerView.getVisibility()).isEqualTo(View.VISIBLE); assertThat(recyclerView.getAdapter().getItemCount()).isEqualTo(3); } @Test - public void onCreateDialog_multipleConnectedDevice_dialogDismiss() { + public void onCreateDialog_multipleExtraConnectedDevice_dialogDismiss() { mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING); ArrayList list = new ArrayList<>(); list.add(TEST_DEVICE_ITEM1); diff --git a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingReceiverTest.java b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingReceiverTest.java index deed229bbcb..db6eb8c72de 100644 --- a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingReceiverTest.java +++ b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingReceiverTest.java @@ -25,7 +25,7 @@ import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.times; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoInteractions; import static org.mockito.Mockito.when; @@ -164,8 +164,7 @@ public class AudioSharingReceiverTest { AudioSharingReceiver audioSharingReceiver = getAudioSharingReceiver(intent); audioSharingReceiver.onReceive(mContext, intent); - verify(mNm, times(1)) - .notify(eq(R.drawable.ic_bt_le_audio_sharing), any(Notification.class)); + verify(mNm).notify(eq(R.drawable.ic_bt_le_audio_sharing), any(Notification.class)); verify(mFeatureFactory.metricsFeatureProvider) .action(mContext, SettingsEnums.ACTION_SHOW_AUDIO_SHARING_NOTIFICATION); } @@ -181,7 +180,7 @@ public class AudioSharingReceiverTest { AudioSharingReceiver audioSharingReceiver = getAudioSharingReceiver(intent); audioSharingReceiver.onReceive(mContext, intent); - verify(mNm, times(1)).cancel(R.drawable.ic_bt_le_audio_sharing); + verify(mNm).cancel(R.drawable.ic_bt_le_audio_sharing); verify(mFeatureFactory.metricsFeatureProvider) .action(mContext, SettingsEnums.ACTION_CANCEL_AUDIO_SHARING_NOTIFICATION); } @@ -199,8 +198,10 @@ public class AudioSharingReceiverTest { } @Test - public void broadcastReceiver_receiveAudioSharingStopIntent_stopBroadcast() { + public void + broadcastReceiver_receiveAudioSharingStopIntent_notInBroadcast_cancelNotification() { mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING); + when(mBroadcast.isEnabled(null)).thenReturn(false); int broadcastId = 1; when(mBroadcast.getLatestBroadcastId()).thenReturn(broadcastId); @@ -209,7 +210,25 @@ public class AudioSharingReceiverTest { AudioSharingReceiver audioSharingReceiver = getAudioSharingReceiver(intent); audioSharingReceiver.onReceive(mContext, intent); - verify(mBroadcast, times(1)).stopBroadcast(broadcastId); + verify(mBroadcast, never()).stopBroadcast(broadcastId); + verify(mNm).cancel(R.drawable.ic_bt_le_audio_sharing); + verify(mFeatureFactory.metricsFeatureProvider) + .action(mContext, SettingsEnums.ACTION_CANCEL_AUDIO_SHARING_NOTIFICATION); + } + + @Test + public void broadcastReceiver_receiveAudioSharingStopIntent_inBroadcast_stopBroadcast() { + mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING); + when(mBroadcast.isEnabled(null)).thenReturn(true); + int broadcastId = 1; + when(mBroadcast.getLatestBroadcastId()).thenReturn(broadcastId); + + Intent intent = new Intent(ACTION_LE_AUDIO_SHARING_STOP); + intent.setPackage(mContext.getPackageName()); + AudioSharingReceiver audioSharingReceiver = getAudioSharingReceiver(intent); + audioSharingReceiver.onReceive(mContext, intent); + + verify(mBroadcast).stopBroadcast(broadcastId); verify(mFeatureFactory.metricsFeatureProvider) .action(mContext, SettingsEnums.ACTION_STOP_AUDIO_SHARING_FROM_NOTIFICATION); } diff --git a/tests/spa_unit/src/com/android/settings/network/telephony/EnabledNetworkModePreferenceControllerHelperTest.kt b/tests/spa_unit/src/com/android/settings/network/telephony/EnabledNetworkModePreferenceControllerHelperTest.kt new file mode 100644 index 00000000000..8edc90fa24c --- /dev/null +++ b/tests/spa_unit/src/com/android/settings/network/telephony/EnabledNetworkModePreferenceControllerHelperTest.kt @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.network.telephony + +import android.content.Context +import android.telephony.CarrierConfigManager +import androidx.test.core.app.ApplicationProvider +import androidx.test.ext.junit.runners.AndroidJUnit4 +import com.google.common.truth.Truth.assertThat +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.kotlin.spy + +@RunWith(AndroidJUnit4::class) +class EnabledNetworkModePreferenceControllerHelperTest { + + private var context: Context = spy(ApplicationProvider.getApplicationContext()) {} + + @Before + fun setUp() { + CarrierConfigRepository.resetForTest() + CarrierConfigRepository.setBooleanForTest( + SUB_ID, CarrierConfigManager.KEY_CARRIER_CONFIG_APPLIED_BOOL, true) + } + + @Test + fun getNetworkModePreferenceType_hideCarrierNetworkSettings_returnNone() { + CarrierConfigRepository.setBooleanForTest( + SUB_ID, CarrierConfigManager.KEY_HIDE_CARRIER_NETWORK_SETTINGS_BOOL, true) + + val networkModePreferenceType = getNetworkModePreferenceType(context, SUB_ID) + + assertThat(networkModePreferenceType).isEqualTo(NetworkModePreferenceType.None) + } + + @Test + fun getNetworkModePreferenceType_hidePreferredNetworkType_returnNone() { + CarrierConfigRepository.setBooleanForTest( + SUB_ID, CarrierConfigManager.KEY_HIDE_PREFERRED_NETWORK_TYPE_BOOL, true) + + val networkModePreferenceType = getNetworkModePreferenceType(context, SUB_ID) + + assertThat(networkModePreferenceType).isEqualTo(NetworkModePreferenceType.None) + } + + @Test + fun getNetworkModePreferenceType_carrierConfigNotReady_returnNone() { + CarrierConfigRepository.setBooleanForTest( + SUB_ID, CarrierConfigManager.KEY_CARRIER_CONFIG_APPLIED_BOOL, false) + + val networkModePreferenceType = getNetworkModePreferenceType(context, SUB_ID) + + assertThat(networkModePreferenceType).isEqualTo(NetworkModePreferenceType.None) + } + + @Test + fun getNetworkModePreferenceType_isWorldPhone_returnPreferredNetworkMode() { + CarrierConfigRepository.setBooleanForTest( + SUB_ID, CarrierConfigManager.KEY_WORLD_PHONE_BOOL, true) + + val networkModePreferenceType = getNetworkModePreferenceType(context, SUB_ID) + + assertThat(networkModePreferenceType) + .isEqualTo(NetworkModePreferenceType.PreferredNetworkMode) + } + + @Test + fun getNetworkModePreferenceType_notWorldPhone_returnEnabledNetworkMode() { + CarrierConfigRepository.setBooleanForTest( + SUB_ID, CarrierConfigManager.KEY_WORLD_PHONE_BOOL, false) + + val networkModePreferenceType = getNetworkModePreferenceType(context, SUB_ID) + + assertThat(networkModePreferenceType) + .isEqualTo(NetworkModePreferenceType.EnabledNetworkMode) + } + + private companion object { + const val SUB_ID = 10 + } +} diff --git a/tests/spa_unit/src/com/android/settings/network/telephony/MobileNetworkSettingsSearchIndexTest.kt b/tests/spa_unit/src/com/android/settings/network/telephony/MobileNetworkSettingsSearchIndexTest.kt index 5e7e83c9f43..bf5120817c1 100644 --- a/tests/spa_unit/src/com/android/settings/network/telephony/MobileNetworkSettingsSearchIndexTest.kt +++ b/tests/spa_unit/src/com/android/settings/network/telephony/MobileNetworkSettingsSearchIndexTest.kt @@ -25,6 +25,7 @@ import androidx.test.core.app.ApplicationProvider import androidx.test.ext.junit.runners.AndroidJUnit4 import com.android.settings.R import com.android.settings.network.telephony.MobileNetworkSettingsSearchIndex.Companion.isMobileNetworkSettingsSearchable +import com.android.settings.network.telephony.MobileNetworkSettingsSearchIndex.MobileNetworkSettingsSearchResult import com.android.settings.spa.SpaSearchLanding.BundleValue import com.android.settings.spa.SpaSearchLanding.SpaSearchLandingFragment import com.android.settings.spa.SpaSearchLanding.SpaSearchLandingKey @@ -62,10 +63,12 @@ class MobileNetworkSettingsSearchIndexTest { private val mobileNetworkSettingsSearchIndex = MobileNetworkSettingsSearchIndex { listOf( object : MobileNetworkSettingsSearchIndex.MobileNetworkSettingsSearchItem { - override val key = KEY - override val title = TITLE - - override fun isAvailable(subId: Int) = subId == SUB_ID_1 + override fun getSearchResult(subId: Int): MobileNetworkSettingsSearchResult? = + if (subId == SUB_ID_1) { + MobileNetworkSettingsSearchResult(key = KEY, title = TITLE) + } else { + null + } }) } diff --git a/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppNotificationPreferenceTest.kt b/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppNotificationPreferenceTest.kt index 37f3a119d0a..7a0ec8c7f13 100644 --- a/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppNotificationPreferenceTest.kt +++ b/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppNotificationPreferenceTest.kt @@ -20,8 +20,8 @@ import android.content.Context import android.content.pm.ApplicationInfo import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.test.assertIsDisplayed import androidx.compose.ui.test.assertIsNotEnabled +import androidx.compose.ui.test.hasText import androidx.compose.ui.test.junit4.createComposeRule import androidx.compose.ui.test.onNodeWithText import androidx.compose.ui.test.onRoot @@ -34,36 +34,35 @@ import com.android.settings.applications.appinfo.AppInfoDashboardFragment import com.android.settings.notification.app.AppNotificationSettings import com.android.settings.spa.notification.IAppNotificationRepository import com.android.settingslib.spa.testutils.delay +import com.android.settingslib.spa.testutils.waitUntilExists import org.junit.After import org.junit.Before import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.mockito.MockitoSession -import org.mockito.Spy import org.mockito.quality.Strictness @RunWith(AndroidJUnit4::class) class AppNotificationPreferenceTest { - @get:Rule - val composeTestRule = createComposeRule() + @get:Rule val composeTestRule = createComposeRule() private lateinit var mockSession: MockitoSession - @Spy private val context: Context = ApplicationProvider.getApplicationContext() - private val repository = object : IAppNotificationRepository { - override fun getNotificationSummary(app: ApplicationInfo) = SUMMARY - } + private val repository = + object : IAppNotificationRepository { + override fun getNotificationSummary(app: ApplicationInfo) = SUMMARY + } @Before fun setUp() { - mockSession = ExtendedMockito.mockitoSession() - .initMocks(this) - .mockStatic(AppInfoDashboardFragment::class.java) - .strictness(Strictness.LENIENT) - .startMocking() + mockSession = + ExtendedMockito.mockitoSession() + .mockStatic(AppInfoDashboardFragment::class.java) + .strictness(Strictness.LENIENT) + .startMocking() } @After @@ -75,25 +74,26 @@ class AppNotificationPreferenceTest { fun title_displayed() { setContent(APP) - composeTestRule.onNodeWithText(context.getString(R.string.notifications_label)) - .assertIsDisplayed() + composeTestRule.waitUntilExists(hasText(context.getString(R.string.notifications_label))) } @Test fun summary_displayed() { setContent(APP) - composeTestRule.onNodeWithText(SUMMARY).assertIsDisplayed() + composeTestRule.waitUntilExists(hasText(SUMMARY)) } @Test fun whenNotInstalled_disable() { - setContent(ApplicationInfo().apply { - packageName = PACKAGE_NAME - uid = UID - }) + setContent( + ApplicationInfo().apply { + packageName = PACKAGE_NAME + uid = UID + }) - composeTestRule.onNodeWithText(context.getString(R.string.notifications_label)) + composeTestRule + .onNodeWithText(context.getString(R.string.notifications_label)) .assertIsNotEnabled() } @@ -125,11 +125,12 @@ class AppNotificationPreferenceTest { private companion object { const val PACKAGE_NAME = "package.name" const val UID = 123 - val APP = ApplicationInfo().apply { - packageName = PACKAGE_NAME - uid = UID - flags = ApplicationInfo.FLAG_INSTALLED - } + val APP = + ApplicationInfo().apply { + packageName = PACKAGE_NAME + uid = UID + flags = ApplicationInfo.FLAG_INSTALLED + } const val SUMMARY = "Summary" } -} \ No newline at end of file +} diff --git a/tests/unit/src/com/android/settings/network/telephony/EnabledNetworkModePreferenceControllerTest.java b/tests/unit/src/com/android/settings/network/telephony/EnabledNetworkModePreferenceControllerTest.java index b3d095e5453..adc8dc0cdc4 100644 --- a/tests/unit/src/com/android/settings/network/telephony/EnabledNetworkModePreferenceControllerTest.java +++ b/tests/unit/src/com/android/settings/network/telephony/EnabledNetworkModePreferenceControllerTest.java @@ -18,9 +18,6 @@ package com.android.settings.network.telephony; import static androidx.lifecycle.Lifecycle.Event.ON_START; -import static com.android.settings.core.BasePreferenceController.AVAILABLE; -import static com.android.settings.core.BasePreferenceController.AVAILABLE_UNSEARCHABLE; -import static com.android.settings.core.BasePreferenceController.CONDITIONALLY_UNAVAILABLE; import static com.android.settings.network.telephony.MobileNetworkUtils.getRafFromNetworkType; import static com.android.settings.network.telephony.TelephonyConstants.RadioAccessFamily.CDMA; import static com.android.settings.network.telephony.TelephonyConstants.RadioAccessFamily.EVDO; @@ -33,8 +30,6 @@ import static com.android.settings.network.telephony.TelephonyConstants.RadioAcc import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; @@ -123,79 +118,6 @@ public class EnabledNetworkModePreferenceControllerTest { mPreference.setKey(mController.getPreferenceKey()); } - @UiThreadTest - @Test - public void getAvailabilityStatus_hideCarrierNetworkSettings_returnUnavailable() { - mPersistableBundle.putBoolean( - CarrierConfigManager.KEY_HIDE_CARRIER_NETWORK_SETTINGS_BOOL, - true); - - assertThat(mController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE); - } - - @UiThreadTest - @Test - public void getAvailabilityStatus_hidePreferredNetworkType_returnUnavailable() { - mPersistableBundle.putBoolean(CarrierConfigManager.KEY_HIDE_PREFERRED_NETWORK_TYPE_BOOL, - true); - - when(mServiceState.getState()).thenReturn(ServiceState.STATE_OUT_OF_SERVICE); - when(mServiceState.getDataRegistrationState()).thenReturn( - ServiceState.STATE_OUT_OF_SERVICE); - assertThat(mController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE); - - when(mServiceState.getState()).thenReturn(ServiceState.STATE_IN_SERVICE); - when(mServiceState.getDataRegistrationState()).thenReturn(ServiceState.STATE_IN_SERVICE); - - when(mServiceState.getRoaming()).thenReturn(false); - assertThat(mController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE); - - when(mServiceState.getRoaming()).thenReturn(true); - assertThat(mController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE); - } - - @UiThreadTest - @Test - public void getAvailabilityStatus_carrierConfigNotReady_returnUnavailable() { - mPersistableBundle.putBoolean(CarrierConfigManager.KEY_CARRIER_CONFIG_APPLIED_BOOL, false); - - assertThat(mController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE); - } - - @UiThreadTest - @Test - public void getAvailabilityStatus_notWorldPhone_returnAvailable() { - mPersistableBundle.putBoolean(CarrierConfigManager.KEY_HIDE_CARRIER_NETWORK_SETTINGS_BOOL, - false); - mPersistableBundle.putBoolean(CarrierConfigManager.KEY_WORLD_PHONE_BOOL, false); - - assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE); - } - - @UiThreadTest - @Test - public void getAvailabilityStatus_callStateIsIdle_returnAvailable() { - mockEnabledNetworkMode(TelephonyManagerConstants.NETWORK_MODE_NR_LTE_GSM_WCDMA); - mController.getTelephonyCallback().onCallStateChanged(TelephonyManager.CALL_STATE_IDLE); - - mController.updateState(mPreference); - - assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE); - assertTrue(mPreference.isEnabled()); - } - - @UiThreadTest - @Test - public void getAvailabilityStatus_duringCalling_returnAvailable() { - mockEnabledNetworkMode(TelephonyManagerConstants.NETWORK_MODE_NR_LTE_GSM_WCDMA); - mController.getTelephonyCallback().onCallStateChanged(TelephonyManager.CALL_STATE_OFFHOOK); - - mController.updateState(mPreference); - - assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE_UNSEARCHABLE); - assertFalse(mPreference.isEnabled()); - } - @UiThreadTest @Test public void updateState_LteWorldPhone_GlobalHasLte() { diff --git a/tests/unit/src/com/android/settings/network/telephony/PreferredNetworkModePreferenceControllerTest.java b/tests/unit/src/com/android/settings/network/telephony/PreferredNetworkModePreferenceControllerTest.java index 9dbfdde3d3b..f22ad3bce8d 100644 --- a/tests/unit/src/com/android/settings/network/telephony/PreferredNetworkModePreferenceControllerTest.java +++ b/tests/unit/src/com/android/settings/network/telephony/PreferredNetworkModePreferenceControllerTest.java @@ -16,8 +16,6 @@ package com.android.settings.network.telephony; -import static com.android.settings.core.BasePreferenceController.AVAILABLE; -import static com.android.settings.core.BasePreferenceController.CONDITIONALLY_UNAVAILABLE; import static com.android.settings.network.telephony.TelephonyConstants.RadioAccessFamily.GSM; import static com.android.settings.network.telephony.TelephonyConstants.RadioAccessFamily.RAF_TD_SCDMA; import static com.android.settings.network.telephony.TelephonyConstants.RadioAccessFamily.WCDMA; @@ -32,7 +30,6 @@ import static org.mockito.Mockito.when; import android.content.Context; import android.os.PersistableBundle; -import android.telephony.CarrierConfigManager; import android.telephony.ServiceState; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; @@ -91,43 +88,6 @@ public class PreferredNetworkModePreferenceControllerTest { mPreference.setKey(mController.getPreferenceKey()); } - @Test - public void getAvailabilityStatus_hideCarrierNetworkSettings_returnUnavailable() { - mPersistableBundle.putBoolean(CarrierConfigManager.KEY_HIDE_CARRIER_NETWORK_SETTINGS_BOOL, - true); - - assertThat(mController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE); - } - - @Test - public void getAvailabilityStatus_worldPhone_returnAvailable() { - mPersistableBundle.putBoolean(CarrierConfigManager.KEY_HIDE_CARRIER_NETWORK_SETTINGS_BOOL, - false); - mPersistableBundle.putBoolean(CarrierConfigManager.KEY_WORLD_PHONE_BOOL, true); - - assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE); - } - - @Test - public void getAvailabilityStatus_hidePreferredNetworkType_returnUnavailable() { - mPersistableBundle.putBoolean(CarrierConfigManager.KEY_HIDE_PREFERRED_NETWORK_TYPE_BOOL, - true); - - when(mServiceState.getState()).thenReturn(ServiceState.STATE_OUT_OF_SERVICE); - when(mServiceState.getDataRegistrationState()).thenReturn( - ServiceState.STATE_OUT_OF_SERVICE); - assertThat(mController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE); - - when(mServiceState.getState()).thenReturn(ServiceState.STATE_IN_SERVICE); - when(mServiceState.getDataRegistrationState()).thenReturn(ServiceState.STATE_IN_SERVICE); - - when(mServiceState.getRoaming()).thenReturn(false); - assertThat(mController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE); - - when(mServiceState.getRoaming()).thenReturn(true); - assertThat(mController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE); - } - @Test public void updateState_updateByNetworkMode() { // NETWORK_MODE_TDSCDMA_GSM_WCDMA = RAF_TD_SCDMA | GSM | WCDMA