diff --git a/res/values/strings.xml b/res/values/strings.xml
index ac99f2d5160..6d865c21096 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -14360,6 +14360,16 @@ Data usage charges may apply.
No filter is perfect, but this should help hide sexually explicit sites
Allow all sites
+
+ Google Search
+
+ SafeSearch filtering ON
+
+ Helps filter out explicit images, text, and links from search results on this device
+
+ SafeSearch filtering OFF
+
+ Account settings may still filter or blur explicit results
Enter supervision PIN
diff --git a/src/com/android/settings/bluetooth/BluetoothDetailsProfilesController.java b/src/com/android/settings/bluetooth/BluetoothDetailsProfilesController.java
index 58d278704b2..d7f53ca4cb5 100644
--- a/src/com/android/settings/bluetooth/BluetoothDetailsProfilesController.java
+++ b/src/com/android/settings/bluetooth/BluetoothDetailsProfilesController.java
@@ -419,32 +419,7 @@ public class BluetoothDetailsProfilesController extends BluetoothDetailsControll
mContext,
SettingsEnums.ACTION_BLUETOOTH_PROFILE_LE_AUDIO_OFF,
isCurrentDeviceInOrByPassAllowList());
-
- LocalBluetoothProfile asha = mProfileManager.getHearingAidProfile();
- LocalBluetoothProfile broadcastAssistant =
- mProfileManager.getLeAudioBroadcastAssistantProfile();
-
- for (CachedBluetoothDevice leAudioDevice : mProfileDeviceMap.get(profile.toString())) {
- Log.d(TAG,
- "device:" + leAudioDevice.getDevice().getAnonymizedAddress()
- + " disable LE profile");
- profile.setEnabled(leAudioDevice.getDevice(), false);
- if (asha != null) {
- asha.setEnabled(leAudioDevice.getDevice(), true);
- }
- if (broadcastAssistant != null) {
- Log.d(TAG,
- "device:" + leAudioDevice.getDevice().getAnonymizedAddress()
- + " disable LE broadcast assistant profile");
- broadcastAssistant.setEnabled(leAudioDevice.getDevice(), false);
- }
- }
-
- if (!SystemProperties.getBoolean(ENABLE_DUAL_MODE_AUDIO, false)) {
- Log.i(TAG, "Enabling classic audio profiles because dual mode is disabled");
- enableProfileAfterUserDisablesLeAudio(mProfileManager.getA2dpProfile());
- enableProfileAfterUserDisablesLeAudio(mProfileManager.getHeadsetProfile());
- }
+ Utils.setLeAudioEnabled(mManager, List.copyOf(mCachedDeviceGroup), false);
}
/**
@@ -462,75 +437,7 @@ public class BluetoothDetailsProfilesController extends BluetoothDetailsControll
mContext,
SettingsEnums.ACTION_BLUETOOTH_PROFILE_LE_AUDIO_ON,
isCurrentDeviceInOrByPassAllowList());
-
- if (!SystemProperties.getBoolean(ENABLE_DUAL_MODE_AUDIO, false)) {
- Log.i(TAG, "Disabling classic audio profiles because dual mode is disabled");
- disableProfileBeforeUserEnablesLeAudio(mProfileManager.getA2dpProfile());
- disableProfileBeforeUserEnablesLeAudio(mProfileManager.getHeadsetProfile());
- }
- LocalBluetoothProfile asha = mProfileManager.getHearingAidProfile();
- LocalBluetoothProfile broadcastAssistant =
- mProfileManager.getLeAudioBroadcastAssistantProfile();
-
- for (CachedBluetoothDevice leAudioDevice : mProfileDeviceMap.get(profile.toString())) {
- Log.d(TAG,
- "device:" + leAudioDevice.getDevice().getAnonymizedAddress()
- + " enable LE profile");
- profile.setEnabled(leAudioDevice.getDevice(), true);
- if (asha != null) {
- asha.setEnabled(leAudioDevice.getDevice(), false);
- }
- if (broadcastAssistant != null) {
- Log.d(TAG,
- "device:" + leAudioDevice.getDevice().getAnonymizedAddress()
- + " enable LE broadcast assistant profile");
- broadcastAssistant.setEnabled(leAudioDevice.getDevice(), true);
- }
- }
- }
-
- private void disableProfileBeforeUserEnablesLeAudio(LocalBluetoothProfile profile) {
- if (profile != null && mProfileDeviceMap.get(profile.toString()) != null) {
- Log.d(TAG, "Disable " + profile.toString() + " before user enables LE");
- for (CachedBluetoothDevice profileDevice : mProfileDeviceMap.get(profile.toString())) {
- if (profile.isEnabled(profileDevice.getDevice())) {
- Log.d(TAG, "The " + profileDevice.getDevice().getAnonymizedAddress() + ":"
- + profile.toString() + " set disable");
- profile.setEnabled(profileDevice.getDevice(), false);
- } else {
- Log.d(TAG, "The " + profileDevice.getDevice().getAnonymizedAddress() + ":"
- + profile.toString() + " profile is disabled. Do nothing.");
- }
- }
- } else {
- if (profile == null) {
- Log.w(TAG, "profile is null");
- } else {
- Log.w(TAG, profile.toString() + " is not in " + mProfileDeviceMap);
- }
- }
- }
-
- private void enableProfileAfterUserDisablesLeAudio(LocalBluetoothProfile profile) {
- if (profile != null && mProfileDeviceMap.get(profile.toString()) != null) {
- Log.d(TAG, "enable " + profile.toString() + "after user disables LE");
- for (CachedBluetoothDevice profileDevice : mProfileDeviceMap.get(profile.toString())) {
- if (!profile.isEnabled(profileDevice.getDevice())) {
- Log.d(TAG, "The " + profileDevice.getDevice().getAnonymizedAddress() + ":"
- + profile.toString() + " set enable");
- profile.setEnabled(profileDevice.getDevice(), true);
- } else {
- Log.d(TAG, "The " + profileDevice.getDevice().getAnonymizedAddress() + ":"
- + profile.toString() + " profile is enabled. Do nothing.");
- }
- }
- } else {
- if (profile == null) {
- Log.w(TAG, "profile is null");
- } else {
- Log.w(TAG, profile.toString() + " is not in " + mProfileDeviceMap);
- }
- }
+ Utils.setLeAudioEnabled(mManager, List.copyOf(mCachedDeviceGroup), true);
}
/**
diff --git a/src/com/android/settings/bluetooth/BluetoothKeyMissingReceiver.java b/src/com/android/settings/bluetooth/BluetoothKeyMissingReceiver.java
index e7e0b4a100e..cfe9c056d39 100644
--- a/src/com/android/settings/bluetooth/BluetoothKeyMissingReceiver.java
+++ b/src/com/android/settings/bluetooth/BluetoothKeyMissingReceiver.java
@@ -55,9 +55,18 @@ public final class BluetoothKeyMissingReceiver extends BroadcastReceiver {
}
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
+ if (device == null) {
+ return;
+ }
PowerManager powerManager = context.getSystemService(PowerManager.class);
if (TextUtils.equals(action, BluetoothDevice.ACTION_KEY_MISSING)) {
Log.d(TAG, "Receive ACTION_KEY_MISSING");
+ if (device.getBondState() == BluetoothDevice.BOND_NONE) {
+ Log.d(
+ TAG,
+ "Device " + device.getAnonymizedAddress() + " is already unbonded, skip.");
+ return;
+ }
Integer keyMissingCount = BluetoothUtils.getKeyMissingCount(device);
if (keyMissingCount != null && keyMissingCount != 1) {
Log.d(TAG, "Key missing count is " + keyMissingCount + ", skip.");
diff --git a/src/com/android/settings/bluetooth/Utils.java b/src/com/android/settings/bluetooth/Utils.java
index 9f4bb132921..76c3ed0c73b 100644
--- a/src/com/android/settings/bluetooth/Utils.java
+++ b/src/com/android/settings/bluetooth/Utils.java
@@ -28,6 +28,7 @@ import android.content.pm.ActivityInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
+import android.os.SystemProperties;
import android.os.UserHandle;
import android.provider.Settings;
import android.util.Log;
@@ -45,15 +46,20 @@ import com.android.settingslib.bluetooth.BluetoothUtils;
import com.android.settingslib.bluetooth.BluetoothUtils.ErrorListener;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
+import com.android.settingslib.bluetooth.HearingAidProfile;
+import com.android.settingslib.bluetooth.LeAudioProfile;
import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast;
import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.settingslib.bluetooth.LocalBluetoothManager.BluetoothManagerCallback;
+import com.android.settingslib.bluetooth.LocalBluetoothProfile;
+import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
import com.android.settingslib.utils.ThreadUtils;
import com.google.common.base.Supplier;
import com.google.common.collect.ImmutableList;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
@@ -70,6 +76,7 @@ import java.util.stream.Collectors;
public final class Utils {
private static final String TAG = "BluetoothUtils";
+ private static final String ENABLE_DUAL_MODE_AUDIO = "persist.bluetooth.enable_dual_mode_audio";
static final boolean V = BluetoothUtils.V; // verbose logging
static final boolean D = BluetoothUtils.D; // regular logging
@@ -360,4 +367,119 @@ public final class Utils {
dialog.show();
return dialog;
}
+
+ /** Enables/disables LE Audio profile for the device. */
+ public static void setLeAudioEnabled(
+ @NonNull LocalBluetoothManager manager,
+ @NonNull CachedBluetoothDevice cachedDevice,
+ boolean enable) {
+ List devices =
+ List.copyOf(findAllCachedBluetoothDevicesByGroupId(manager, cachedDevice));
+ setLeAudioEnabled(manager, devices, enable);
+ }
+
+ /** Enables/disables LE Audio profile for the devices in the same csip group. */
+ public static void setLeAudioEnabled(
+ @NonNull LocalBluetoothManager manager,
+ @NonNull List devicesWithSameGroupId,
+ boolean enable) {
+ LocalBluetoothProfileManager profileManager = manager.getProfileManager();
+ LeAudioProfile leAudioProfile = profileManager.getLeAudioProfile();
+ List leAudioDevices =
+ getDevicesWithProfile(devicesWithSameGroupId, leAudioProfile);
+ if (leAudioDevices.isEmpty()) {
+ Log.i(TAG, "Fail to setLeAudioEnabled, no LE Audio profile found.");
+ }
+ boolean dualModeEnabled = SystemProperties.getBoolean(ENABLE_DUAL_MODE_AUDIO, false);
+
+ if (enable && !dualModeEnabled) {
+ Log.i(TAG, "Disabling classic audio profiles because dual mode is disabled");
+ setProfileEnabledWhenChangingLeAudio(
+ devicesWithSameGroupId, profileManager.getA2dpProfile(), false);
+ setProfileEnabledWhenChangingLeAudio(
+ devicesWithSameGroupId, profileManager.getHeadsetProfile(), false);
+ }
+
+ HearingAidProfile asha = profileManager.getHearingAidProfile();
+ LocalBluetoothLeBroadcastAssistant broadcastAssistant =
+ profileManager.getLeAudioBroadcastAssistantProfile();
+
+ for (CachedBluetoothDevice leAudioDevice : leAudioDevices) {
+ Log.d(
+ TAG,
+ "device:"
+ + leAudioDevice.getDevice().getAnonymizedAddress()
+ + " set LE profile enabled: "
+ + enable);
+ leAudioProfile.setEnabled(leAudioDevice.getDevice(), enable);
+ if (asha != null) {
+ asha.setEnabled(leAudioDevice.getDevice(), !enable);
+ }
+ if (broadcastAssistant != null) {
+ Log.d(
+ TAG,
+ "device:"
+ + leAudioDevice.getDevice().getAnonymizedAddress()
+ + " enable LE broadcast assistant profile: "
+ + enable);
+ broadcastAssistant.setEnabled(leAudioDevice.getDevice(), enable);
+ }
+ }
+
+ if (!enable && !dualModeEnabled) {
+ Log.i(TAG, "Enabling classic audio profiles because dual mode is disabled");
+ setProfileEnabledWhenChangingLeAudio(
+ devicesWithSameGroupId, profileManager.getA2dpProfile(), true);
+ setProfileEnabledWhenChangingLeAudio(
+ devicesWithSameGroupId, profileManager.getHeadsetProfile(), true);
+ }
+ }
+
+ private static List getDevicesWithProfile(
+ List devices, LocalBluetoothProfile profile) {
+ List devicesWithProfile = new ArrayList<>();
+ for (CachedBluetoothDevice device : devices) {
+ for (LocalBluetoothProfile currentProfile : device.getProfiles()) {
+ if (currentProfile.toString().equals(profile.toString())) {
+ devicesWithProfile.add(device);
+ }
+ }
+ }
+ return devicesWithProfile;
+ }
+
+ private static void setProfileEnabledWhenChangingLeAudio(
+ List devices,
+ @Nullable LocalBluetoothProfile profile,
+ boolean enable) {
+ if (profile == null) {
+ Log.i(TAG, "profile is null");
+ return;
+ }
+ List deviceWithProfile = getDevicesWithProfile(devices, profile);
+ Log.d(TAG, "Set " + profile + " enabled:" + enable + " when switching LE Audio");
+ for (CachedBluetoothDevice profileDevice : deviceWithProfile) {
+ if (profile.isEnabled(profileDevice.getDevice()) != enable) {
+ Log.d(
+ TAG,
+ "The "
+ + profileDevice.getDevice().getAnonymizedAddress()
+ + ":"
+ + profile
+ + " set to "
+ + enable);
+ profile.setEnabled(profileDevice.getDevice(), enable);
+ } else {
+ Log.d(
+ TAG,
+ "The "
+ + profileDevice.getDevice().getAnonymizedAddress()
+ + ":"
+ + profile
+ + " profile is already "
+ + enable
+ + ". Do nothing.");
+ }
+ }
+ }
}
diff --git a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingSwitchBarController.java b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingSwitchBarController.java
index 92ebc57bf52..f1fcd694b0a 100644
--- a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingSwitchBarController.java
+++ b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingSwitchBarController.java
@@ -192,7 +192,7 @@ public class AudioSharingSwitchBarController extends BasePreferenceController
Log.d(TAG, "Skip handleOnBroadcastReady, not in starting process");
return;
}
- handleOnBroadcastReady();
+ handleOnBroadcastReady(metadata);
}
@Override
@@ -273,7 +273,7 @@ public class AudioSharingSwitchBarController extends BasePreferenceController
+ mSinksInAdding);
if (mSinksToWaitFor.contains(sink)) {
mSinksToWaitFor.remove(sink);
- if (mSinksToWaitFor.isEmpty()) {
+ if (mSinksToWaitFor.isEmpty() && mBroadcast != null) {
// To avoid users advance to share then pair flow before the
// primary/active sinks successfully join the audio sharing,
// popup dialog till adding source complete for mSinksToWaitFor.
@@ -284,7 +284,8 @@ public class AudioSharingSwitchBarController extends BasePreferenceController
/* userTriggered= */ false,
/* deviceCountInSharing= */ 1,
/* candidateDeviceCount= */ 0);
- showAudioSharingDialog(eventData);
+ showJoinAudioSharingDialog(eventData,
+ mBroadcast.getLatestBluetoothLeBroadcastMetadata());
}
}
}
@@ -501,9 +502,10 @@ public class AudioSharingSwitchBarController extends BasePreferenceController
mBtManager == null ? null : mBtManager.getCachedDeviceManager();
CachedBluetoothDevice cachedDevice =
deviceManager == null ? null : deviceManager.findDevice(device);
- if (cachedDevice != null) {
+ if (cachedDevice != null && mBroadcast != null) {
Log.d(TAG, "handleAutoAddSourceAfterPair, device = " + device.getAnonymizedAddress());
- addSourceToTargetSinks(ImmutableList.of(device), cachedDevice.getName());
+ addSourceToTargetSinks(ImmutableList.of(device), cachedDevice.getName(),
+ mBroadcast.getLatestBluetoothLeBroadcastMetadata());
}
}
@@ -642,7 +644,7 @@ public class AudioSharingSwitchBarController extends BasePreferenceController
return mAssistant != null && mAssistant.getAllConnectedDevices().isEmpty();
}
- private void handleOnBroadcastReady() {
+ private void handleOnBroadcastReady(@NonNull BluetoothLeBroadcastMetadata metadata) {
List targetActiveSinks = mTargetActiveItem == null ? ImmutableList.of()
: mGroupedConnectedDevices.getOrDefault(
mTargetActiveItem.getGroupId(), ImmutableList.of());
@@ -656,7 +658,7 @@ public class AudioSharingSwitchBarController extends BasePreferenceController
// Auto add primary/active sinks w/o user interactions.
if (!targetActiveSinks.isEmpty() && mTargetActiveItem != null) {
Log.d(TAG, "handleOnBroadcastReady: automatically add source to active sinks.");
- addSourceToTargetSinks(targetActiveSinks, mTargetActiveItem.getName());
+ addSourceToTargetSinks(targetActiveSinks, mTargetActiveItem.getName(), metadata);
// To avoid users advance to share then pair flow before the primary/active sinks
// successfully join the audio sharing, save the primary/active sinks in mSinksToWaitFor
// and popup dialog till adding source complete for these sinks.
@@ -677,7 +679,7 @@ public class AudioSharingSwitchBarController extends BasePreferenceController
AudioSharingDeviceItem target = mDeviceItemsForSharing.get(0);
List targetSinks = mGroupedConnectedDevices.getOrDefault(
target.getGroupId(), ImmutableList.of());
- addSourceToTargetSinks(targetSinks, target.getName());
+ addSourceToTargetSinks(targetSinks, target.getName(), metadata);
cleanUpStatesForStartSharing();
// TODO: Add metric for auto add by intent
return;
@@ -698,20 +700,21 @@ public class AudioSharingSwitchBarController extends BasePreferenceController
// successfully join the audio sharing, popup dialog till adding source complete for
// mSinksToWaitFor.
if (mSinksToWaitFor.isEmpty() && !mStoppingSharing.get()) {
- showAudioSharingDialog(eventData);
+ showJoinAudioSharingDialog(eventData, metadata);
}
}
- private void showAudioSharingDialog(Pair[] eventData) {
+ private void showJoinAudioSharingDialog(Pair[] eventData,
+ @Nullable BluetoothLeBroadcastMetadata metadata) {
if (!BluetoothUtils.isBroadcasting(mBtManager)) {
- Log.d(TAG, "Skip showAudioSharingDialog, broadcast is stopped");
+ Log.d(TAG, "Skip showJoinAudioSharingDialog, broadcast is stopped");
return;
}
AudioSharingDialogFragment.DialogEventListener listener =
new AudioSharingDialogFragment.DialogEventListener() {
@Override
public void onPositiveClick() {
- // Could go to other pages, dismiss the progress dialog.
+ // Could go to other pages (pair new device), dismiss the progress dialog.
dismissProgressDialogIfNeeded();
cleanUpStatesForStartSharing();
}
@@ -720,19 +723,17 @@ public class AudioSharingSwitchBarController extends BasePreferenceController
public void onItemClick(@NonNull AudioSharingDeviceItem item) {
List targetSinks = mGroupedConnectedDevices.getOrDefault(
item.getGroupId(), ImmutableList.of());
- addSourceToTargetSinks(targetSinks, item.getName());
+ addSourceToTargetSinks(targetSinks, item.getName(), metadata);
cleanUpStatesForStartSharing();
}
@Override
public void onCancelClick() {
- // Could go to other pages, dismiss the progress dialog.
+ // Could go to other pages (show qr code), dismiss the progress dialog.
dismissProgressDialogIfNeeded();
cleanUpStatesForStartSharing();
}
};
- BluetoothLeBroadcastMetadata metadata = mBroadcast == null ? null
- : mBroadcast.getLatestBluetoothLeBroadcastMetadata();
AudioSharingUtils.postOnMainThread(
mContext,
() -> AudioSharingDialogFragment.show(
@@ -828,13 +829,27 @@ public class AudioSharingSwitchBarController extends BasePreferenceController
});
}
- private void addSourceToTargetSinks(List targetActiveSinks,
- @NonNull String sinkName) {
- mSinksInAdding.addAll(targetActiveSinks);
+ private void addSourceToTargetSinks(List targetGroupedSinks,
+ @NonNull String targetSinkName, @Nullable BluetoothLeBroadcastMetadata metadata) {
+ if (targetGroupedSinks.isEmpty()) {
+ Log.d(TAG, "Skip addSourceToTargetSinks, no sinks.");
+ return;
+ }
+ if (metadata == null) {
+ Log.d(TAG, "Skip addSourceToTargetSinks, metadata is null");
+ return;
+ }
+ if (mAssistant == null) {
+ Log.d(TAG, "skip addSourceToTargetDevices, assistant profile is null.");
+ return;
+ }
+ mSinksInAdding.addAll(targetGroupedSinks);
String progressMessage = mContext.getString(
- R.string.audio_sharing_progress_dialog_add_source_content, sinkName);
+ R.string.audio_sharing_progress_dialog_add_source_content, targetSinkName);
showProgressDialog(progressMessage);
- AudioSharingUtils.addSourceToTargetSinks(targetActiveSinks, mBtManager);
+ for (BluetoothDevice sink : targetGroupedSinks) {
+ mAssistant.addSource(sink, metadata, /* isGroupOp= */ false);
+ }
}
private void showProgressDialog(@NonNull String progressMessage) {
diff --git a/src/com/android/settings/contract/SettingsContract.kt b/src/com/android/settings/contract/SettingsContract.kt
index 3a354194eb6..20ff0c0cbcc 100644
--- a/src/com/android/settings/contract/SettingsContract.kt
+++ b/src/com/android/settings/contract/SettingsContract.kt
@@ -69,6 +69,12 @@ const val KEY_SCREEN_ATTENTION = "screen_attention"
/** Contract key for the "Use adaptive connectivity" setting. */
const val KEY_ADAPTIVE_CONNECTIVITY = "adaptive_connectivity"
+/** Contract key for the "Auto-switch Wi-Fi to Cellular" setting. */
+const val KEY_ADAPTIVE_WIFI_SCORER = "adaptive_wifi_scorer"
+
+/** Contract key for the " Auto-switch mobile network for battery life" setting. */
+const val KEY_ADAPTIVE_MOBILE_NETWORK = "adaptive_mobile_network"
+
/** Contract key for the "WiFi hotspot" setting. */
const val KEY_WIFI_HOTSPOT = "enable_wifi_ap"
diff --git a/src/com/android/settings/deviceinfo/PhoneNumberPreferenceController.java b/src/com/android/settings/deviceinfo/PhoneNumberPreferenceController.java
index b49d62d444f..bb39d88245c 100644
--- a/src/com/android/settings/deviceinfo/PhoneNumberPreferenceController.java
+++ b/src/com/android/settings/deviceinfo/PhoneNumberPreferenceController.java
@@ -65,9 +65,10 @@ public class PhoneNumberPreferenceController extends BasePreferenceController {
@Override
public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen);
- if (!SubscriptionUtil.isSimHardwareVisible(mContext)) {
+ if (!isAvailable()) {
return;
}
+
final Preference preference = screen.findPreference(getPreferenceKey());
final PreferenceCategory category = screen.findPreference(KEY_PREFERENCE_CATEGORY);
mPreferenceList.add(preference);
diff --git a/src/com/android/settings/display/DeviceStateAutoRotateSettingController.java b/src/com/android/settings/display/DeviceStateAutoRotateSettingController.java
index d3950ee1396..5c2dec21810 100644
--- a/src/com/android/settings/display/DeviceStateAutoRotateSettingController.java
+++ b/src/com/android/settings/display/DeviceStateAutoRotateSettingController.java
@@ -35,7 +35,6 @@ import com.android.settings.core.TogglePreferenceController;
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import com.android.settingslib.devicestate.DeviceStateAutoRotateSettingManager;
-import com.android.settingslib.devicestate.DeviceStateRotationLockSettingsManager;
import com.android.settingslib.search.SearchIndexableRaw;
import java.util.List;
@@ -46,7 +45,7 @@ public class DeviceStateAutoRotateSettingController extends TogglePreferenceCont
private TwoStatePreference mPreference;
- private final DeviceStateRotationLockSettingsManager mAutoRotateSettingsManager;
+ private final DeviceStateAutoRotateSettingManager mAutoRotateSettingsManager;
private final int mOrder;
private final DeviceStateAutoRotateSettingManager.DeviceStateAutoRotateSettingListener
mDeviceStateAutoRotateSettingListener = () -> updateState(mPreference);
@@ -62,7 +61,8 @@ public class DeviceStateAutoRotateSettingController extends TogglePreferenceCont
mMetricsFeatureProvider = metricsFeatureProvider;
mDeviceState = deviceState;
mDeviceStateDescription = deviceStateDescription;
- mAutoRotateSettingsManager = DeviceStateRotationLockSettingsManager.getInstance(context);
+ mAutoRotateSettingsManager =
+ DeviceStateAutoRotateSettingManagerProvider.getSingletonInstance(context);
mOrder = order;
}
diff --git a/src/com/android/settings/display/DeviceStateAutoRotateSettingManagerProvider.kt b/src/com/android/settings/display/DeviceStateAutoRotateSettingManagerProvider.kt
new file mode 100644
index 00000000000..906ffe4b566
--- /dev/null
+++ b/src/com/android/settings/display/DeviceStateAutoRotateSettingManagerProvider.kt
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2025 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.display
+
+import android.content.Context
+import android.hardware.devicestate.DeviceStateManager
+import android.os.Build
+import android.os.Handler
+import android.os.Looper
+import com.android.internal.annotations.VisibleForTesting
+import com.android.settingslib.devicestate.AndroidSecureSettings
+import com.android.settingslib.devicestate.DeviceStateAutoRotateSettingManager
+import com.android.settingslib.devicestate.DeviceStateAutoRotateSettingManagerProvider.createInstance
+import com.android.settingslib.devicestate.PosturesHelper
+import com.android.settingslib.utils.ThreadUtils
+import com.android.window.flags.Flags
+
+/**
+ * Provides appropriate instance of [DeviceStateAutoRotateSettingManager], based on the value of
+ * [Flags.FLAG_ENABLE_DEVICE_STATE_AUTO_ROTATE_SETTING_REFACTOR].
+ */
+object DeviceStateAutoRotateSettingManagerProvider {
+ private var nullableSingletonSettingManager: DeviceStateAutoRotateSettingManager? = null
+
+ /**
+ * Provides a singleton instance of [DeviceStateAutoRotateSettingManager], based on the
+ * value of[Flags.FLAG_ENABLE_DEVICE_STATE_AUTO_ROTATE_SETTING_REFACTOR]. It is supposed to
+ * be used by apps that don't support dagger to provide and manager instance.
+ */
+ @JvmStatic
+ fun getSingletonInstance(context: Context) =
+ nullableSingletonSettingManager ?: createInstance(
+ context,
+ ThreadUtils.getBackgroundExecutor(),
+ AndroidSecureSettings(context.contentResolver),
+ Handler(Looper.getMainLooper()),
+ PosturesHelper(context, context.getSystemService(DeviceStateManager::class.java))
+ ).also {
+ nullableSingletonSettingManager = it
+ }
+
+ /** Resets the singleton instance of [DeviceStateAutoRotateSettingManager]. */
+ @JvmStatic
+ @VisibleForTesting
+ fun resetInstance() {
+ nullableSingletonSettingManager = null
+ }
+}
diff --git a/src/com/android/settings/display/DeviceStateAutoRotationHelper.java b/src/com/android/settings/display/DeviceStateAutoRotationHelper.java
index 3bf9def2316..7b285248e1c 100644
--- a/src/com/android/settings/display/DeviceStateAutoRotationHelper.java
+++ b/src/com/android/settings/display/DeviceStateAutoRotationHelper.java
@@ -16,6 +16,8 @@
package com.android.settings.display;
+import static com.android.settingslib.devicestate.DeviceStateAutoRotateSettingUtils.isDeviceStateRotationLockEnabled;
+
import android.content.Context;
import android.util.Log;
@@ -25,7 +27,6 @@ import com.android.internal.view.RotationPolicy;
import com.android.settings.R;
import com.android.settings.core.BasePreferenceController;
import com.android.settingslib.core.AbstractPreferenceController;
-import com.android.settingslib.devicestate.DeviceStateRotationLockSettingsManager;
import com.android.settingslib.devicestate.SettableDeviceState;
import com.android.settingslib.search.SearchIndexableRaw;
@@ -51,8 +52,8 @@ public class DeviceStateAutoRotationHelper {
static ImmutableList createPreferenceControllers(
Context context) {
- List settableDeviceStates = DeviceStateRotationLockSettingsManager
- .getInstance(context).getSettableDeviceStates();
+ List settableDeviceStates = DeviceStateAutoRotateSettingManagerProvider
+ .getSingletonInstance(context).getSettableDeviceStates();
int numDeviceStates = settableDeviceStates.size();
if (numDeviceStates == 0) {
return ImmutableList.of();
@@ -99,7 +100,7 @@ public class DeviceStateAutoRotationHelper {
/** Returns whether the device state based auto-rotation settings are enabled. */
public static boolean isDeviceStateRotationEnabled(Context context) {
return RotationPolicy.isRotationLockToggleVisible(context)
- && DeviceStateRotationLockSettingsManager.isDeviceStateRotationLockEnabled(context);
+ && isDeviceStateRotationLockEnabled(context);
}
/**
@@ -108,6 +109,6 @@ public class DeviceStateAutoRotationHelper {
*/
public static boolean isDeviceStateRotationEnabledForA11y(Context context) {
return RotationPolicy.isRotationSupported(context)
- && DeviceStateRotationLockSettingsManager.isDeviceStateRotationLockEnabled(context);
+ && isDeviceStateRotationLockEnabled(context);
}
}
diff --git a/src/com/android/settings/display/SmartAutoRotateController.java b/src/com/android/settings/display/SmartAutoRotateController.java
index c99b2f853ca..4bc28ff41e0 100644
--- a/src/com/android/settings/display/SmartAutoRotateController.java
+++ b/src/com/android/settings/display/SmartAutoRotateController.java
@@ -47,7 +47,6 @@ import com.android.settings.core.TogglePreferenceController;
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import com.android.settingslib.devicestate.DeviceStateAutoRotateSettingManager;
-import com.android.settingslib.devicestate.DeviceStateRotationLockSettingsManager;
/**
* SmartAutoRotateController controls whether auto rotation is enabled
@@ -75,7 +74,7 @@ public class SmartAutoRotateController extends TogglePreferenceController implem
}
};
- private final DeviceStateRotationLockSettingsManager mDeviceStateAutoRotateSettingsManager;
+ private final DeviceStateAutoRotateSettingManager mDeviceStateAutoRotateSettingsManager;
private final DeviceStateAutoRotateSettingManager.DeviceStateAutoRotateSettingListener
mDeviceStateAutoRotateSettingListener = () -> updateState(mPreference);
private RotationPolicy.RotationPolicyListener mRotationPolicyListener;
@@ -85,8 +84,9 @@ public class SmartAutoRotateController extends TogglePreferenceController implem
mMetricsFeatureProvider = FeatureFactory.getFeatureFactory().getMetricsFeatureProvider();
mPrivacyManager = SensorPrivacyManager.getInstance(context);
mPowerManager = context.getSystemService(PowerManager.class);
- mDeviceStateAutoRotateSettingsManager = DeviceStateRotationLockSettingsManager.getInstance(
- context);
+ mDeviceStateAutoRotateSettingsManager =
+ DeviceStateAutoRotateSettingManagerProvider.getSingletonInstance(
+ context);
}
@Override
diff --git a/src/com/android/settings/network/telephony/satellite/SatelliteSettingsPreferenceCategoryController.java b/src/com/android/settings/network/telephony/satellite/SatelliteSettingsPreferenceCategoryController.java
index f2fb347852c..d0cb1bcc5ca 100644
--- a/src/com/android/settings/network/telephony/satellite/SatelliteSettingsPreferenceCategoryController.java
+++ b/src/com/android/settings/network/telephony/satellite/SatelliteSettingsPreferenceCategoryController.java
@@ -159,6 +159,7 @@ public class SatelliteSettingsPreferenceCategoryController
@Override
public void onResult(Boolean result) {
mIsSatelliteSupported.set(result);
+ Log.d(TAG, "Satellite requestIsSupported : " + result);
SatelliteSettingsPreferenceCategoryController.this.displayPreference();
}
});
diff --git a/src/com/android/settings/supervision/SupervisionSafeSearchPreference.kt b/src/com/android/settings/supervision/SupervisionSafeSearchPreference.kt
new file mode 100644
index 00000000000..617a3451207
--- /dev/null
+++ b/src/com/android/settings/supervision/SupervisionSafeSearchPreference.kt
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2025 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.supervision
+
+import android.content.Context
+import androidx.preference.Preference
+import com.android.settings.R
+import com.android.settingslib.datastore.KeyValueStore
+import com.android.settingslib.datastore.Permissions
+import com.android.settingslib.datastore.SettingsSecureStore
+import com.android.settingslib.metadata.BooleanValuePreference
+import com.android.settingslib.metadata.PreferenceMetadata
+import com.android.settingslib.metadata.ReadWritePermit
+import com.android.settingslib.metadata.SensitivityLevel
+import com.android.settingslib.preference.PreferenceBinding
+import com.android.settingslib.preference.forEachRecursively
+import com.android.settingslib.widget.SelectorWithWidgetPreference
+
+/** Base class of web content filters SafeSearch preferences. */
+sealed class SupervisionSafeSearchPreference :
+ BooleanValuePreference, SelectorWithWidgetPreference.OnClickListener, PreferenceBinding {
+ override fun storage(context: Context): KeyValueStore = SettingsSecureStore.get(context)
+
+ override fun getReadPermissions(context: Context) = Permissions.EMPTY
+
+ override fun getWritePermissions(context: Context) = Permissions.EMPTY
+
+ override fun getReadPermit(context: Context, callingPid: Int, callingUid: Int) =
+ ReadWritePermit.ALLOW
+
+ override fun getWritePermit(
+ context: Context,
+ value: Boolean?,
+ callingPid: Int,
+ callingUid: Int,
+ ) = ReadWritePermit.DISALLOW
+
+ override val sensitivityLevel
+ get() = SensitivityLevel.NO_SENSITIVITY
+
+ override fun createWidget(context: Context) = SelectorWithWidgetPreference(context)
+
+ override fun onRadioButtonClicked(emiter: SelectorWithWidgetPreference) {
+ emiter.parent?.forEachRecursively {
+ if (it is SelectorWithWidgetPreference) {
+ it.isChecked = it == emiter
+ }
+ }
+ }
+
+ override fun bind(preference: Preference, metadata: PreferenceMetadata) {
+ super.bind(preference, metadata)
+ (preference as SelectorWithWidgetPreference).also {
+ // TODO(b/401568995): Set the isChecked value using stored values.
+ it.isChecked = (it.key == SupervisionSearchFilterOffPreference.KEY)
+ it.setOnClickListener(this)
+ }
+ }
+}
+
+/** The SafeSearch filter on preference. */
+class SupervisionSearchFilterOnPreference : SupervisionSafeSearchPreference() {
+
+ override val key
+ get() = KEY
+
+ override val title
+ get() = R.string.supervision_web_content_filters_search_filter_on_title
+
+ override val summary
+ get() = R.string.supervision_web_content_filters_search_filter_on_summary
+
+ companion object {
+ const val KEY = "web_content_filters_search_filter_on"
+ }
+}
+
+/** The SafeSearch filter off preference. */
+class SupervisionSearchFilterOffPreference : SupervisionSafeSearchPreference() {
+
+ override val key
+ get() = KEY
+
+ override val title
+ get() = R.string.supervision_web_content_filters_search_filter_off_title
+
+ override val summary
+ get() = R.string.supervision_web_content_filters_search_filter_off_summary
+
+ companion object {
+ const val KEY = "web_content_filters_search_filter_off"
+ }
+}
diff --git a/src/com/android/settings/supervision/SupervisionSafeSitesDataStore.kt b/src/com/android/settings/supervision/SupervisionSafeSitesDataStore.kt
new file mode 100644
index 00000000000..4f283b8c22c
--- /dev/null
+++ b/src/com/android/settings/supervision/SupervisionSafeSitesDataStore.kt
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2025 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.supervision
+
+import android.content.Context
+import android.provider.Settings.Secure.BROWSER_CONTENT_FILTERS_ENABLED
+import com.android.settingslib.datastore.AbstractKeyedDataObservable
+import com.android.settingslib.datastore.HandlerExecutor
+import com.android.settingslib.datastore.KeyValueStore
+import com.android.settingslib.datastore.KeyedObserver
+import com.android.settingslib.datastore.SettingsSecureStore
+import com.android.settingslib.datastore.SettingsStore
+
+/** Datastore of the safe sites preference. */
+@Suppress("UNCHECKED_CAST")
+class SupervisionSafeSitesDataStore(
+ private val context: Context,
+ private val settingsStore: SettingsStore = SettingsSecureStore.get(context),
+) : AbstractKeyedDataObservable(), KeyedObserver, KeyValueStore {
+
+ override fun contains(key: String) =
+ key == SupervisionBlockExplicitSitesPreference.KEY ||
+ key == SupervisionAllowAllSitesPreference.KEY
+
+ override fun getValue(key: String, valueType: Class): T? {
+ val settingValue = (settingsStore.getBoolean(BROWSER_CONTENT_FILTERS_ENABLED) == true)
+ return when (key) {
+ SupervisionAllowAllSitesPreference.KEY -> !settingValue
+
+ SupervisionBlockExplicitSitesPreference.KEY -> settingValue
+
+ else -> null
+ }
+ as T?
+ }
+
+ override fun setValue(key: String, valueType: Class, value: T?) {
+ if (value !is Boolean) return
+ when (key) {
+ SupervisionAllowAllSitesPreference.KEY ->
+ settingsStore.setBoolean(BROWSER_CONTENT_FILTERS_ENABLED, !value)
+
+ SupervisionBlockExplicitSitesPreference.KEY ->
+ settingsStore.setBoolean(BROWSER_CONTENT_FILTERS_ENABLED, value)
+ }
+ }
+
+ override fun onFirstObserverAdded() {
+ // observe the underlying storage key
+ settingsStore.addObserver(BROWSER_CONTENT_FILTERS_ENABLED, this, HandlerExecutor.main)
+ }
+
+ override fun onKeyChanged(key: String, reason: Int) {
+ // forward data change to preference hierarchy key
+ notifyChange(SupervisionBlockExplicitSitesPreference.KEY, reason)
+ notifyChange(SupervisionAllowAllSitesPreference.KEY, reason)
+ }
+
+ override fun onLastObserverRemoved() {
+ settingsStore.removeObserver(BROWSER_CONTENT_FILTERS_ENABLED, this)
+ }
+}
diff --git a/src/com/android/settings/supervision/SupervisionSafeSitesPreference.kt b/src/com/android/settings/supervision/SupervisionSafeSitesPreference.kt
index aaa5a333a86..d78afb299ac 100644
--- a/src/com/android/settings/supervision/SupervisionSafeSitesPreference.kt
+++ b/src/com/android/settings/supervision/SupervisionSafeSitesPreference.kt
@@ -18,9 +18,7 @@ package com.android.settings.supervision
import android.content.Context
import androidx.preference.Preference
import com.android.settings.R
-import com.android.settingslib.datastore.KeyValueStore
import com.android.settingslib.datastore.Permissions
-import com.android.settingslib.datastore.SettingsSecureStore
import com.android.settingslib.metadata.BooleanValuePreference
import com.android.settingslib.metadata.PreferenceMetadata
import com.android.settingslib.metadata.ReadWritePermit
@@ -30,9 +28,10 @@ import com.android.settingslib.preference.forEachRecursively
import com.android.settingslib.widget.SelectorWithWidgetPreference
/** Base class of web content filters Safe sites preferences. */
-sealed class SupervisionSafeSitesPreference :
- BooleanValuePreference, SelectorWithWidgetPreference.OnClickListener, PreferenceBinding {
- override fun storage(context: Context): KeyValueStore = SettingsSecureStore.get(context)
+sealed class SupervisionSafeSitesPreference(
+ protected val dataStore: SupervisionSafeSitesDataStore
+) : BooleanValuePreference, SelectorWithWidgetPreference.OnClickListener, PreferenceBinding {
+ override fun storage(context: Context) = dataStore
override fun getReadPermissions(context: Context) = Permissions.EMPTY
@@ -64,15 +63,15 @@ sealed class SupervisionSafeSitesPreference :
override fun bind(preference: Preference, metadata: PreferenceMetadata) {
super.bind(preference, metadata)
(preference as SelectorWithWidgetPreference).also {
- // TODO(b/401568468): Set the isChecked value using stored values.
- it.isChecked = (it.key == SupervisionAllowAllSitesPreference.KEY)
+ it.isChecked = (dataStore.getBoolean(it.key) == true)
it.setOnClickListener(this)
}
}
}
/** The "Try to block explicit sites" preference. */
-class SupervisionBlockExplicitSitesPreference : SupervisionSafeSitesPreference() {
+class SupervisionBlockExplicitSitesPreference(dataStore: SupervisionSafeSitesDataStore) :
+ SupervisionSafeSitesPreference(dataStore) {
override val key
get() = KEY
@@ -89,7 +88,8 @@ class SupervisionBlockExplicitSitesPreference : SupervisionSafeSitesPreference()
}
/** The "Allow all sites" preference. */
-class SupervisionAllowAllSitesPreference : SupervisionSafeSitesPreference() {
+class SupervisionAllowAllSitesPreference(dataStore: SupervisionSafeSitesDataStore) :
+ SupervisionSafeSitesPreference(dataStore) {
override val key
get() = KEY
diff --git a/src/com/android/settings/supervision/SupervisionWebContentFiltersScreen.kt b/src/com/android/settings/supervision/SupervisionWebContentFiltersScreen.kt
index 0a2891b5c5e..994165a8b36 100644
--- a/src/com/android/settings/supervision/SupervisionWebContentFiltersScreen.kt
+++ b/src/com/android/settings/supervision/SupervisionWebContentFiltersScreen.kt
@@ -47,14 +47,23 @@ class SupervisionWebContentFiltersScreen : PreferenceScreenCreator {
R.string.supervision_web_content_filters_browser_title,
) +=
{
- +SupervisionBlockExplicitSitesPreference()
- +SupervisionAllowAllSitesPreference()
+ val dataStore = SupervisionSafeSitesDataStore(context)
+ +SupervisionBlockExplicitSitesPreference(dataStore)
+ +SupervisionAllowAllSitesPreference(dataStore)
+ }
+ +PreferenceCategory(
+ SEARCH_RADIO_BUTTON_GROUP,
+ R.string.supervision_web_content_filters_search_title,
+ ) +=
+ {
+ +SupervisionSearchFilterOnPreference()
+ +SupervisionSearchFilterOffPreference()
}
- // TODO(b/401569571) implement the SafeSearch group.
}
companion object {
const val KEY = "supervision_web_content_filters"
internal const val BROWSER_RADIO_BUTTON_GROUP = "browser_radio_button_group"
+ internal const val SEARCH_RADIO_BUTTON_GROUP = "search_radio_button_group"
}
}
diff --git a/tests/robotests/src/com/android/settings/accessibility/LockScreenRotationPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/LockScreenRotationPreferenceControllerTest.java
index c98ad3df5a3..88623ac6889 100644
--- a/tests/robotests/src/com/android/settings/accessibility/LockScreenRotationPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/LockScreenRotationPreferenceControllerTest.java
@@ -16,9 +16,14 @@
package com.android.settings.accessibility;
+import static com.android.settings.testutils.DeviceStateAutoRotateSettingTestUtils.setDeviceStateRotationLockEnabled;
+
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.when;
+
import android.content.Context;
+import android.content.res.Resources;
import android.os.UserHandle;
import android.provider.Settings;
@@ -26,12 +31,14 @@ import androidx.preference.SwitchPreference;
import com.android.internal.view.RotationPolicy;
import com.android.settings.core.BasePreferenceController;
-import com.android.settings.testutils.shadow.ShadowDeviceStateRotationLockSettingsManager;
import com.android.settings.testutils.shadow.ShadowRotationPolicy;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
@@ -41,48 +48,45 @@ import org.robolectric.annotation.Config;
com.android.settings.testutils.shadow.ShadowSystemSettings.class,
})
public class LockScreenRotationPreferenceControllerTest {
-
+ @Mock
+ private Resources mResources;
private Context mContext;
private SwitchPreference mPreference;
private LockScreenRotationPreferenceController mController;
@Before
public void setUp() {
- mContext = RuntimeEnvironment.application;
+ MockitoAnnotations.initMocks(this);
+ mContext = Mockito.spy(RuntimeEnvironment.application);
mPreference = new SwitchPreference(mContext);
+ when(mContext.getResources()).thenReturn(mResources);
+
mController = new LockScreenRotationPreferenceController(mContext, "lock_screen");
}
@Test
- @Config(shadows = {
- ShadowRotationPolicy.class,
- ShadowDeviceStateRotationLockSettingsManager.class
- })
+ @Config(shadows = {ShadowRotationPolicy.class})
public void getAvailabilityStatus_supportedRotation_shouldReturnAvailable() {
ShadowRotationPolicy.setRotationSupported(true /* supported */);
+ setDeviceStateRotationLockEnabled(false, mResources);
assertThat(mController.getAvailabilityStatus()).isEqualTo(
BasePreferenceController.AVAILABLE);
}
@Test
- @Config(shadows = {
- ShadowRotationPolicy.class,
- ShadowDeviceStateRotationLockSettingsManager.class
- })
+ @Config(shadows = {ShadowRotationPolicy.class})
public void getAvailabilityStatus_deviceStateRotationEnabled_returnsUnsupported() {
ShadowRotationPolicy.setRotationSupported(true /* supported */);
- ShadowDeviceStateRotationLockSettingsManager.setDeviceStateRotationLockEnabled(true);
+ setDeviceStateRotationLockEnabled(true, mResources);
assertThat(mController.getAvailabilityStatus()).isEqualTo(
BasePreferenceController.UNSUPPORTED_ON_DEVICE);
}
@Test
- @Config(shadows = {
- ShadowRotationPolicy.class,
- ShadowDeviceStateRotationLockSettingsManager.class
- }) public void getAvailabilityStatus_unsupportedRotation_shouldReturnUnsupportedOnDevice() {
+ @Config(shadows = {ShadowRotationPolicy.class})
+ public void getAvailabilityStatus_unsupportedRotation_shouldReturnUnsupportedOnDevice() {
ShadowRotationPolicy.setRotationSupported(false /* supported */);
assertThat(mController.getAvailabilityStatus()).isEqualTo(
diff --git a/tests/robotests/src/com/android/settings/bluetooth/BluetoothKeyMissingReceiverTest.java b/tests/robotests/src/com/android/settings/bluetooth/BluetoothKeyMissingReceiverTest.java
index a183d8d7e68..42d7105c6f3 100644
--- a/tests/robotests/src/com/android/settings/bluetooth/BluetoothKeyMissingReceiverTest.java
+++ b/tests/robotests/src/com/android/settings/bluetooth/BluetoothKeyMissingReceiverTest.java
@@ -127,6 +127,7 @@ public class BluetoothKeyMissingReceiverTest {
public void broadcastReceiver_background_showNotification() {
Intent intent = spy(new Intent(BluetoothDevice.ACTION_KEY_MISSING));
when(intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE)).thenReturn(mBluetoothDevice);
+ when(mBluetoothDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
BluetoothKeyMissingReceiver bluetoothKeyMissingReceiver = getReceiver(intent);
bluetoothKeyMissingReceiver.onReceive(mContext, intent);
@@ -141,6 +142,7 @@ public class BluetoothKeyMissingReceiverTest {
when(mLocalBtManager.isForegroundActivity()).thenReturn(true);
Intent intent = spy(new Intent(BluetoothDevice.ACTION_KEY_MISSING));
when(intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE)).thenReturn(mBluetoothDevice);
+ when(mBluetoothDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
BluetoothKeyMissingReceiver bluetoothKeyMissingReceiver = getReceiver(intent);
bluetoothKeyMissingReceiver.onReceive(mContext, intent);
diff --git a/tests/robotests/src/com/android/settings/bluetooth/UtilsTest.java b/tests/robotests/src/com/android/settings/bluetooth/UtilsTest.java
index 8859ebd97e5..176bfa8f573 100644
--- a/tests/robotests/src/com/android/settings/bluetooth/UtilsTest.java
+++ b/tests/robotests/src/com/android/settings/bluetooth/UtilsTest.java
@@ -18,22 +18,29 @@ package com.android.settings.bluetooth;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.bluetooth.BluetoothCsipSetCoordinator;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothLeBroadcastReceiveState;
import android.content.Context;
+import android.os.SystemProperties;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.testutils.FakeFeatureFactory;
-import com.android.settings.testutils.shadow.ShadowBluetoothUtils;
+import com.android.settingslib.bluetooth.A2dpProfile;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
+import com.android.settingslib.bluetooth.HeadsetProfile;
+import com.android.settingslib.bluetooth.HearingAidProfile;
+import com.android.settingslib.bluetooth.LeAudioProfile;
import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast;
import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
@@ -41,8 +48,8 @@ import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
-import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -52,10 +59,8 @@ import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import org.robolectric.RobolectricTestRunner;
-import org.robolectric.annotation.Config;
@RunWith(RobolectricTestRunner.class)
-@Config(shadows = {ShadowBluetoothUtils.class})
public class UtilsTest {
private static final int METADATA_FAST_PAIR_CUSTOMIZED_FIELDS = 25;
private static final String TEMP_BOND_METADATA =
@@ -73,6 +78,14 @@ public class UtilsTest {
@Mock
private LocalBluetoothLeBroadcastAssistant mAssistant;
@Mock
+ private A2dpProfile mA2dpProfile;
+ @Mock
+ private HeadsetProfile mHeadsetProfile;
+ @Mock
+ private LeAudioProfile mLeAudioProfile;
+ @Mock
+ private HearingAidProfile mHearingAidProfile;
+ @Mock
private CachedBluetoothDeviceManager mDeviceManager;
private MetricsFeatureProvider mMetricsFeatureProvider;
@@ -80,17 +93,14 @@ public class UtilsTest {
@Before
public void setUp() {
mMetricsFeatureProvider = FakeFeatureFactory.setupForTest().getMetricsFeatureProvider();
- ShadowBluetoothUtils.sLocalBluetoothManager = mLocalBtManager;
- mLocalBtManager = Utils.getLocalBtManager(mContext);
when(mLocalBtManager.getProfileManager()).thenReturn(mProfileManager);
when(mLocalBtManager.getCachedDeviceManager()).thenReturn(mDeviceManager);
when(mProfileManager.getLeAudioBroadcastProfile()).thenReturn(mBroadcast);
when(mProfileManager.getLeAudioBroadcastAssistantProfile()).thenReturn(mAssistant);
- }
-
- @After
- public void tearDown() {
- ShadowBluetoothUtils.reset();
+ when(mProfileManager.getA2dpProfile()).thenReturn(mA2dpProfile);
+ when(mProfileManager.getHeadsetProfile()).thenReturn(mHeadsetProfile);
+ when(mProfileManager.getLeAudioProfile()).thenReturn(mLeAudioProfile);
+ when(mProfileManager.getHearingAidProfile()).thenReturn(mHearingAidProfile);
}
@Test
@@ -170,4 +180,148 @@ public class UtilsTest {
when(mAssistant.getAllSources(any())).thenReturn(ImmutableList.of(state));
assertThat(Utils.shouldBlockPairingInAudioSharing(mLocalBtManager)).isTrue();
}
+
+ @Test
+ public void enableLeAudioProfile_multipleDeviceInGroup() {
+ CachedBluetoothDevice cachedDevice1 = mock(CachedBluetoothDevice.class);
+ CachedBluetoothDevice cachedDevice2 = mock(CachedBluetoothDevice.class);
+ CachedBluetoothDevice cachedDevice3 = mock(CachedBluetoothDevice.class);
+ BluetoothDevice device1 = mock(BluetoothDevice.class);
+ BluetoothDevice device2 = mock(BluetoothDevice.class);
+ BluetoothDevice device3 = mock(BluetoothDevice.class);
+ when(cachedDevice1.getDevice()).thenReturn(device1);
+ when(cachedDevice2.getDevice()).thenReturn(device2);
+ when(cachedDevice3.getDevice()).thenReturn(device3);
+ when(cachedDevice1.getMemberDevice()).thenReturn(ImmutableSet.of(cachedDevice2));
+ when(mDeviceManager.getCachedDevicesCopy())
+ .thenReturn(ImmutableList.of(cachedDevice1, cachedDevice3));
+ when(cachedDevice1.getGroupId()).thenReturn(1);
+ when(cachedDevice2.getGroupId()).thenReturn(1);
+ when(cachedDevice3.getGroupId()).thenReturn(2);
+ when(cachedDevice1.getProfiles())
+ .thenReturn(ImmutableList.of(mA2dpProfile, mHeadsetProfile, mLeAudioProfile));
+ when(cachedDevice2.getProfiles()).thenReturn(ImmutableList.of(mLeAudioProfile));
+ when(cachedDevice3.getProfiles())
+ .thenReturn(ImmutableList.of(mA2dpProfile, mHeadsetProfile, mLeAudioProfile));
+
+ Utils.setLeAudioEnabled(mLocalBtManager, cachedDevice2, true);
+
+ verify(mLeAudioProfile).setEnabled(device1, true);
+ verify(mLeAudioProfile).setEnabled(device2, true);
+ verify(mHearingAidProfile).setEnabled(device1, false);
+ verify(mAssistant).setEnabled(device1, true);
+ verify(mLeAudioProfile, never()).setEnabled(eq(device3), anyBoolean());
+ verify(mA2dpProfile, never()).setEnabled(eq(device3), anyBoolean());
+ verify(mHeadsetProfile, never()).setEnabled(eq(device3), anyBoolean());
+ }
+
+ @Test
+ public void enableLeAudioProfile_dualModeEnabled_a2dpAndHfpNotChanged() {
+ SystemProperties.set("persist.bluetooth.enable_dual_mode_audio", "true");
+ CachedBluetoothDevice cachedDevice1 = mock(CachedBluetoothDevice.class);
+ BluetoothDevice device1 = mock(BluetoothDevice.class);
+ when(cachedDevice1.getDevice()).thenReturn(device1);
+ when(cachedDevice1.getGroupId()).thenReturn(BluetoothCsipSetCoordinator.GROUP_ID_INVALID);
+ when(cachedDevice1.getProfiles())
+ .thenReturn(ImmutableList.of(mA2dpProfile, mHeadsetProfile, mLeAudioProfile));
+ when(mA2dpProfile.isEnabled(device1)).thenReturn(true);
+ when(mHeadsetProfile.isEnabled(device1)).thenReturn(true);
+
+ Utils.setLeAudioEnabled(mLocalBtManager, cachedDevice1, true);
+
+ verify(mLeAudioProfile).setEnabled(device1, true);
+ verify(mA2dpProfile, never()).setEnabled(device1, false);
+ verify(mHeadsetProfile, never()).setEnabled(device1, false);
+ }
+
+ @Test
+ public void enableLeAudioProfile_dualModeDisabled_disableA2dpAndHfp() {
+ SystemProperties.set("persist.bluetooth.enable_dual_mode_audio", "false");
+ CachedBluetoothDevice cachedDevice1 = mock(CachedBluetoothDevice.class);
+ BluetoothDevice device1 = mock(BluetoothDevice.class);
+ when(cachedDevice1.getDevice()).thenReturn(device1);
+ when(cachedDevice1.getGroupId()).thenReturn(BluetoothCsipSetCoordinator.GROUP_ID_INVALID);
+ when(cachedDevice1.getProfiles())
+ .thenReturn(ImmutableList.of(mA2dpProfile, mHeadsetProfile, mLeAudioProfile));
+ when(mA2dpProfile.isEnabled(device1)).thenReturn(true);
+ when(mHeadsetProfile.isEnabled(device1)).thenReturn(true);
+
+ Utils.setLeAudioEnabled(mLocalBtManager, cachedDevice1, true);
+
+ verify(mLeAudioProfile).setEnabled(device1, true);
+ verify(mA2dpProfile).setEnabled(device1, false);
+ verify(mHeadsetProfile).setEnabled(device1, false);
+ }
+
+ @Test
+ public void disableLeAudioProfile_multipleDeviceInGroup() {
+ CachedBluetoothDevice cachedDevice1 = mock(CachedBluetoothDevice.class);
+ CachedBluetoothDevice cachedDevice2 = mock(CachedBluetoothDevice.class);
+ CachedBluetoothDevice cachedDevice3 = mock(CachedBluetoothDevice.class);
+ BluetoothDevice device1 = mock(BluetoothDevice.class);
+ BluetoothDevice device2 = mock(BluetoothDevice.class);
+ BluetoothDevice device3 = mock(BluetoothDevice.class);
+ when(cachedDevice1.getDevice()).thenReturn(device1);
+ when(cachedDevice2.getDevice()).thenReturn(device2);
+ when(cachedDevice3.getDevice()).thenReturn(device3);
+ when(cachedDevice1.getMemberDevice()).thenReturn(ImmutableSet.of(cachedDevice2));
+ when(mDeviceManager.getCachedDevicesCopy())
+ .thenReturn(ImmutableList.of(cachedDevice1, cachedDevice3));
+ when(cachedDevice1.getGroupId()).thenReturn(1);
+ when(cachedDevice2.getGroupId()).thenReturn(1);
+ when(cachedDevice3.getGroupId()).thenReturn(2);
+ when(cachedDevice1.getProfiles())
+ .thenReturn(ImmutableList.of(mA2dpProfile, mHeadsetProfile, mLeAudioProfile));
+ when(cachedDevice2.getProfiles()).thenReturn(ImmutableList.of(mLeAudioProfile));
+ when(cachedDevice3.getProfiles())
+ .thenReturn(ImmutableList.of(mA2dpProfile, mHeadsetProfile, mLeAudioProfile));
+
+ Utils.setLeAudioEnabled(mLocalBtManager, cachedDevice2, false);
+
+ verify(mLeAudioProfile).setEnabled(device1, false);
+ verify(mLeAudioProfile).setEnabled(device2, false);
+ verify(mHearingAidProfile).setEnabled(device1, true);
+ verify(mAssistant).setEnabled(device1, false);
+ verify(mLeAudioProfile, never()).setEnabled(eq(device3), anyBoolean());
+ verify(mA2dpProfile, never()).setEnabled(eq(device3), anyBoolean());
+ verify(mHeadsetProfile, never()).setEnabled(eq(device3), anyBoolean());
+ }
+
+ @Test
+ public void disableLeAudioProfile_dualModeEnabled_a2dpAndHfpNotChanged() {
+ SystemProperties.set("persist.bluetooth.enable_dual_mode_audio", "true");
+ CachedBluetoothDevice cachedDevice1 = mock(CachedBluetoothDevice.class);
+ BluetoothDevice device1 = mock(BluetoothDevice.class);
+ when(cachedDevice1.getDevice()).thenReturn(device1);
+ when(cachedDevice1.getGroupId()).thenReturn(BluetoothCsipSetCoordinator.GROUP_ID_INVALID);
+ when(cachedDevice1.getProfiles())
+ .thenReturn(ImmutableList.of(mA2dpProfile, mHeadsetProfile, mLeAudioProfile));
+ when(mA2dpProfile.isEnabled(device1)).thenReturn(false);
+ when(mHeadsetProfile.isEnabled(device1)).thenReturn(false);
+
+ Utils.setLeAudioEnabled(mLocalBtManager, cachedDevice1, false);
+
+ verify(mLeAudioProfile).setEnabled(device1, false);
+ verify(mA2dpProfile, never()).setEnabled(device1, true);
+ verify(mHeadsetProfile, never()).setEnabled(device1, true);
+ }
+
+ @Test
+ public void disableLeAudioProfile_dualModeDisabled_enableA2dpAndHfp() {
+ SystemProperties.set("persist.bluetooth.enable_dual_mode_audio", "false");
+ CachedBluetoothDevice cachedDevice1 = mock(CachedBluetoothDevice.class);
+ BluetoothDevice device1 = mock(BluetoothDevice.class);
+ when(cachedDevice1.getDevice()).thenReturn(device1);
+ when(cachedDevice1.getGroupId()).thenReturn(BluetoothCsipSetCoordinator.GROUP_ID_INVALID);
+ when(cachedDevice1.getProfiles())
+ .thenReturn(ImmutableList.of(mA2dpProfile, mHeadsetProfile, mLeAudioProfile));
+ when(mA2dpProfile.isEnabled(device1)).thenReturn(false);
+ when(mHeadsetProfile.isEnabled(device1)).thenReturn(false);
+
+ Utils.setLeAudioEnabled(mLocalBtManager, cachedDevice1, false);
+
+ verify(mLeAudioProfile).setEnabled(device1, false);
+ verify(mA2dpProfile).setEnabled(device1, true);
+ verify(mHeadsetProfile).setEnabled(device1, true);
+ }
}
diff --git a/tests/robotests/src/com/android/settings/display/DeviceStateAutoRotateDetailsFragmentTest.java b/tests/robotests/src/com/android/settings/display/DeviceStateAutoRotateDetailsFragmentTest.java
index d1c32a2281f..6fce9a83390 100644
--- a/tests/robotests/src/com/android/settings/display/DeviceStateAutoRotateDetailsFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/display/DeviceStateAutoRotateDetailsFragmentTest.java
@@ -39,7 +39,6 @@ import android.hardware.devicestate.DeviceStateManager;
import com.android.settings.R;
import com.android.settingslib.core.AbstractPreferenceController;
-import com.android.settingslib.devicestate.DeviceStateRotationLockSettingsManager;
import org.junit.Before;
import org.junit.Test;
@@ -144,16 +143,15 @@ public class DeviceStateAutoRotateDetailsFragmentTest {
}
private void enableDeviceStateSettableRotationStates(String[] settableStates,
- String[] settableStatesDescriptions) {
+ String[] settableStatesDescriptions) {
when(mResources.getStringArray(
com.android.internal.R.array.config_perDeviceStateRotationLockDefaults)).thenReturn(
settableStates);
when(mResources.getStringArray(
R.array.config_settableAutoRotationDeviceStatesDescriptions)).thenReturn(
settableStatesDescriptions);
- DeviceStateRotationLockSettingsManager.resetInstance();
- DeviceStateRotationLockSettingsManager.getInstance(mContext)
- .resetStateForTesting(mResources);
+ DeviceStateAutoRotateSettingManagerProvider.resetInstance();
+ when(mContext.getResources()).thenReturn(mResources);
}
// Sets up posture mappings for PosturesHelper
diff --git a/tests/robotests/src/com/android/settings/display/DeviceStateAutoRotateOverviewControllerTest.java b/tests/robotests/src/com/android/settings/display/DeviceStateAutoRotateOverviewControllerTest.java
index a5416e70413..4c2c694a4bd 100644
--- a/tests/robotests/src/com/android/settings/display/DeviceStateAutoRotateOverviewControllerTest.java
+++ b/tests/robotests/src/com/android/settings/display/DeviceStateAutoRotateOverviewControllerTest.java
@@ -18,30 +18,48 @@ package com.android.settings.display;
import static com.android.settings.core.BasePreferenceController.AVAILABLE;
import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_DEVICE;
+import static com.android.settings.testutils.DeviceStateAutoRotateSettingTestUtils.setDeviceStateRotationLockEnabled;
import static com.google.common.truth.Truth.assertThat;
-import com.android.settings.testutils.shadow.ShadowDeviceStateRotationLockSettingsManager;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.content.res.Resources;
+
import com.android.settings.testutils.shadow.ShadowRotationPolicy;
+import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
@RunWith(RobolectricTestRunner.class)
-@Config(shadows = {ShadowRotationPolicy.class, ShadowDeviceStateRotationLockSettingsManager.class})
+@Config(shadows = {ShadowRotationPolicy.class})
public class DeviceStateAutoRotateOverviewControllerTest {
+ @Mock
+ private Resources mResources;
+ private DeviceStateAutoRotateOverviewController mController;
- private final DeviceStateAutoRotateOverviewController mController =
- new DeviceStateAutoRotateOverviewController(
- RuntimeEnvironment.application, "device_state_auto_rotate");
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ Context context = Mockito.spy(RuntimeEnvironment.application);
+ when(context.getResources()).thenReturn(mResources);
+
+ mController = new DeviceStateAutoRotateOverviewController(
+ context, "device_state_auto_rotate");
+ }
@Test
public void getAvailabilityStatus_rotationAndDeviceStateRotationEnabled_returnsAvailable() {
ShadowRotationPolicy.setRotationSupported(true);
- ShadowDeviceStateRotationLockSettingsManager.setDeviceStateRotationLockEnabled(true);
+ setDeviceStateRotationLockEnabled(true, mResources);
int availability = mController.getAvailabilityStatus();
@@ -51,7 +69,7 @@ public class DeviceStateAutoRotateOverviewControllerTest {
@Test
public void getAvailabilityStatus_rotationNotSupported_returnsUnsupportedOnDevice() {
ShadowRotationPolicy.setRotationSupported(false);
- ShadowDeviceStateRotationLockSettingsManager.setDeviceStateRotationLockEnabled(true);
+ setDeviceStateRotationLockEnabled(true, mResources);
int availability = mController.getAvailabilityStatus();
@@ -61,7 +79,7 @@ public class DeviceStateAutoRotateOverviewControllerTest {
@Test
public void getAvailabilityStatus_deviceStateRotationNotSupported_returnsUnsupportedOnDevice() {
ShadowRotationPolicy.setRotationSupported(true);
- ShadowDeviceStateRotationLockSettingsManager.setDeviceStateRotationLockEnabled(false);
+ setDeviceStateRotationLockEnabled(false, mResources);
int availability = mController.getAvailabilityStatus();
diff --git a/tests/robotests/src/com/android/settings/display/DeviceStateAutoRotateSettingControllerTest.java b/tests/robotests/src/com/android/settings/display/DeviceStateAutoRotateSettingControllerTest.java
index cb1be85f881..63a4af21e91 100644
--- a/tests/robotests/src/com/android/settings/display/DeviceStateAutoRotateSettingControllerTest.java
+++ b/tests/robotests/src/com/android/settings/display/DeviceStateAutoRotateSettingControllerTest.java
@@ -18,14 +18,17 @@ package com.android.settings.display;
import static com.android.settings.core.BasePreferenceController.AVAILABLE;
import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_DEVICE;
+import static com.android.settings.testutils.DeviceStateAutoRotateSettingTestUtils.setDeviceStateRotationLockEnabled;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
import android.app.settings.SettingsEnums;
import android.content.Context;
+import android.content.res.Resources;
import android.hardware.devicestate.DeviceState;
import android.hardware.devicestate.DeviceStateManager;
@@ -34,10 +37,9 @@ import androidx.preference.PreferenceManager;
import androidx.preference.PreferenceScreen;
import com.android.settings.R;
-import com.android.settings.testutils.shadow.ShadowDeviceStateRotationLockSettingsManager;
import com.android.settings.testutils.shadow.ShadowRotationPolicy;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
-import com.android.settingslib.devicestate.DeviceStateRotationLockSettingsManager;
+import com.android.settingslib.devicestate.DeviceStateAutoRotateSettingManager;
import com.android.settingslib.search.SearchIndexableRaw;
import org.junit.Before;
@@ -54,10 +56,7 @@ import java.util.ArrayList;
import java.util.List;
@RunWith(RobolectricTestRunner.class)
-@Config(shadows = {
- ShadowRotationPolicy.class,
- ShadowDeviceStateRotationLockSettingsManager.class
-})
+@Config(shadows = {ShadowRotationPolicy.class})
public class DeviceStateAutoRotateSettingControllerTest {
private static final DeviceState DEFAULT_DEVICE_STATE = new DeviceState(
@@ -66,10 +65,11 @@ public class DeviceStateAutoRotateSettingControllerTest {
private static final int DEFAULT_ORDER = -10;
private final Context mContext = Mockito.spy(RuntimeEnvironment.application);
- private DeviceStateRotationLockSettingsManager mAutoRotateSettingsManager;
+ private DeviceStateAutoRotateSettingManager mAutoRotateSettingsManager;
@Mock private MetricsFeatureProvider mMetricsFeatureProvider;
@Mock private DeviceStateManager mDeviceStateManager;
+ @Mock private Resources mResources;
private DeviceStateAutoRotateSettingController mController;
@@ -78,11 +78,14 @@ public class DeviceStateAutoRotateSettingControllerTest {
MockitoAnnotations.initMocks(this);
doReturn(mContext).when(mContext).getApplicationContext();
+ when(mContext.getResources()).thenReturn(mResources);
doReturn(mDeviceStateManager).when(mContext).getSystemService(DeviceStateManager.class);
doReturn(List.of(DEFAULT_DEVICE_STATE)).when(
mDeviceStateManager).getSupportedDeviceStates();
+ setDeviceStateRotationLockEnabled(false, mResources);
mAutoRotateSettingsManager =
- DeviceStateRotationLockSettingsManager.getInstance(mContext);
+ DeviceStateAutoRotateSettingManagerProvider.getSingletonInstance(mContext);
+
mController = new DeviceStateAutoRotateSettingController(
mContext,
DEFAULT_DEVICE_STATE.getIdentifier(),
@@ -108,7 +111,7 @@ public class DeviceStateAutoRotateSettingControllerTest {
@Test
public void getAvailabilityStatus_rotationAndDeviceStateRotationEnabled_returnsAvailable() {
ShadowRotationPolicy.setRotationSupported(true);
- ShadowDeviceStateRotationLockSettingsManager.setDeviceStateRotationLockEnabled(true);
+ setDeviceStateRotationLockEnabled(true, mResources);
int availability = mController.getAvailabilityStatus();
@@ -118,7 +121,7 @@ public class DeviceStateAutoRotateSettingControllerTest {
@Test
public void getAvailabilityStatus_deviceStateRotationDisabled_returnsUnsupported() {
ShadowRotationPolicy.setRotationSupported(true);
- ShadowDeviceStateRotationLockSettingsManager.setDeviceStateRotationLockEnabled(false);
+ setDeviceStateRotationLockEnabled(false, mResources);
int availability = mController.getAvailabilityStatus();
@@ -128,7 +131,7 @@ public class DeviceStateAutoRotateSettingControllerTest {
@Test
public void getAvailabilityStatus_rotationDisabled_returnsUnsupported() {
ShadowRotationPolicy.setRotationSupported(false);
- ShadowDeviceStateRotationLockSettingsManager.setDeviceStateRotationLockEnabled(true);
+ setDeviceStateRotationLockEnabled(true, mResources);
int availability = mController.getAvailabilityStatus();
diff --git a/tests/robotests/src/com/android/settings/display/DeviceStateAutoRotateSettingManagerProviderTest.kt b/tests/robotests/src/com/android/settings/display/DeviceStateAutoRotateSettingManagerProviderTest.kt
new file mode 100644
index 00000000000..f2e59c5a005
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/display/DeviceStateAutoRotateSettingManagerProviderTest.kt
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2025 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.display;
+
+import android.content.Context
+import android.content.res.Resources
+import android.hardware.devicestate.DeviceStateManager
+import android.platform.test.annotations.DisableFlags
+import android.platform.test.annotations.EnableFlags
+import android.platform.test.flag.junit.SetFlagsRule
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.internal.R
+import com.android.settingslib.devicestate.DeviceStateAutoRotateSettingManagerImpl
+import com.android.settingslib.devicestate.DeviceStateRotationLockSettingsManager
+import com.android.window.flags.Flags
+import com.google.common.truth.Truth.assertThat
+import org.junit.After
+import org.junit.Before
+import org.junit.Assert.assertNotSame
+import org.junit.Assert.assertSame
+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.Mockito.`when` as whenever
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class DeviceStateAutoRotateSettingManagerProviderTest {
+
+ @get:Rule
+ val setFlagsRule: SetFlagsRule = SetFlagsRule()
+ @get:Rule
+ val rule = MockitoJUnit.rule()
+
+ @Mock
+ private lateinit var mockContext: Context
+ @Mock
+ private lateinit var mockDeviceStateManager: DeviceStateManager
+ @Mock
+ private lateinit var mockResources: Resources
+
+ private val context: Context = ApplicationProvider.getApplicationContext()
+
+ @Before
+ fun setup() {
+ whenever(mockContext.contentResolver).thenReturn(context.contentResolver)
+ whenever(mockContext.getSystemService(DeviceStateManager::class.java)).thenReturn(
+ mockDeviceStateManager
+ )
+ whenever(mockContext.resources).thenReturn(mockResources)
+ whenever(mockResources.getStringArray(R.array.config_perDeviceStateRotationLockDefaults))
+ .thenReturn(arrayOf())
+ }
+
+ @After
+ fun tearDown() {
+ DeviceStateAutoRotateSettingManagerProvider.resetInstance()
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_DEVICE_STATE_AUTO_ROTATE_SETTING_REFACTOR)
+ fun getSingletonInstance_refactorFlagEnabled_returnsRefactoredManager() {
+ val manager = DeviceStateAutoRotateSettingManagerProvider.getSingletonInstance(mockContext)
+
+ assertThat(manager).isInstanceOf(DeviceStateAutoRotateSettingManagerImpl::class.java)
+ }
+
+ @Test
+ @DisableFlags(Flags.FLAG_ENABLE_DEVICE_STATE_AUTO_ROTATE_SETTING_REFACTOR)
+ fun getSingletonInstance_refactorFlagDisabled_returnsLegacyManager() {
+ val manager = DeviceStateAutoRotateSettingManagerProvider.getSingletonInstance(mockContext)
+
+ assertThat(manager).isInstanceOf(DeviceStateRotationLockSettingsManager::class.java)
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_DEVICE_STATE_AUTO_ROTATE_SETTING_REFACTOR)
+ fun getSingletonInstance_resetInstance_returnsNewInstance() {
+ val manager1 = DeviceStateAutoRotateSettingManagerProvider.getSingletonInstance(mockContext)
+ DeviceStateAutoRotateSettingManagerProvider.resetInstance()
+ val manager2 = DeviceStateAutoRotateSettingManagerProvider.getSingletonInstance(mockContext)
+
+ assertNotSame(manager1, manager2)
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_DEVICE_STATE_AUTO_ROTATE_SETTING_REFACTOR)
+ fun getSingletonInstance_getInstanceTwice_returnsSameInstance() {
+ val manager1 = DeviceStateAutoRotateSettingManagerProvider.getSingletonInstance(mockContext)
+ val manager2 = DeviceStateAutoRotateSettingManagerProvider.getSingletonInstance(mockContext)
+
+ assertSame(manager1, manager2)
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/display/SmartAutoRotateControllerTest.java b/tests/robotests/src/com/android/settings/display/SmartAutoRotateControllerTest.java
index e2542b0d55b..a1eb89c249a 100644
--- a/tests/robotests/src/com/android/settings/display/SmartAutoRotateControllerTest.java
+++ b/tests/robotests/src/com/android/settings/display/SmartAutoRotateControllerTest.java
@@ -19,6 +19,7 @@ package com.android.settings.display;
import static com.android.settings.core.BasePreferenceController.AVAILABLE;
import static com.android.settings.core.BasePreferenceController.DISABLED_DEPENDENT_SETTING;
import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_DEVICE;
+import static com.android.settings.testutils.DeviceStateAutoRotateSettingTestUtils.setDeviceStateRotationLockEnabled;
import static com.google.common.truth.Truth.assertThat;
@@ -33,6 +34,7 @@ import android.content.Context;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
+import android.content.res.Resources;
import android.hardware.devicestate.DeviceState;
import android.hardware.devicestate.DeviceStateManager;
import android.os.UserHandle;
@@ -41,11 +43,11 @@ import android.provider.Settings;
import androidx.preference.Preference;
import com.android.settings.testutils.ResolveInfoBuilder;
-import com.android.settings.testutils.shadow.ShadowDeviceStateRotationLockSettingsManager;
+import com.android.settings.testutils.shadow.ShadowDeviceStateAutoRotateSettingManager;
import com.android.settings.testutils.shadow.ShadowRotationPolicy;
import com.android.settings.testutils.shadow.ShadowSensorPrivacyManager;
import com.android.settings.testutils.shadow.ShadowSystemSettings;
-import com.android.settingslib.devicestate.DeviceStateRotationLockSettingsManager;
+import com.android.settingslib.devicestate.DeviceStateAutoRotateSettingManager;
import org.junit.Before;
import org.junit.Test;
@@ -73,17 +75,21 @@ public class SmartAutoRotateControllerTest {
private Preference mPreference;
@Mock
private DeviceStateManager mDeviceStateManager;
+ @Mock
+ private Resources mResources;
private ContentResolver mContentResolver;
- private DeviceStateRotationLockSettingsManager mDeviceStateAutoRotateSettingsManager;
+ private DeviceStateAutoRotateSettingManager mDeviceStateAutoRotateSettingManager;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
final Context context = Mockito.spy(RuntimeEnvironment.application);
mContentResolver = RuntimeEnvironment.application.getContentResolver();
+ mResources = Mockito.spy(RuntimeEnvironment.application.getResources());
when(context.getPackageManager()).thenReturn(mPackageManager);
when(context.getContentResolver()).thenReturn(mContentResolver);
+ when(context.getResources()).thenReturn(mResources);
doReturn(PACKAGE_NAME).when(mPackageManager).getRotationResolverPackageName();
doReturn(PackageManager.PERMISSION_GRANTED).when(mPackageManager).checkPermission(
Manifest.permission.CAMERA, PACKAGE_NAME);
@@ -91,8 +97,9 @@ public class SmartAutoRotateControllerTest {
doReturn(context).when(context).getApplicationContext();
doReturn(mDeviceStateManager).when(context).getSystemService(DeviceStateManager.class);
doReturn(getDeviceStateList()).when(mDeviceStateManager).getSupportedDeviceStates();
- mDeviceStateAutoRotateSettingsManager = DeviceStateRotationLockSettingsManager.getInstance(
- context);
+ setDeviceStateRotationLockEnabled(false, mResources);
+ mDeviceStateAutoRotateSettingManager =
+ DeviceStateAutoRotateSettingManagerProvider.getSingletonInstance(context);
mController = Mockito.spy(new SmartAutoRotateController(context, "test_key"));
when(mController.isCameraLocked()).thenReturn(false);
@@ -144,7 +151,7 @@ public class SmartAutoRotateControllerTest {
@Test
@Config(shadows = {
- ShadowDeviceStateRotationLockSettingsManager.class,
+ ShadowDeviceStateAutoRotateSettingManager.class,
ShadowRotationPolicy.class
})
public void getAvailabilityStatus_deviceStateRotationLocked_returnDisableDependentSetting() {
@@ -158,7 +165,7 @@ public class SmartAutoRotateControllerTest {
@Test
@Config(shadows = {
- ShadowDeviceStateRotationLockSettingsManager.class,
+ ShadowDeviceStateAutoRotateSettingManager.class,
ShadowRotationPolicy.class
})
public void getAvailabilityStatus_deviceStateRotationUnlocked_returnAvailable() {
@@ -182,18 +189,18 @@ public class SmartAutoRotateControllerTest {
private void enableDeviceStateRotation() {
ShadowRotationPolicy.setRotationSupported(true);
- ShadowDeviceStateRotationLockSettingsManager.setDeviceStateRotationLockEnabled(true);
+ setDeviceStateRotationLockEnabled(true, mResources);
}
private void lockDeviceStateRotation() {
- ShadowDeviceStateRotationLockSettingsManager shadowManager =
- Shadow.extract(mDeviceStateAutoRotateSettingsManager);
+ ShadowDeviceStateAutoRotateSettingManager shadowManager =
+ Shadow.extract(mDeviceStateAutoRotateSettingManager);
shadowManager.setRotationLockedForAllStates(true);
}
private void unlockDeviceStateRotation() {
- ShadowDeviceStateRotationLockSettingsManager shadowManager =
- Shadow.extract(mDeviceStateAutoRotateSettingsManager);
+ ShadowDeviceStateAutoRotateSettingManager shadowManager =
+ Shadow.extract(mDeviceStateAutoRotateSettingManager);
shadowManager.setRotationLockedForAllStates(false);
}
diff --git a/tests/robotests/src/com/android/settings/display/SmartAutoRotatePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/display/SmartAutoRotatePreferenceControllerTest.java
index 9f1b5d4357f..1fb4703fc7c 100644
--- a/tests/robotests/src/com/android/settings/display/SmartAutoRotatePreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/display/SmartAutoRotatePreferenceControllerTest.java
@@ -18,6 +18,8 @@ package com.android.settings.display;
import static android.provider.Settings.Secure.CAMERA_AUTOROTATE;
+import static com.android.settings.testutils.DeviceStateAutoRotateSettingTestUtils.setDeviceStateRotationLockEnabled;
+
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
@@ -40,7 +42,6 @@ import com.android.settings.R;
import com.android.settings.core.BasePreferenceController;
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.testutils.ResolveInfoBuilder;
-import com.android.settings.testutils.shadow.ShadowDeviceStateRotationLockSettingsManager;
import com.android.settings.testutils.shadow.ShadowSensorPrivacyManager;
import com.android.settings.testutils.shadow.ShadowSystemSettings;
@@ -57,8 +58,7 @@ import org.robolectric.annotation.Config;
@RunWith(RobolectricTestRunner.class)
@Config(shadows = {
ShadowSystemSettings.class,
- ShadowSensorPrivacyManager.class,
- ShadowDeviceStateRotationLockSettingsManager.class
+ ShadowSensorPrivacyManager.class
})
public class SmartAutoRotatePreferenceControllerTest {
@@ -104,7 +104,7 @@ public class SmartAutoRotatePreferenceControllerTest {
new SmartAutoRotatePreferenceController(mContext, "smart_auto_rotate"));
when(mController.isCameraLocked()).thenReturn(false);
when(mController.isPowerSaveMode()).thenReturn(false);
- ShadowDeviceStateRotationLockSettingsManager.setDeviceStateRotationLockEnabled(false);
+ setDeviceStateRotationLockEnabled(false, mResources);
}
@Test
@@ -213,7 +213,7 @@ public class SmartAutoRotatePreferenceControllerTest {
@Test
public void getAvailabilityStatus_deviceStateRotationEnabled_returnsUnsupported() {
enableAutoRotationPreference();
- ShadowDeviceStateRotationLockSettingsManager.setDeviceStateRotationLockEnabled(true);
+ setDeviceStateRotationLockEnabled(true, mResources);
assertThat(mController.getAvailabilityStatus()).isEqualTo(
BasePreferenceController.UNSUPPORTED_ON_DEVICE);
diff --git a/tests/robotests/src/com/android/settings/display/SmartAutoRotatePreferenceFragmentTest.java b/tests/robotests/src/com/android/settings/display/SmartAutoRotatePreferenceFragmentTest.java
index 16155384cf8..731cffb8719 100644
--- a/tests/robotests/src/com/android/settings/display/SmartAutoRotatePreferenceFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/display/SmartAutoRotatePreferenceFragmentTest.java
@@ -27,6 +27,7 @@ import static android.provider.Settings.Secure.DEVICE_STATE_ROTATION_LOCK_LOCKED
import static com.android.settings.display.SmartAutoRotatePreferenceFragment.AUTO_ROTATE_MAIN_SWITCH_PREFERENCE_KEY;
import static com.android.settings.display.SmartAutoRotatePreferenceFragment.AUTO_ROTATE_SWITCH_PREFERENCE_KEY;
+import static com.android.settings.testutils.DeviceStateAutoRotateSettingTestUtils.setDeviceStateRotationLockEnabled;
import static com.google.common.truth.Truth.assertThat;
@@ -55,10 +56,8 @@ import androidx.preference.Preference;
import com.android.settings.R;
import com.android.settings.SettingsActivity;
import com.android.settings.testutils.ResolveInfoBuilder;
-import com.android.settings.testutils.shadow.ShadowDeviceStateRotationLockSettingsManager;
import com.android.settings.testutils.shadow.ShadowRotationPolicy;
import com.android.settingslib.core.AbstractPreferenceController;
-import com.android.settingslib.devicestate.DeviceStateRotationLockSettingsManager;
import org.junit.Before;
import org.junit.Test;
@@ -75,7 +74,6 @@ import java.util.Set;
@RunWith(RobolectricTestRunner.class)
@Config(shadows = {
com.android.settings.testutils.shadow.ShadowFragment.class,
- ShadowDeviceStateRotationLockSettingsManager.class,
ShadowRotationPolicy.class
})
public class SmartAutoRotatePreferenceFragmentTest {
@@ -174,7 +172,7 @@ public class SmartAutoRotatePreferenceFragmentTest {
@Test
public void createHeader_faceDetectionSupported_switchBarIsEnabled() {
- ShadowDeviceStateRotationLockSettingsManager.setDeviceStateRotationLockEnabled(false);
+ setDeviceStateRotationLockEnabled(false, mResources);
mFragment.createHeader(mActivity);
verify(mRotateMainSwitchPreference, never()).setVisible(false);
@@ -184,7 +182,7 @@ public class SmartAutoRotatePreferenceFragmentTest {
@Test
public void createHeader_deviceStateRotationSupported_switchBarIsDisabled() {
ShadowRotationPolicy.setRotationSupported(true);
- ShadowDeviceStateRotationLockSettingsManager.setDeviceStateRotationLockEnabled(true);
+ setDeviceStateRotationLockEnabled(true, mResources);
mFragment.createHeader(mActivity);
@@ -258,15 +256,14 @@ public class SmartAutoRotatePreferenceFragmentTest {
private void enableDeviceStateSettableRotationStates(
String[] settableStates, String[] settableStatesDescriptions) {
when(mResources.getStringArray(
- com.android.internal.R.array.config_perDeviceStateRotationLockDefaults))
+ com.android.internal.R.array.config_perDeviceStateRotationLockDefaults))
.thenReturn(settableStates);
when(mResources.getStringArray(R.array.config_settableAutoRotationDeviceStatesDescriptions))
.thenReturn(settableStatesDescriptions);
when(mResources.getBoolean(R.bool.config_auto_rotate_face_detection_available))
.thenReturn(true);
- DeviceStateRotationLockSettingsManager.resetInstance();
- DeviceStateRotationLockSettingsManager.getInstance(mContext)
- .resetStateForTesting(mResources);
+ DeviceStateAutoRotateSettingManagerProvider.resetInstance();
+ when(mContext.getResources()).thenReturn(mResources);
}
// Sets up posture mappings for PosturesHelper
diff --git a/tests/robotests/src/com/android/settings/supervision/SupervisionSafeSearchPreferenceTest.kt b/tests/robotests/src/com/android/settings/supervision/SupervisionSafeSearchPreferenceTest.kt
new file mode 100644
index 00000000000..371cca3f2b5
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/supervision/SupervisionSafeSearchPreferenceTest.kt
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2025 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.supervision
+
+import android.content.Context
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.settings.R
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class SupervisionSafeSearchPreferenceTest {
+ private val context: Context = ApplicationProvider.getApplicationContext()
+
+ private val searchFilterOnPreference = SupervisionSearchFilterOnPreference()
+
+ private val searchFilterOffPreference = SupervisionSearchFilterOffPreference()
+
+ @Test
+ fun getTitle_filterOn() {
+ assertThat(searchFilterOnPreference.title)
+ .isEqualTo(R.string.supervision_web_content_filters_search_filter_on_title)
+ }
+
+
+ @Test
+ fun getSummary_filterOn() {
+ assertThat(searchFilterOnPreference.summary)
+ .isEqualTo(R.string.supervision_web_content_filters_search_filter_on_summary)
+ }
+
+ @Test
+ fun getTitle_filterOff() {
+ assertThat(searchFilterOffPreference.title)
+ .isEqualTo(R.string.supervision_web_content_filters_search_filter_off_title)
+ }
+
+ @Test
+ fun getSummary_filterOff() {
+ assertThat(searchFilterOffPreference.summary)
+ .isEqualTo(
+ R.string.supervision_web_content_filters_search_filter_off_summary
+ )
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/supervision/SupervisionSafeSitesPreferenceTest.kt b/tests/robotests/src/com/android/settings/supervision/SupervisionSafeSitesPreferenceTest.kt
index 5be7a1167e4..a3aca69cf32 100644
--- a/tests/robotests/src/com/android/settings/supervision/SupervisionSafeSitesPreferenceTest.kt
+++ b/tests/robotests/src/com/android/settings/supervision/SupervisionSafeSitesPreferenceTest.kt
@@ -16,20 +16,33 @@
package com.android.settings.supervision
import android.content.Context
+import android.provider.Settings
+import android.provider.Settings.Secure.BROWSER_CONTENT_FILTERS_ENABLED
+import android.provider.Settings.SettingNotFoundException
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.settings.R
+import com.android.settingslib.preference.createAndBindWidget
+import com.android.settingslib.widget.SelectorWithWidgetPreference
import com.google.common.truth.Truth.assertThat
+import org.junit.Assert.assertThrows
+import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
class SupervisionSafeSitesPreferenceTest {
private val context: Context = ApplicationProvider.getApplicationContext()
+ private lateinit var dataStore: SupervisionSafeSitesDataStore
+ private lateinit var allowAllSitesPreference: SupervisionAllowAllSitesPreference
+ private lateinit var blockExplicitSitesPreference: SupervisionBlockExplicitSitesPreference
- private val allowAllSitesPreference = SupervisionAllowAllSitesPreference()
-
- private val blockExplicitSitesPreference = SupervisionBlockExplicitSitesPreference()
+ @Before
+ fun setUp() {
+ dataStore = SupervisionSafeSitesDataStore(context)
+ allowAllSitesPreference = SupervisionAllowAllSitesPreference(dataStore)
+ blockExplicitSitesPreference = SupervisionBlockExplicitSitesPreference(dataStore)
+ }
@Test
fun getTitle_allowAllSites() {
@@ -50,4 +63,64 @@ class SupervisionSafeSitesPreferenceTest {
R.string.supervision_web_content_filters_browser_block_explicit_sites_summary
)
}
+
+ @Test
+ fun allowAllSitesIsChecked_whenNoValueIsSet() {
+ assertThrows(SettingNotFoundException::class.java) {
+ Settings.Secure.getInt(context.getContentResolver(), BROWSER_CONTENT_FILTERS_ENABLED)
+ }
+ assertThat(getBlockExplicitSitesWidget().isChecked).isFalse()
+ assertThat(getAllowAllSitesWidget().isChecked).isTrue()
+ }
+
+ @Test
+ fun blockExplicitSitesIsChecked_whenPreviouslyEnabled() {
+ Settings.Secure.putInt(context.getContentResolver(), BROWSER_CONTENT_FILTERS_ENABLED, 1)
+ assertThat(getAllowAllSitesWidget().isChecked).isFalse()
+ assertThat(getBlockExplicitSitesWidget().isChecked).isTrue()
+ }
+
+ @Test
+ fun clickBlockExplicitSites_enablesFilter() {
+ Settings.Secure.putInt(context.getContentResolver(), BROWSER_CONTENT_FILTERS_ENABLED, 0)
+ val blockExplicitSitesWidget = getBlockExplicitSitesWidget()
+ assertThat(blockExplicitSitesWidget.isChecked).isFalse()
+
+ blockExplicitSitesWidget.performClick()
+
+ assertThat(
+ Settings.Secure.getInt(
+ context.getContentResolver(),
+ BROWSER_CONTENT_FILTERS_ENABLED,
+ )
+ )
+ .isEqualTo(1)
+ assertThat(blockExplicitSitesWidget.isChecked).isTrue()
+ }
+
+ @Test
+ fun clickAllowAllSites_disablesFilter() {
+ Settings.Secure.putInt(context.getContentResolver(), BROWSER_CONTENT_FILTERS_ENABLED, 1)
+ val allowAllSitesWidget = getAllowAllSitesWidget()
+ assertThat(allowAllSitesWidget.isChecked).isFalse()
+
+ allowAllSitesWidget.performClick()
+
+ assertThat(
+ Settings.Secure.getInt(
+ context.getContentResolver(),
+ BROWSER_CONTENT_FILTERS_ENABLED,
+ )
+ )
+ .isEqualTo(0)
+ assertThat(allowAllSitesWidget.isChecked).isTrue()
+ }
+
+ private fun getBlockExplicitSitesWidget(): SelectorWithWidgetPreference {
+ return blockExplicitSitesPreference.createAndBindWidget(context)
+ }
+
+ private fun getAllowAllSitesWidget(): SelectorWithWidgetPreference {
+ return allowAllSitesPreference.createAndBindWidget(context)
+ }
}
diff --git a/tests/robotests/src/com/android/settings/supervision/SupervisionWebContentFiltersScreenTest.kt b/tests/robotests/src/com/android/settings/supervision/SupervisionWebContentFiltersScreenTest.kt
index 351cbdeaa19..31bdbd29405 100644
--- a/tests/robotests/src/com/android/settings/supervision/SupervisionWebContentFiltersScreenTest.kt
+++ b/tests/robotests/src/com/android/settings/supervision/SupervisionWebContentFiltersScreenTest.kt
@@ -15,18 +15,32 @@
*/
package com.android.settings.supervision
+import android.app.supervision.flags.Flags
import android.content.Context
+import android.platform.test.annotations.DisableFlags
+import android.platform.test.annotations.EnableFlags
+import android.platform.test.flag.junit.SetFlagsRule
+import androidx.fragment.app.testing.FragmentScenario
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.settings.R
+import com.android.settingslib.widget.SelectorWithWidgetPreference
import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
class SupervisionWebContentFiltersScreenTest {
+ @get:Rule val setFlagsRule = SetFlagsRule()
private val context: Context = ApplicationProvider.getApplicationContext()
- private val supervisionWebContentFiltersScreen = SupervisionWebContentFiltersScreen()
+ private lateinit var supervisionWebContentFiltersScreen: SupervisionWebContentFiltersScreen
+
+ @Before
+ fun setUp() {
+ supervisionWebContentFiltersScreen = SupervisionWebContentFiltersScreen()
+ }
@Test
fun key() {
@@ -39,4 +53,40 @@ class SupervisionWebContentFiltersScreenTest {
assertThat(supervisionWebContentFiltersScreen.title)
.isEqualTo(R.string.supervision_web_content_filters_title)
}
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_WEB_CONTENT_FILTERS_SCREEN)
+ fun flagEnabled() {
+ assertThat(supervisionWebContentFiltersScreen.isFlagEnabled(context)).isTrue()
+ }
+
+ @Test
+ @DisableFlags(Flags.FLAG_ENABLE_WEB_CONTENT_FILTERS_SCREEN)
+ fun flagDisabled() {
+ assertThat(supervisionWebContentFiltersScreen.isFlagEnabled(context)).isFalse()
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_WEB_CONTENT_FILTERS_SCREEN)
+ fun switchSafeSitesPreferences() {
+ FragmentScenario.launchInContainer(supervisionWebContentFiltersScreen.fragmentClass())
+ .onFragment { fragment ->
+ val allowAllSitesPreference =
+ fragment.findPreference(
+ SupervisionAllowAllSitesPreference.KEY
+ )!!
+ val blockExplicitSitesPreference =
+ fragment.findPreference(
+ SupervisionBlockExplicitSitesPreference.KEY
+ )!!
+
+ assertThat(allowAllSitesPreference.isChecked).isTrue()
+ assertThat(blockExplicitSitesPreference.isChecked).isFalse()
+
+ blockExplicitSitesPreference.performClick()
+
+ assertThat(blockExplicitSitesPreference.isChecked).isTrue()
+ assertThat(allowAllSitesPreference.isChecked).isFalse()
+ }
+ }
}
diff --git a/tests/robotests/src/com/android/settings/testutils/DeviceStateAutoRotateSettingTestUtils.java b/tests/robotests/src/com/android/settings/testutils/DeviceStateAutoRotateSettingTestUtils.java
new file mode 100644
index 00000000000..3359b2f9dc5
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/testutils/DeviceStateAutoRotateSettingTestUtils.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2025 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.testutils;
+
+import static org.mockito.Mockito.when;
+
+import android.content.res.Resources;
+
+/**
+ * Helper for testing device state auto rotate setting
+ */
+public class DeviceStateAutoRotateSettingTestUtils {
+
+ /**
+ * Mock {@link mockResources} to return device state auto rotate enabled or disabled based on
+ * value passed for {@link enable}.
+ */
+ public static void setDeviceStateRotationLockEnabled(boolean enable, Resources mockResources) {
+ String[] perDeviceStateRotationLockDefaults = new String[0];
+ if (enable) {
+ perDeviceStateRotationLockDefaults = new String[]{"test_value"};
+ }
+ when(mockResources.getStringArray(
+ com.android.internal.R.array.config_perDeviceStateRotationLockDefaults))
+ .thenReturn(perDeviceStateRotationLockDefaults);
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowDeviceStateRotationLockSettingsManager.java b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowDeviceStateAutoRotateSettingManager.java
similarity index 73%
rename from tests/robotests/src/com/android/settings/testutils/shadow/ShadowDeviceStateRotationLockSettingsManager.java
rename to tests/robotests/src/com/android/settings/testutils/shadow/ShadowDeviceStateAutoRotateSettingManager.java
index ed266e3b23e..b44d79e3acc 100644
--- a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowDeviceStateRotationLockSettingsManager.java
+++ b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowDeviceStateAutoRotateSettingManager.java
@@ -16,28 +16,16 @@
package com.android.settings.testutils.shadow;
-import android.content.Context;
-
import com.android.settingslib.devicestate.DeviceStateRotationLockSettingsManager;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
@Implements(DeviceStateRotationLockSettingsManager.class)
-public class ShadowDeviceStateRotationLockSettingsManager {
+public class ShadowDeviceStateAutoRotateSettingManager {
- private static boolean sDeviceStateRotationLockEnabled;
private boolean mIsRotationLockedForAllStates;
- @Implementation
- public static boolean isDeviceStateRotationLockEnabled(Context context) {
- return sDeviceStateRotationLockEnabled;
- }
-
- public static void setDeviceStateRotationLockEnabled(boolean enabled) {
- sDeviceStateRotationLockEnabled = enabled;
- }
-
@Implementation
public boolean isRotationLockedForAllStates() {
return mIsRotationLockedForAllStates;
diff --git a/tests/robotests/testutils/com/android/settings/testutils/shadow/ShadowBluetoothUtils.java b/tests/robotests/testutils/com/android/settings/testutils/shadow/ShadowBluetoothUtils.java
index 4dca7490e1a..72de74672f6 100644
--- a/tests/robotests/testutils/com/android/settings/testutils/shadow/ShadowBluetoothUtils.java
+++ b/tests/robotests/testutils/com/android/settings/testutils/shadow/ShadowBluetoothUtils.java
@@ -18,24 +18,48 @@ package com.android.settings.testutils.shadow;
import android.content.Context;
+import androidx.annotation.NonNull;
+
import com.android.settings.bluetooth.Utils;
+import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
import org.robolectric.annotation.Resetter;
+import java.util.HashMap;
+import java.util.Map;
+
/** Robolectric shadow for the bluetooth utils. */
@Implements(Utils.class)
public class ShadowBluetoothUtils {
public static LocalBluetoothManager sLocalBluetoothManager;
+ private static final Map sLeAudioState = new HashMap<>();
@Implementation
protected static LocalBluetoothManager getLocalBtManager(Context context) {
return sLocalBluetoothManager;
}
+ /** Sets le audio state for the device. */
+ @Implementation
+ public static void setLeAudioEnabled(
+ @NonNull LocalBluetoothManager manager,
+ @NonNull CachedBluetoothDevice cachedDevice,
+ boolean enable) {
+ sLeAudioState.put(cachedDevice, enable);
+ }
+
+ /** Checks whether le audio is enabled for the device. */
+ public static boolean isLeAudioEnabled(@NonNull CachedBluetoothDevice cachedDevice) {
+ if (sLeAudioState.containsKey(cachedDevice)) {
+ return sLeAudioState.get(cachedDevice);
+ }
+ return false;
+ }
+
/** Resets the local bluetooth manager to null. */
@Resetter
public static void reset() {