diff --git a/res/layout/audio_sharing_password_dialog.xml b/res/layout/audio_sharing_password_dialog.xml
index f1a78bcaad4..2bdf505290d 100644
--- a/res/layout/audio_sharing_password_dialog.xml
+++ b/res/layout/audio_sharing_password_dialog.xml
@@ -53,8 +53,8 @@
diff --git a/res/navigation/privatespace_main_context_nav.xml b/res/navigation/privatespace_main_context_nav.xml
index 3eb57d3ecda..e20eaff5206 100644
--- a/res/navigation/privatespace_main_context_nav.xml
+++ b/res/navigation/privatespace_main_context_nav.xml
@@ -35,6 +35,9 @@
+
+
Couldn\u2019t set up a private space
Try Again
+
+ Exit
+
+ Private space isn\u2019t available.\nView possible causes
+
+ View possible causes
Choose a new lock for private space?
diff --git a/res/xml/mobile_network_settings.xml b/res/xml/mobile_network_settings.xml
index 6c0f7b5450c..63d8a3d7b50 100644
--- a/res/xml/mobile_network_settings.xml
+++ b/res/xml/mobile_network_settings.xml
@@ -85,9 +85,10 @@
android:summary="@string/auto_data_switch_summary"
settings:controller="com.android.settings.network.telephony.AutoDataSwitchPreferenceController"/>
+
> mGroupedConnectedDevices = new HashMap<>();
+ Map> mGroupedConnectedDevices = new HashMap<>();
private List mDeviceItemsInSharingSession = new ArrayList<>();
private final AtomicBoolean mCallbacksRegistered = new AtomicBoolean(false);
@@ -210,17 +210,18 @@ public class AudioSharingCallAudioPreferenceController extends AudioSharingBaseP
"Skip set fallback active device: unchanged");
return;
}
- List devices =
+ List devices =
mGroupedConnectedDevices.getOrDefault(
item.getGroupId(), ImmutableList.of());
CachedBluetoothDevice lead =
- AudioSharingUtils.getLeadDevice(devices);
+ AudioSharingUtils.getLeadDevice(
+ mCacheManager, devices);
if (lead != null) {
Log.d(
TAG,
"Set fallback active device: "
+ lead.getDevice()
- .getAnonymizedAddress());
+ .getAnonymizedAddress());
lead.setActive();
logCallAudioDeviceChange(currentGroupId, lead);
} else {
@@ -347,8 +348,8 @@ public class AudioSharingCallAudioPreferenceController extends AudioSharingBaseP
*/
private void updateSummary() {
updateDeviceItemsInSharingSession();
- int fallbackActiveGroupId = BluetoothUtils.getPrimaryGroupIdForBroadcast(
- mContext.getContentResolver());
+ int fallbackActiveGroupId =
+ BluetoothUtils.getPrimaryGroupIdForBroadcast(mContext.getContentResolver());
if (fallbackActiveGroupId != BluetoothCsipSetCoordinator.GROUP_ID_INVALID) {
for (AudioSharingDeviceItem item : mDeviceItemsInSharingSession) {
if (item.getGroupId() == fallbackActiveGroupId) {
diff --git a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDialogHandler.java b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDialogHandler.java
index 472cb440063..4ee405d0f35 100644
--- a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDialogHandler.java
+++ b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDialogHandler.java
@@ -16,6 +16,8 @@
package com.android.settings.connecteddevice.audiosharing;
+import static java.util.stream.Collectors.toList;
+
import android.app.settings.SettingsEnums;
import android.bluetooth.BluetoothCsipSetCoordinator;
import android.bluetooth.BluetoothDevice;
@@ -38,6 +40,7 @@ import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.bluetooth.BluetoothUtils;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
+import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast;
import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
@@ -49,14 +52,14 @@ import com.google.common.collect.ImmutableList;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
-import java.util.Objects;
import java.util.concurrent.Executor;
public class AudioSharingDialogHandler {
- private static final String TAG = "AudioSharingDialogHandler";
+ private static final String TAG = "AudioSharingDlgHandler";
private final Context mContext;
private final Fragment mHostFragment;
@Nullable private final LocalBluetoothManager mLocalBtManager;
+ @Nullable private final CachedBluetoothDeviceManager mDeviceManager;
@Nullable private final LocalBluetoothLeBroadcast mBroadcast;
@Nullable private final LocalBluetoothLeBroadcastAssistant mAssistant;
private final MetricsFeatureProvider mMetricsFeatureProvider;
@@ -163,6 +166,7 @@ public class AudioSharingDialogHandler {
mContext = context;
mHostFragment = fragment;
mLocalBtManager = Utils.getLocalBluetoothManager(context);
+ mDeviceManager = mLocalBtManager != null ? mLocalBtManager.getCachedDeviceManager() : null;
mBroadcast =
mLocalBtManager != null
? mLocalBtManager.getProfileManager().getLeAudioBroadcastProfile()
@@ -212,7 +216,7 @@ public class AudioSharingDialogHandler {
if (isBroadcasting) {
// Show stop audio sharing dialog when an ineligible (non LE audio) remote device
// connected during a sharing session.
- Map> groupedDevices =
+ Map> groupedDevices =
AudioSharingUtils.fetchConnectedDevicesByGroupId(mLocalBtManager);
List deviceItemsInSharingSession =
AudioSharingUtils.buildOrderedConnectedLeadAudioSharingDeviceItem(
@@ -256,19 +260,19 @@ public class AudioSharingDialogHandler {
@NonNull CachedBluetoothDevice cachedDevice,
boolean isBroadcasting,
boolean userTriggered) {
- Map> groupedDevices =
+ Map> groupedDevices =
AudioSharingUtils.fetchConnectedDevicesByGroupId(mLocalBtManager);
BluetoothDevice btDevice = cachedDevice.getDevice();
String deviceAddress = btDevice == null ? "" : btDevice.getAnonymizedAddress();
+ int groupId = BluetoothUtils.getGroupId(cachedDevice);
if (isBroadcasting) {
// If another device within the same is already in the sharing session, add source to
// the device automatically.
- int groupId = BluetoothUtils.getGroupId(cachedDevice);
if (groupedDevices.containsKey(groupId)
&& groupedDevices.get(groupId).stream()
.anyMatch(
device ->
- BluetoothUtils.hasConnectedBroadcastSource(
+ BluetoothUtils.hasConnectedBroadcastSourceForBtDevice(
device, mLocalBtManager))) {
Log.d(
TAG,
@@ -352,14 +356,17 @@ public class AudioSharingDialogHandler {
} else {
// Build a list of AudioSharingDeviceItem for connected devices other than cachedDevice.
List deviceItems = new ArrayList<>();
- for (List devices : groupedDevices.values()) {
+ for (Map.Entry> entry : groupedDevices.entrySet()) {
+ if (entry.getKey() == groupId) continue;
// Use random device in the group within the sharing session to represent the group.
- CachedBluetoothDevice device = devices.get(0);
- if (BluetoothUtils.getGroupId(device)
- == BluetoothUtils.getGroupId(cachedDevice)) {
- continue;
+ for (BluetoothDevice device : entry.getValue()) {
+ CachedBluetoothDevice cDevice =
+ mDeviceManager != null ? mDeviceManager.findDevice(device) : null;
+ if (cDevice != null) {
+ deviceItems.add(AudioSharingUtils.buildAudioSharingDeviceItem(cDevice));
+ break;
+ }
}
- deviceItems.add(AudioSharingUtils.buildAudioSharingDeviceItem(device));
}
// Show audio sharing join dialog when the second eligible (LE audio) remote
// device connect and no sharing session.
@@ -368,13 +375,10 @@ public class AudioSharingDialogHandler {
new AudioSharingJoinDialogFragment.DialogEventListener() {
@Override
public void onShareClick() {
- mTargetSinks = new ArrayList<>();
- for (List devices :
- groupedDevices.values()) {
- for (CachedBluetoothDevice device : devices) {
- mTargetSinks.add(device.getDevice());
- }
- }
+ mTargetSinks =
+ groupedDevices.values().stream()
+ .flatMap(items -> items.stream())
+ .collect(toList());
Log.d(TAG, "Start broadcast with sinks = " + mTargetSinks.size());
if (mBroadcast != null) {
mBroadcast.startPrivateBroadcast();
@@ -493,7 +497,7 @@ public class AudioSharingDialogHandler {
}
private void removeSourceForGroup(
- int groupId, Map> groupedDevices) {
+ int groupId, Map> groupedDevices) {
if (mAssistant == null) {
Log.d(TAG, "Fail to add source due to null profiles, group = " + groupId);
return;
@@ -503,8 +507,6 @@ public class AudioSharingDialogHandler {
return;
}
groupedDevices.getOrDefault(groupId, ImmutableList.of()).stream()
- .map(CachedBluetoothDevice::getDevice)
- .filter(Objects::nonNull)
.forEach(
device -> {
for (BluetoothLeBroadcastReceiveState source :
@@ -515,7 +517,7 @@ public class AudioSharingDialogHandler {
}
private void addSourceForGroup(
- int groupId, Map> groupedDevices) {
+ int groupId, Map> groupedDevices) {
if (mBroadcast == null || mAssistant == null) {
Log.d(TAG, "Fail to add source due to null profiles, group = " + groupId);
return;
@@ -525,8 +527,6 @@ public class AudioSharingDialogHandler {
return;
}
groupedDevices.getOrDefault(groupId, ImmutableList.of()).stream()
- .map(CachedBluetoothDevice::getDevice)
- .filter(Objects::nonNull)
.forEach(
device ->
mAssistant.addSource(
diff --git a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingSwitchBarController.java b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingSwitchBarController.java
index 3c0faba5db8..8396e48afd1 100644
--- a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingSwitchBarController.java
+++ b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingSwitchBarController.java
@@ -48,7 +48,6 @@ import com.android.settings.core.BasePreferenceController;
import com.android.settings.overlay.FeatureFactory;
import com.android.settings.widget.SettingsMainSwitchBar;
import com.android.settingslib.bluetooth.BluetoothUtils;
-import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast;
import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
@@ -63,17 +62,15 @@ import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
-import java.util.Objects;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.stream.Collectors;
public class AudioSharingSwitchBarController extends BasePreferenceController
implements DefaultLifecycleObserver,
- OnCheckedChangeListener,
- LocalBluetoothProfileManager.ServiceListener {
- private static final String TAG = "AudioSharingSwitchBarCtl";
+ OnCheckedChangeListener,
+ LocalBluetoothProfileManager.ServiceListener {
+ private static final String TAG = "AudioSharingSwitchCtlr";
private static final String PREF_KEY = "audio_sharing_main_switch";
interface OnAudioSharingStateChangedListener {
@@ -103,7 +100,7 @@ public class AudioSharingSwitchBarController extends BasePreferenceController
private final Executor mExecutor;
private final MetricsFeatureProvider mMetricsFeatureProvider;
private final OnAudioSharingStateChangedListener mListener;
- private Map> mGroupedConnectedDevices = new HashMap<>();
+ private Map> mGroupedConnectedDevices = new HashMap<>();
private List mTargetActiveSinks = new ArrayList<>();
private List mDeviceItemsForSharing = new ArrayList<>();
@VisibleForTesting IntentFilter mIntentFilter;
@@ -341,8 +338,8 @@ public class AudioSharingSwitchBarController extends BasePreferenceController
// FeatureFlagUtils.SETTINGS_NEED_CONNECTED_BLE_DEVICE_FOR_BROADCAST is always true in
// prod. We can turn off the flag for debug purpose.
if (FeatureFlagUtils.isEnabled(
- mContext,
- FeatureFlagUtils.SETTINGS_NEED_CONNECTED_BLE_DEVICE_FOR_BROADCAST)
+ mContext,
+ FeatureFlagUtils.SETTINGS_NEED_CONNECTED_BLE_DEVICE_FOR_BROADCAST)
&& mAssistant.getAllConnectedDevices().isEmpty()) {
// Pop up dialog to ask users to connect at least one lea buds before audio sharing.
AudioSharingUtils.postOnMainThread(
@@ -454,13 +451,11 @@ public class AudioSharingSwitchBarController extends BasePreferenceController
mDeviceItemsForSharing = new ArrayList<>(deviceItems);
mTargetActiveSinks = new ArrayList<>();
if (!deviceItems.isEmpty() && deviceItems.get(0).isActive()) {
- for (CachedBluetoothDevice device :
+ // If active device exists for audio sharing, share to it
+ // automatically once the broadcast is started.
+ mTargetActiveSinks =
mGroupedConnectedDevices.getOrDefault(
- deviceItems.get(0).getGroupId(), ImmutableList.of())) {
- // If active device exists for audio sharing, share to it
- // automatically once the broadcast is started.
- mTargetActiveSinks.add(device.getDevice());
- }
+ deviceItems.get(0).getGroupId(), ImmutableList.of());
mDeviceItemsForSharing.remove(0);
}
if (mBroadcast != null) {
@@ -488,7 +483,7 @@ public class AudioSharingSwitchBarController extends BasePreferenceController
boolean isStateReady =
isBluetoothOn()
&& AudioSharingUtils.isAudioSharingProfileReady(
- mProfileManager);
+ mProfileManager);
AudioSharingUtils.postOnMainThread(
mContext,
() -> {
@@ -541,12 +536,8 @@ public class AudioSharingSwitchBarController extends BasePreferenceController
@Override
public void onItemClick(@NonNull AudioSharingDeviceItem item) {
AudioSharingUtils.addSourceToTargetSinks(
- mGroupedConnectedDevices
- .getOrDefault(item.getGroupId(), ImmutableList.of())
- .stream()
- .map(CachedBluetoothDevice::getDevice)
- .filter(Objects::nonNull)
- .collect(Collectors.toList()),
+ mGroupedConnectedDevices.getOrDefault(
+ item.getGroupId(), ImmutableList.of()),
mBtManager);
mGroupedConnectedDevices.clear();
mDeviceItemsForSharing.clear();
@@ -575,8 +566,8 @@ public class AudioSharingSwitchBarController extends BasePreferenceController
@NonNull ViewGroup host, @NonNull View view, @NonNull AccessibilityEvent event) {
if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED
&& (event.getContentChangeTypes()
- & AccessibilityEvent.CONTENT_CHANGE_TYPE_ENABLED)
- != 0) {
+ & AccessibilityEvent.CONTENT_CHANGE_TYPE_ENABLED)
+ != 0) {
Log.d(TAG, "Skip accessibility event for CONTENT_CHANGE_TYPE_ENABLED");
return false;
}
diff --git a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingUtils.java b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingUtils.java
index 50f9c9a8cc9..0c2dc367171 100644
--- a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingUtils.java
+++ b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingUtils.java
@@ -22,6 +22,8 @@ import static com.android.settings.connecteddevice.audiosharing.AudioSharingUtil
import static com.android.settings.connecteddevice.audiosharing.AudioSharingUtils.MetricKey.METRIC_KEY_SOURCE_PAGE_ID;
import static com.android.settings.connecteddevice.audiosharing.AudioSharingUtils.MetricKey.METRIC_KEY_USER_TRIGGERED;
+import static java.util.stream.Collectors.toList;
+
import android.bluetooth.BluetoothCsipSetCoordinator;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothLeBroadcastMetadata;
@@ -44,10 +46,11 @@ import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
import com.android.settingslib.bluetooth.VolumeControlProfile;
import java.util.ArrayList;
+import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
-import java.util.stream.Collectors;
+import java.util.Objects;
public class AudioSharingUtils {
private static final String TAG = "AudioSharingUtils";
@@ -62,15 +65,15 @@ public class AudioSharingUtils {
}
/**
- * Fetch {@link CachedBluetoothDevice}s connected to the broadcast assistant. The devices are
- * grouped by CSIP group id.
+ * Fetch {@link BluetoothDevice}s connected to the broadcast assistant. The devices are grouped
+ * by CSIP group id.
*
* @param localBtManager The BT manager to provide BT functions.
* @return A map of connected devices grouped by CSIP group id.
*/
- public static Map> fetchConnectedDevicesByGroupId(
+ public static Map> fetchConnectedDevicesByGroupId(
@Nullable LocalBluetoothManager localBtManager) {
- Map> groupedDevices = new HashMap<>();
+ Map> groupedDevices = new HashMap<>();
if (localBtManager == null) {
Log.d(TAG, "Skip fetchConnectedDevicesByGroupId due to bt manager is null");
return groupedDevices;
@@ -99,7 +102,7 @@ public class AudioSharingUtils {
if (!groupedDevices.containsKey(groupId)) {
groupedDevices.put(groupId, new ArrayList<>());
}
- groupedDevices.get(groupId).add(cachedDevice);
+ groupedDevices.get(groupId).add(device);
}
if (DEBUG) {
Log.d(TAG, "fetchConnectedDevicesByGroupId: " + groupedDevices);
@@ -122,11 +125,16 @@ public class AudioSharingUtils {
*/
public static List buildOrderedConnectedLeadDevices(
@Nullable LocalBluetoothManager localBtManager,
- Map> groupedConnectedDevices,
+ Map> groupedConnectedDevices,
boolean filterByInSharing) {
List orderedDevices = new ArrayList<>();
- for (List devices : groupedConnectedDevices.values()) {
- CachedBluetoothDevice leadDevice = getLeadDevice(devices);
+ if (localBtManager == null) {
+ Log.d(TAG, "Skip buildOrderedConnectedLeadDevices due to bt manager is null");
+ return orderedDevices;
+ }
+ CachedBluetoothDeviceManager deviceManager = localBtManager.getCachedDeviceManager();
+ for (List devices : groupedConnectedDevices.values()) {
+ CachedBluetoothDevice leadDevice = getLeadDevice(deviceManager, devices);
if (leadDevice == null) {
Log.d(TAG, "Skip due to no lead device");
continue;
@@ -141,52 +149,39 @@ public class AudioSharingUtils {
}
orderedDevices.add(leadDevice);
}
- orderedDevices.sort(
- (CachedBluetoothDevice d1, CachedBluetoothDevice d2) -> {
- // Active above not inactive
- int comparison =
- (isActiveLeAudioDevice(d2) ? 1 : 0)
- - (isActiveLeAudioDevice(d1) ? 1 : 0);
- if (comparison != 0) return comparison;
- // Bonded above not bonded
- comparison =
- (d2.getBondState() == BluetoothDevice.BOND_BONDED ? 1 : 0)
- - (d1.getBondState() == BluetoothDevice.BOND_BONDED ? 1 : 0);
- if (comparison != 0) return comparison;
- // Bond timestamp available above unavailable
- comparison =
- (d2.getBondTimestamp() != null ? 1 : 0)
- - (d1.getBondTimestamp() != null ? 1 : 0);
- if (comparison != 0) return comparison;
- // Order by bond timestamp if it is available
- // Otherwise order by device name
- return d1.getBondTimestamp() != null
- ? d1.getBondTimestamp().compareTo(d2.getBondTimestamp())
- : d1.getName().compareTo(d2.getName());
- });
+ orderedDevices.sort(sCachedDeviceComparator);
return orderedDevices;
}
/**
* Get the lead device from a list of devices with same group id.
*
+ * @param deviceManager CachedBluetoothDeviceManager
* @param devices A list of devices with same group id.
* @return The lead device
*/
@Nullable
public static CachedBluetoothDevice getLeadDevice(
- @NonNull List devices) {
- if (devices.isEmpty()) return null;
- for (CachedBluetoothDevice device : devices) {
- if (!device.getMemberDevice().isEmpty()) {
- return device;
+ @Nullable CachedBluetoothDeviceManager deviceManager,
+ @NonNull List devices) {
+ if (deviceManager == null || devices.isEmpty()) return null;
+ List cachedDevices =
+ devices.stream()
+ .map(device -> deviceManager.findDevice(device))
+ .filter(Objects::nonNull)
+ .collect(toList());
+ for (CachedBluetoothDevice cachedDevice : cachedDevices) {
+ if (!cachedDevice.getMemberDevice().isEmpty()) {
+ return cachedDevice;
}
}
- CachedBluetoothDevice leadDevice = devices.get(0);
+ CachedBluetoothDevice leadDevice = cachedDevices.isEmpty() ? null : cachedDevices.get(0);
Log.d(
TAG,
"No lead device in the group, pick arbitrary device as the lead: "
- + leadDevice.getDevice().getAnonymizedAddress());
+ + (leadDevice == null
+ ? "null"
+ : leadDevice.getDevice().getAnonymizedAddress()));
return leadDevice;
}
@@ -206,13 +201,13 @@ public class AudioSharingUtils {
@NonNull
public static List buildOrderedConnectedLeadAudioSharingDeviceItem(
@Nullable LocalBluetoothManager localBtManager,
- Map> groupedConnectedDevices,
+ Map> groupedConnectedDevices,
boolean filterByInSharing) {
return buildOrderedConnectedLeadDevices(
localBtManager, groupedConnectedDevices, filterByInSharing)
.stream()
.map(AudioSharingUtils::buildAudioSharingDeviceItem)
- .collect(Collectors.toList());
+ .collect(toList());
}
/** Build {@link AudioSharingDeviceItem} from {@link CachedBluetoothDevice}. */
@@ -361,4 +356,27 @@ public class AudioSharingUtils {
Pair.create(METRIC_KEY_CANDIDATE_DEVICE_COUNT.ordinal(), candidateDeviceCount)
};
}
+
+ private static final Comparator sCachedDeviceComparator =
+ (CachedBluetoothDevice d1, CachedBluetoothDevice d2) -> {
+ // Active above not inactive
+ int comparison =
+ (isActiveLeAudioDevice(d2) ? 1 : 0) - (isActiveLeAudioDevice(d1) ? 1 : 0);
+ if (comparison != 0) return comparison;
+ // Bonded above not bonded
+ comparison =
+ (d2.getBondState() == BluetoothDevice.BOND_BONDED ? 1 : 0)
+ - (d1.getBondState() == BluetoothDevice.BOND_BONDED ? 1 : 0);
+ if (comparison != 0) return comparison;
+ // Bond timestamp available above unavailable
+ comparison =
+ (d2.getBondTimestamp() != null ? 1 : 0)
+ - (d1.getBondTimestamp() != null ? 1 : 0);
+ if (comparison != 0) return comparison;
+ // Order by bond timestamp if it is available
+ // Otherwise order by device name
+ return d1.getBondTimestamp() != null
+ ? d1.getBondTimestamp().compareTo(d2.getBondTimestamp())
+ : d1.getName().compareTo(d2.getName());
+ };
}
diff --git a/src/com/android/settings/network/telephony/MobileNetworkSettingsSearchIndex.kt b/src/com/android/settings/network/telephony/MobileNetworkSettingsSearchIndex.kt
index ca50fd0e758..d1800715302 100644
--- a/src/com/android/settings/network/telephony/MobileNetworkSettingsSearchIndex.kt
+++ b/src/com/android/settings/network/telephony/MobileNetworkSettingsSearchIndex.kt
@@ -23,6 +23,7 @@ import com.android.settings.R
import com.android.settings.network.SubscriptionUtil
import com.android.settings.network.telephony.MmsMessagePreferenceController.Companion.MmsMessageSearchItem
import com.android.settings.network.telephony.NrAdvancedCallingPreferenceController.Companion.NrAdvancedCallingSearchItem
+import com.android.settings.network.telephony.RoamingPreferenceController.Companion.RoamingSearchItem
import com.android.settings.spa.SpaSearchLanding.BundleValue
import com.android.settings.spa.SpaSearchLanding.SpaSearchLandingFragment
import com.android.settings.spa.SpaSearchLanding.SpaSearchLandingKey
@@ -111,6 +112,7 @@ class MobileNetworkSettingsSearchIndex(
fun createSearchItems(context: Context): List =
listOf(
+ RoamingSearchItem(context),
MmsMessageSearchItem(context),
NrAdvancedCallingSearchItem(context),
)
diff --git a/src/com/android/settings/network/telephony/RoamingPreferenceController.kt b/src/com/android/settings/network/telephony/RoamingPreferenceController.kt
index 2529d41324e..7633677dcb4 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.MobileNetworkSettingsSearchItem
import com.android.settings.spa.preference.ComposePreferenceController
import com.android.settingslib.spa.widget.preference.SwitchPreferenceModel
import com.android.settingslib.spaprivileged.model.enterprise.Restrictions
@@ -47,6 +48,7 @@ constructor(
private var telephonyManager = context.getSystemService(TelephonyManager::class.java)!!
private val carrierConfigRepository = CarrierConfigRepository(context)
+ private val roamingSearchItem = RoamingSearchItem(context)
fun init(fragmentManager: FragmentManager, subId: Int) {
this.fragmentManager = fragmentManager
@@ -54,14 +56,8 @@ constructor(
telephonyManager = telephonyManager.createForSubscriptionId(subId)
}
- override fun getAvailabilityStatus(): Int {
- if (!SubscriptionManager.isValidSubscriptionId(subId)) return CONDITIONALLY_UNAVAILABLE
- val isForceHomeNetwork =
- carrierConfigRepository.getBoolean(
- subId, CarrierConfigManager.KEY_FORCE_HOME_NETWORK_BOOL)
-
- return if (isForceHomeNetwork) CONDITIONALLY_UNAVAILABLE else AVAILABLE
- }
+ override fun getAvailabilityStatus() =
+ if (roamingSearchItem.isAvailable(subId)) AVAILABLE else CONDITIONALLY_UNAVAILABLE
@Composable
override fun Content() {
@@ -101,5 +97,17 @@ 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)
+
+ private val carrierConfigRepository = CarrierConfigRepository(context)
+
+ override fun isAvailable(subId: Int): Boolean =
+ SubscriptionManager.isValidSubscriptionId(subId) &&
+ !carrierConfigRepository.getBoolean(
+ subId, CarrierConfigManager.KEY_FORCE_HOME_NETWORK_BOOL)
+ }
}
}
diff --git a/src/com/android/settings/password/PasswordUtils.java b/src/com/android/settings/password/PasswordUtils.java
index a54df94fa90..8c8afc2e9ef 100644
--- a/src/com/android/settings/password/PasswordUtils.java
+++ b/src/com/android/settings/password/PasswordUtils.java
@@ -116,7 +116,7 @@ public final class PasswordUtils extends com.android.settingslib.Utils {
final ViewGroup.MarginLayoutParams lp = new ViewGroup.MarginLayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
- lp.leftMargin = layoutTitleParams.leftMargin;
+ lp.setMarginStart(layoutTitleParams.leftMargin);
lp.topMargin = (int) context.getResources().getDimensionPixelSize(
R.dimen.screen_lock_options_button_margin_top);
optButton.setPadding(0, 0, 0, 0);
diff --git a/src/com/android/settings/privatespace/PrivateProfileCreationRestrictedError.java b/src/com/android/settings/privatespace/PrivateProfileCreationRestrictedError.java
new file mode 100644
index 00000000000..d2bdb8cbe79
--- /dev/null
+++ b/src/com/android/settings/privatespace/PrivateProfileCreationRestrictedError.java
@@ -0,0 +1,99 @@
+/*
+ * 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.privatespace;
+
+import android.app.Activity;
+import android.app.settings.SettingsEnums;
+import android.os.Bundle;
+import android.text.util.Linkify;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import androidx.activity.OnBackPressedCallback;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.android.settings.R;
+import com.android.settings.core.InstrumentedFragment;
+
+import com.google.android.setupcompat.template.FooterBarMixin;
+import com.google.android.setupcompat.template.FooterButton;
+import com.google.android.setupdesign.GlifLayout;
+
+import java.util.regex.Pattern;
+
+public class PrivateProfileCreationRestrictedError extends InstrumentedFragment {
+ private static final String TAG = "PrivateSpaceCreationErr";
+
+ @NonNull
+ @Override
+ public View onCreateView(
+ @NonNull LayoutInflater inflater,
+ @Nullable ViewGroup container,
+ @Nullable Bundle savedInstanceState) {
+ GlifLayout rootView =
+ (GlifLayout)
+ inflater.inflate(R.layout.privatespace_creation_error, container, false);
+ final FooterBarMixin mixin = rootView.getMixin(FooterBarMixin.class);
+ mixin.setPrimaryButton(
+ new FooterButton.Builder(getContext())
+ .setText(R.string.private_space_exit_label)
+ .setListener(onExit())
+ .setButtonType(FooterButton.ButtonType.NEXT)
+ .setTheme(com.google.android.setupdesign.R.style.SudGlifButton_Primary)
+ .build());
+ OnBackPressedCallback callback =
+ new OnBackPressedCallback(true /* enabled by default */) {
+ @Override
+ public void handleOnBackPressed() {
+ // Handle the back button event. We intentionally don't want to allow back
+ // button to work in this screen during the setup flow.
+ }
+ };
+ requireActivity().getOnBackPressedDispatcher().addCallback(this, callback);
+ rootView.setDescriptionText(R.string.private_space_error_description);
+ TextView textView = rootView.getDescriptionTextView();
+ Pattern pattern = Pattern.compile(getString(R.string.private_space_error_causes_text));
+ Linkify.addLinks(
+ textView,
+ pattern,
+ getString(R.string.private_space_learn_more_url));
+
+ return rootView;
+ }
+
+ @Override
+ public int getMetricsCategory() {
+ return SettingsEnums.PRIVATE_SPACE_SETUP_SPACE_CREATION_ERROR;
+ }
+
+ private View.OnClickListener onExit() {
+ return v -> {
+ Activity activity = getActivity();
+ if (activity != null) {
+ mMetricsFeatureProvider.action(
+ getContext(), SettingsEnums.ACTION_PRIVATE_SPACE_SETUP_CANCEL_CREATE_SPACE);
+ Log.i(TAG, "private space setup exited");
+ activity.finish();
+ }
+ };
+ }
+}
+
diff --git a/src/com/android/settings/privatespace/PrivateSpaceCreationFragment.java b/src/com/android/settings/privatespace/PrivateSpaceCreationFragment.java
index ce85d7238cc..0bfedbd394e 100644
--- a/src/com/android/settings/privatespace/PrivateSpaceCreationFragment.java
+++ b/src/com/android/settings/privatespace/PrivateSpaceCreationFragment.java
@@ -29,6 +29,7 @@ import android.net.NetworkInfo;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
+import android.os.UserManager;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
@@ -49,6 +50,7 @@ public class PrivateSpaceCreationFragment extends InstrumentedFragment {
private static final String TAG = "PrivateSpaceCreateFrag";
private static final int PRIVATE_SPACE_CREATE_POST_DELAY_MS = 1000;
private static final int PRIVATE_SPACE_ACCOUNT_LOGIN_POST_DELAY_MS = 5000;
+ private static final int PRIVATE_SPACE_SETUP_NO_ERROR = 0;
private static final Handler sHandler = new Handler(Looper.getMainLooper());
private Runnable mRunnable =
() -> {
@@ -122,6 +124,11 @@ public class PrivateSpaceCreationFragment extends InstrumentedFragment {
Log.i(TAG, "Private Space created");
mMetricsFeatureProvider.action(
getContext(), SettingsEnums.ACTION_PRIVATE_SPACE_SETUP_SPACE_CREATED, true);
+ if (android.multiuser.Flags.showDifferentCreationErrorForUnsupportedDevices()) {
+ mMetricsFeatureProvider.action(
+ getContext(), SettingsEnums.ACTION_PRIVATE_SPACE_SETUP_SPACE_ERRORS,
+ PRIVATE_SPACE_SETUP_NO_ERROR);
+ }
if (isConnectedToInternet()) {
registerReceiver();
sHandler.postDelayed(
@@ -132,8 +139,18 @@ public class PrivateSpaceCreationFragment extends InstrumentedFragment {
}
} else {
mMetricsFeatureProvider.action(
- getContext(), SettingsEnums.ACTION_PRIVATE_SPACE_SETUP_SPACE_CREATED, false);
- showPrivateSpaceErrorScreen();
+ getContext(), SettingsEnums.ACTION_PRIVATE_SPACE_SETUP_SPACE_CREATED,
+ false);
+ if (android.multiuser.Flags.showDifferentCreationErrorForUnsupportedDevices()) {
+ int errorCode = PrivateSpaceMaintainer.getInstance(
+ getActivity()).getPrivateSpaceCreateError();
+ mMetricsFeatureProvider.action(
+ getContext(), SettingsEnums.ACTION_PRIVATE_SPACE_SETUP_SPACE_ERRORS,
+ errorCode);
+ showPrivateSpaceErrorScreen(errorCode);
+ } else {
+ showPrivateSpaceErrorScreen();
+ }
}
}
@@ -147,6 +164,16 @@ public class PrivateSpaceCreationFragment extends InstrumentedFragment {
.navigate(R.id.action_create_profile_error);
}
+ private void showPrivateSpaceErrorScreen(int errorCode) {
+ if (errorCode == UserManager.USER_OPERATION_ERROR_USER_RESTRICTED
+ || errorCode == UserManager.USER_OPERATION_ERROR_PRIVATE_PROFILE) {
+ NavHostFragment.findNavController(PrivateSpaceCreationFragment.this)
+ .navigate(R.id.action_create_profile_error_restrict);
+ } else {
+ showPrivateSpaceErrorScreen();
+ }
+ }
+
/** Returns true if device has an active internet connection, false otherwise. */
private boolean isConnectedToInternet() {
ConnectivityManager cm =
diff --git a/src/com/android/settings/privatespace/PrivateSpaceMaintainer.java b/src/com/android/settings/privatespace/PrivateSpaceMaintainer.java
index ec044daacbf..dd6a4bb6ab4 100644
--- a/src/com/android/settings/privatespace/PrivateSpaceMaintainer.java
+++ b/src/com/android/settings/privatespace/PrivateSpaceMaintainer.java
@@ -60,6 +60,7 @@ public class PrivateSpaceMaintainer {
private final Context mContext;
private final UserManager mUserManager;
private final ActivityManager mActivityManager;
+ private int mErrorCode;
@GuardedBy("this")
private UserHandle mUserHandle;
private final KeyguardManager mKeyguardManager;
@@ -111,6 +112,9 @@ public class PrivateSpaceMaintainer {
userName, USER_TYPE_PROFILE_PRIVATE, new ArraySet<>());
} catch (Exception e) {
Log.e(TAG, "Error creating private space", e);
+ if (android.multiuser.Flags.showDifferentCreationErrorForUnsupportedDevices()) {
+ mErrorCode = ((UserManager.UserOperationException) e).getUserOperationResult();
+ }
return false;
}
@@ -312,6 +316,11 @@ public class PrivateSpaceMaintainer {
return mUserManager.canAddPrivateProfile() || doesPrivateSpaceExist();
}
+ /** Returns the error code for private space creation failure*/
+ public int getPrivateSpaceCreateError() {
+ return mErrorCode;
+ }
+
/** Returns true if private space exists and is running, otherwise returns false */
@VisibleForTesting
synchronized boolean isPrivateProfileRunning() {
diff --git a/src/com/android/settings/wifi/WepNetworksPreferenceController.kt b/src/com/android/settings/wifi/WepNetworksPreferenceController.kt
index 2ce4bcd4d4f..bad7201128c 100644
--- a/src/com/android/settings/wifi/WepNetworksPreferenceController.kt
+++ b/src/com/android/settings/wifi/WepNetworksPreferenceController.kt
@@ -42,6 +42,8 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.asExecutor
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.callbackFlow
+import kotlinx.coroutines.flow.flow
+import kotlinx.coroutines.flow.flowOn
/** Controller that controls whether the WEP network can be connected. */
class WepNetworksPreferenceController(context: Context, preferenceKey: String) :
@@ -49,68 +51,74 @@ class WepNetworksPreferenceController(context: Context, preferenceKey: String) :
var wifiManager = context.getSystemService(WifiManager::class.java)!!
- override fun getAvailabilityStatus() = if (Flags.androidVWifiApi()) AVAILABLE
- else UNSUPPORTED_ON_DEVICE
+ override fun getAvailabilityStatus() =
+ if (Flags.androidVWifiApi()) AVAILABLE else UNSUPPORTED_ON_DEVICE
@Composable
override fun Content() {
- val checked by wepAllowedFlow.flow.collectAsStateWithLifecycle(initialValue = null)
+ val isWepSupported: Boolean? =
+ isWepSupportedFlow.collectAsStateWithLifecycle(initialValue = null).value
+ val isWepAllowed: Boolean? =
+ wepAllowedFlow.flow.collectAsStateWithLifecycle(initialValue = null).value
var openDialog by rememberSaveable { mutableStateOf(false) }
- val wifiInfo = wifiManager.connectionInfo
- SwitchPreference(object : SwitchPreferenceModel {
- override val title = stringResource(R.string.wifi_allow_wep_networks)
- override val summary = { getSummary() }
- override val checked = { checked }
- override val changeable: () -> Boolean
- get() = { carrierAllowed }
- override val onCheckedChange: (Boolean) -> Unit = { newChecked ->
- if (!newChecked && wifiInfo.currentSecurityType == WifiEntry.SECURITY_WEP) {
- openDialog = true
- } else {
- wifiManager.setWepAllowed(newChecked)
- wepAllowedFlow.override(newChecked)
+ SwitchPreference(
+ object : SwitchPreferenceModel {
+ override val title = stringResource(R.string.wifi_allow_wep_networks)
+ override val summary = { getSummary(isWepSupported) }
+ override val checked = {
+ if (isWepSupported == true) isWepAllowed else isWepSupported
}
- }
- })
+ override val changeable: () -> Boolean
+ get() = { isWepSupported == true }
+
+ override val onCheckedChange: (Boolean) -> Unit = { newChecked ->
+ val wifiInfo = wifiManager.connectionInfo
+ if (!newChecked && wifiInfo.currentSecurityType == WifiEntry.SECURITY_WEP) {
+ openDialog = true
+ } else {
+ wifiManager.setWepAllowed(newChecked)
+ wepAllowedFlow.override(newChecked)
+ }
+ }
+ })
if (openDialog) {
SettingsAlertDialogWithIcon(
onDismissRequest = { openDialog = false },
- confirmButton = AlertDialogButton(
- stringResource(R.string.sim_action_yes)
- ) {
- wifiManager.setWepAllowed(false)
- wepAllowedFlow.override(false)
- openDialog = false
- },
+ confirmButton =
+ AlertDialogButton(stringResource(R.string.sim_action_yes)) {
+ wifiManager.setWepAllowed(false)
+ wepAllowedFlow.override(false)
+ openDialog = false
+ },
dismissButton =
- AlertDialogButton(
- stringResource(R.string.wifi_cancel)
- ) { openDialog = false },
+ AlertDialogButton(stringResource(R.string.wifi_cancel)) { openDialog = false },
title = stringResource(R.string.wifi_settings_wep_networks_disconnect_title),
text = {
Text(
stringResource(R.string.wifi_settings_wep_networks_disconnect_summary),
modifier = Modifier.fillMaxWidth(),
- textAlign = TextAlign.Center
+ textAlign = TextAlign.Center,
)
})
}
}
- override fun getSummary(): String = mContext.getString(
- if (carrierAllowed) {
- R.string.wifi_allow_wep_networks_summary
- } else {
- R.string.wifi_allow_wep_networks_summary_carrier_not_allow
- }
- )
+ private fun getSummary(isWepSupported: Boolean?): String =
+ mContext.getString(
+ when (isWepSupported) {
+ true -> R.string.wifi_allow_wep_networks_summary
+ false -> R.string.wifi_allow_wep_networks_summary_carrier_not_allow
+ null -> R.string.summary_placeholder
+ })
- private val carrierAllowed: Boolean
- get() = wifiManager.isWepSupported
+ private val isWepSupportedFlow =
+ flow { emit(wifiManager.isWepSupported) }.flowOn(Dispatchers.Default)
- val wepAllowedFlow = OverridableFlow(callbackFlow {
- wifiManager.queryWepAllowed(Dispatchers.Default.asExecutor(), ::trySend)
+ val wepAllowedFlow =
+ OverridableFlow(
+ callbackFlow {
+ wifiManager.queryWepAllowed(Dispatchers.Default.asExecutor(), ::trySend)
- awaitClose { }
- })
-}
\ No newline at end of file
+ awaitClose {}
+ })
+}
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamConfirmDialogTest.java b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamConfirmDialogTest.java
index e00a146244d..9c83fa6f8ee 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamConfirmDialogTest.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamConfirmDialogTest.java
@@ -23,7 +23,6 @@ import static com.android.settings.connecteddevice.audiosharing.audiostreams.Aud
import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
diff --git a/tests/spa_unit/src/com/android/settings/spa/app/backgroundinstall/BackgroundInstalledAppsPageProviderTest.kt b/tests/spa_unit/src/com/android/settings/spa/app/backgroundinstall/BackgroundInstalledAppsPageProviderTest.kt
index 6a6b91b2922..5ced84b0b5b 100644
--- a/tests/spa_unit/src/com/android/settings/spa/app/backgroundinstall/BackgroundInstalledAppsPageProviderTest.kt
+++ b/tests/spa_unit/src/com/android/settings/spa/app/backgroundinstall/BackgroundInstalledAppsPageProviderTest.kt
@@ -37,45 +37,32 @@ import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.test.runTest
-import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
-import org.mockito.Mock
-import org.mockito.junit.MockitoJUnit
-import org.mockito.junit.MockitoRule
import org.mockito.kotlin.any
import org.mockito.kotlin.argumentCaptor
+import org.mockito.kotlin.doReturn
import org.mockito.kotlin.eq
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.spy
import org.mockito.kotlin.whenever
@RunWith(AndroidJUnit4::class)
class BackgroundInstalledAppsPageProviderTest {
- @get:Rule
- val composeTestRule = createComposeRule()
+ @get:Rule val composeTestRule = createComposeRule()
- @get:Rule
- val mockito: MockitoRule = MockitoJUnit.rule()
+ private val mockPackageManager = mock()
- private val context: Context = ApplicationProvider.getApplicationContext()
+ private val context: Context =
+ spy(ApplicationProvider.getApplicationContext()) {
+ on { packageManager } doReturn mockPackageManager
+ }
- @Mock
- private lateinit var mockContext: Context
-
- @Mock
- private lateinit var mockPackageManager: PackageManager
-
- @Mock
- private lateinit var mockBackgroundInstallControlService: IBackgroundInstallControlService
-
- private var packageInfoFlagsCaptor = argumentCaptor()
+ private val mockBackgroundInstallControlService = mock()
private val fakeNavControllerWrapper = FakeNavControllerWrapper()
- @Before
- fun setup() {
- whenever(mockContext.packageManager).thenReturn(mockPackageManager)
- }
@Test
fun allAppListPageProvider_name() {
assertThat(BackgroundInstalledAppsPageProvider.name)
@@ -108,7 +95,7 @@ class BackgroundInstalledAppsPageProviderTest {
setInjectEntry(false)
- composeTestRule.onNodeWithText("0 apps").assertIsDisplayed()
+ composeTestRule.waitUntilExists(hasText("0 apps"))
}
@Test
@@ -200,7 +187,8 @@ class BackgroundInstalledAppsPageProviderTest {
@Test
fun backgroundInstalledAppsWithGroupingListModel_transform() = runTest {
- val listModel = BackgroundInstalledAppsWithGroupingListModel(mockContext)
+ val packageInfoFlagsCaptor = argumentCaptor()
+ val listModel = BackgroundInstalledAppsWithGroupingListModel(context)
whenever(mockPackageManager.getPackageInfoAsUser(
eq(TEST_PACKAGE_NAME),
packageInfoFlagsCaptor.capture(),
@@ -218,7 +206,7 @@ class BackgroundInstalledAppsPageProviderTest {
@Test
fun backgroundInstalledAppsWithGroupingListModel_filter() = runTest {
- val listModel = BackgroundInstalledAppsWithGroupingListModel(mockContext)
+ val listModel = BackgroundInstalledAppsWithGroupingListModel(context)
listModel.setBackgroundInstallControlService(mockBackgroundInstallControlService)
whenever(mockBackgroundInstallControlService.getBackgroundInstalledPackages(
PackageManager.MATCH_ALL.toLong(),
diff --git a/tests/spa_unit/src/com/android/settings/wifi/WepNetworksPreferenceControllerTest.kt b/tests/spa_unit/src/com/android/settings/wifi/WepNetworksPreferenceControllerTest.kt
index 49e6a171efd..9183096fd7b 100644
--- a/tests/spa_unit/src/com/android/settings/wifi/WepNetworksPreferenceControllerTest.kt
+++ b/tests/spa_unit/src/com/android/settings/wifi/WepNetworksPreferenceControllerTest.kt
@@ -17,6 +17,7 @@
package com.android.settings.wifi
import android.content.Context
+import android.net.wifi.WifiInfo
import android.net.wifi.WifiManager
import androidx.compose.ui.test.assertIsOff
import androidx.compose.ui.test.assertIsOn
@@ -30,7 +31,6 @@ import androidx.preference.PreferenceManager
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.settings.R
-import com.android.settings.dashboard.DashboardFragment
import com.android.settings.spa.preference.ComposePreference
import com.android.settingslib.spa.testutils.onDialogText
import com.android.wifitrackerlib.WifiEntry
@@ -45,29 +45,31 @@ import org.mockito.kotlin.doAnswer
import org.mockito.kotlin.doReturn
import org.mockito.kotlin.mock
import org.mockito.kotlin.spy
+import org.mockito.kotlin.stub
@RunWith(AndroidJUnit4::class)
class WepNetworksPreferenceControllerTest {
- @get:Rule
- val composeTestRule = createComposeRule()
+ @get:Rule val composeTestRule = createComposeRule()
private var wepAllowed = true
- private var mockWifiInfo = mock {
- on { it.currentSecurityType } doReturn WifiEntry.SECURITY_EAP
- on { it.ssid } doReturn SSID
- }
-
- private var mockWifiManager = mock {
- on { queryWepAllowed(any(), any()) } doAnswer {
- @Suppress("UNCHECKED_CAST")
- val consumer = it.arguments[1] as Consumer
- consumer.accept(wepAllowed)
+ private var mockWifiInfo =
+ mock {
+ on { currentSecurityType } doReturn WifiEntry.SECURITY_EAP
+ on { ssid } doReturn SSID
+ }
+
+ private var mockWifiManager =
+ mock {
+ on { queryWepAllowed(any(), any()) } doAnswer
+ {
+ @Suppress("UNCHECKED_CAST") val consumer = it.arguments[1] as Consumer
+ consumer.accept(wepAllowed)
+ }
+ on { isWepSupported } doReturn true
+ on { connectionInfo } doReturn mockWifiInfo
}
- on { it.isWepSupported } doReturn true
- on { it.connectionInfo } doReturn mockWifiInfo
- }
private var context: Context =
spy(ApplicationProvider.getApplicationContext()) {
@@ -85,74 +87,101 @@ class WepNetworksPreferenceControllerTest {
}
@Test
- fun wepAllowedTrue_turnOn() {
+ fun isChecked_wepSupportedAndAllowed_isOn() {
+ mockWifiManager.stub { on { isWepSupported } doReturn true }
wepAllowed = true
- composeTestRule.setContent {
- controller.Content()
- }
- composeTestRule.onNodeWithText(context.getString(R.string.wifi_allow_wep_networks))
+ composeTestRule.setContent { controller.Content() }
+
+ composeTestRule
+ .onNodeWithText(context.getString(R.string.wifi_allow_wep_networks))
.assertIsOn()
}
@Test
- fun wepAllowedFalse_turnOff() {
+ fun isChecked_wepSupportedAndNotAllowed_isOff() {
+ mockWifiManager.stub { on { isWepSupported } doReturn true }
wepAllowed = false
- composeTestRule.setContent {
- controller.Content()
- }
- composeTestRule.onNodeWithText(context.getString(R.string.wifi_allow_wep_networks))
+ composeTestRule.setContent { controller.Content() }
+
+ composeTestRule
+ .onNodeWithText(context.getString(R.string.wifi_allow_wep_networks))
+ .assertIsOff()
+ }
+
+ @Test
+ fun isChecked_wepNotSupportedAndAllowed_isOff() {
+ mockWifiManager.stub { on { isWepSupported } doReturn false }
+ wepAllowed = true
+
+ composeTestRule.setContent { controller.Content() }
+
+ composeTestRule
+ .onNodeWithText(context.getString(R.string.wifi_allow_wep_networks))
+ .assertIsOff()
+ }
+
+ @Test
+ fun isChecked_wepNotSupportedAndNotAllowed_isOff() {
+ mockWifiManager.stub { on { isWepSupported } doReturn false }
+ wepAllowed = false
+
+ composeTestRule.setContent { controller.Content() }
+
+ composeTestRule
+ .onNodeWithText(context.getString(R.string.wifi_allow_wep_networks))
.assertIsOff()
}
@Test
fun onClick_turnOn() {
wepAllowed = false
- composeTestRule.setContent {
- controller.Content()
- }
+ composeTestRule.setContent { controller.Content() }
composeTestRule.onRoot().performClick()
- composeTestRule.onNodeWithText(context.getString(R.string.wifi_allow_wep_networks))
+ composeTestRule
+ .onNodeWithText(context.getString(R.string.wifi_allow_wep_networks))
.assertIsOn()
}
@Test
fun onClick_turnOff() {
wepAllowed = true
- composeTestRule.setContent {
- controller.Content()
- }
+ composeTestRule.setContent { controller.Content() }
composeTestRule.onRoot().performClick()
- composeTestRule.onNodeWithText(context.getString(R.string.wifi_allow_wep_networks))
+ composeTestRule
+ .onNodeWithText(context.getString(R.string.wifi_allow_wep_networks))
.assertIsOff()
}
@Test
fun whenClick_wepAllowed_openDialog() {
wepAllowed = true
- Mockito.`when`(mockWifiInfo.currentSecurityType).thenReturn(WifiEntry.SECURITY_WEP)
- composeTestRule.setContent {
- controller.Content()
+ mockWifiInfo.stub {
+ on { currentSecurityType } doReturn WifiEntry.SECURITY_WEP
}
+ composeTestRule.setContent { controller.Content() }
composeTestRule.onRoot().performClick()
- composeTestRule.onDialogText(context.getString(R.string.wifi_disconnect_button_text))
+ composeTestRule
+ .onDialogText(context.getString(R.string.wifi_disconnect_button_text))
.isDisplayed()
}
@Test
fun whenClick_wepDisallowed_openDialog() {
wepAllowed = false
- Mockito.`when`(mockWifiInfo.currentSecurityType).thenReturn(WifiEntry.SECURITY_WEP)
- composeTestRule.setContent {
- controller.Content()
+ mockWifiInfo.stub {
+ on { currentSecurityType } doReturn WifiEntry.SECURITY_WEP
}
+ composeTestRule.setContent { controller.Content() }
+
composeTestRule.onRoot().performClick()
- composeTestRule.onDialogText(context.getString(R.string.wifi_disconnect_button_text))
+ composeTestRule
+ .onDialogText(context.getString(R.string.wifi_disconnect_button_text))
.isNotDisplayed()
}
@@ -160,4 +189,4 @@ class WepNetworksPreferenceControllerTest {
const val TEST_KEY = "test_key"
const val SSID = "ssid"
}
-}
\ No newline at end of file
+}
diff --git a/tests/unit/src/com/android/settings/localepicker/TermsOfAddressCategoryControllerTest.java b/tests/unit/src/com/android/settings/localepicker/TermsOfAddressCategoryControllerTest.java
index e316b2556c6..b025abdf06a 100644
--- a/tests/unit/src/com/android/settings/localepicker/TermsOfAddressCategoryControllerTest.java
+++ b/tests/unit/src/com/android/settings/localepicker/TermsOfAddressCategoryControllerTest.java
@@ -17,13 +17,11 @@
package com.android.settings.localepicker;
import static com.android.settings.core.BasePreferenceController.AVAILABLE;
-import static com.android.settings.core.BasePreferenceController.CONDITIONALLY_UNAVAILABLE;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.spy;
-import android.app.settings.SettingsEnums;
import android.content.Context;
import android.os.Looper;
@@ -66,14 +64,6 @@ public class TermsOfAddressCategoryControllerTest {
Locale.setDefault(mCacheLocale);
}
- @Test
- public void getAvailabilityStatus_returnUnavailable() {
- Locale.setDefault(Locale.forLanguageTag("fr-CA"));
-
- assertThat(mTermsOfAddressCategoryController.getAvailabilityStatus()).isEqualTo(
- CONDITIONALLY_UNAVAILABLE);
- }
-
@Test
public void getAvailabilityStatus_returnAvailable() {
Locale.setDefault(Locale.forLanguageTag("fr-FR"));