Snap for 13235988 from 4bc471f61e to 25Q2-release

Change-Id: Ifc3e397531aca70c7a40287ada0a08b0eb54bb60
This commit is contained in:
Android Build Coastguard Worker
2025-03-18 18:19:10 -07:00
32 changed files with 1089 additions and 235 deletions

View File

@@ -14360,6 +14360,16 @@ Data usage charges may apply.</string>
<string name="supervision_web_content_filters_browser_block_explicit_sites_summary">No filter is perfect, but this should help hide sexually explicit sites</string> <string name="supervision_web_content_filters_browser_block_explicit_sites_summary">No filter is perfect, but this should help hide sexually explicit sites</string>
<!-- Title for web content filters browser category allow all sites option [CHAR LIMIT=60] --> <!-- Title for web content filters browser category allow all sites option [CHAR LIMIT=60] -->
<string name="supervision_web_content_filters_browser_allow_all_sites_title">Allow all sites</string> <string name="supervision_web_content_filters_browser_allow_all_sites_title">Allow all sites</string>
<!-- Title for web content filters search category [CHAR LIMIT=60] -->
<string name="supervision_web_content_filters_search_title">Google Search</string>
<!-- Title for web content filters search category filter on option [CHAR LIMIT=60] -->
<string name="supervision_web_content_filters_search_filter_on_title">SafeSearch filtering ON</string>
<!-- Summary for web content filters search category filter on option [CHAR LIMIT=None] -->
<string name="supervision_web_content_filters_search_filter_on_summary">Helps filter out explicit images, text, and links from search results on this device</string>
<!-- Title for web content filters search category filter off option [CHAR LIMIT=60] -->
<string name="supervision_web_content_filters_search_filter_off_title">SafeSearch filtering OFF</string>
<!-- Summary for web content filters search category filter off option [CHAR LIMIT=None] -->
<string name="supervision_web_content_filters_search_filter_off_summary">Account settings may still filter or blur explicit results</string>
<!-- Generic content description that is attached to the preview illustration at the top of an Accessibility feature toggle page. [CHAR LIMIT=NONE] --> <!-- Generic content description that is attached to the preview illustration at the top of an Accessibility feature toggle page. [CHAR LIMIT=NONE] -->
<!-- Title for supervision PIN verification screen [CHAR LIMIT=60] --> <!-- Title for supervision PIN verification screen [CHAR LIMIT=60] -->
<string name="supervision_full_screen_pin_verification_title">Enter supervision PIN</string> <string name="supervision_full_screen_pin_verification_title">Enter supervision PIN</string>

View File

@@ -419,32 +419,7 @@ public class BluetoothDetailsProfilesController extends BluetoothDetailsControll
mContext, mContext,
SettingsEnums.ACTION_BLUETOOTH_PROFILE_LE_AUDIO_OFF, SettingsEnums.ACTION_BLUETOOTH_PROFILE_LE_AUDIO_OFF,
isCurrentDeviceInOrByPassAllowList()); isCurrentDeviceInOrByPassAllowList());
Utils.setLeAudioEnabled(mManager, List.copyOf(mCachedDeviceGroup), false);
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());
}
} }
/** /**
@@ -462,75 +437,7 @@ public class BluetoothDetailsProfilesController extends BluetoothDetailsControll
mContext, mContext,
SettingsEnums.ACTION_BLUETOOTH_PROFILE_LE_AUDIO_ON, SettingsEnums.ACTION_BLUETOOTH_PROFILE_LE_AUDIO_ON,
isCurrentDeviceInOrByPassAllowList()); isCurrentDeviceInOrByPassAllowList());
Utils.setLeAudioEnabled(mManager, List.copyOf(mCachedDeviceGroup), true);
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);
}
}
} }
/** /**

View File

@@ -55,9 +55,18 @@ public final class BluetoothKeyMissingReceiver extends BroadcastReceiver {
} }
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
if (device == null) {
return;
}
PowerManager powerManager = context.getSystemService(PowerManager.class); PowerManager powerManager = context.getSystemService(PowerManager.class);
if (TextUtils.equals(action, BluetoothDevice.ACTION_KEY_MISSING)) { if (TextUtils.equals(action, BluetoothDevice.ACTION_KEY_MISSING)) {
Log.d(TAG, "Receive 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); Integer keyMissingCount = BluetoothUtils.getKeyMissingCount(device);
if (keyMissingCount != null && keyMissingCount != 1) { if (keyMissingCount != null && keyMissingCount != 1) {
Log.d(TAG, "Key missing count is " + keyMissingCount + ", skip."); Log.d(TAG, "Key missing count is " + keyMissingCount + ", skip.");

View File

@@ -28,6 +28,7 @@ import android.content.pm.ActivityInfo;
import android.content.pm.PackageInfo; import android.content.pm.PackageInfo;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.PackageManager.NameNotFoundException;
import android.os.SystemProperties;
import android.os.UserHandle; import android.os.UserHandle;
import android.provider.Settings; import android.provider.Settings;
import android.util.Log; 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.BluetoothUtils.ErrorListener;
import com.android.settingslib.bluetooth.CachedBluetoothDevice; import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager; 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.LocalBluetoothLeBroadcast;
import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant; import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant;
import com.android.settingslib.bluetooth.LocalBluetoothManager; import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.settingslib.bluetooth.LocalBluetoothManager.BluetoothManagerCallback; 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.android.settingslib.utils.ThreadUtils;
import com.google.common.base.Supplier; import com.google.common.base.Supplier;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
@@ -70,6 +76,7 @@ import java.util.stream.Collectors;
public final class Utils { public final class Utils {
private static final String TAG = "BluetoothUtils"; 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 V = BluetoothUtils.V; // verbose logging
static final boolean D = BluetoothUtils.D; // regular logging static final boolean D = BluetoothUtils.D; // regular logging
@@ -360,4 +367,119 @@ public final class Utils {
dialog.show(); dialog.show();
return dialog; return dialog;
} }
/** Enables/disables LE Audio profile for the device. */
public static void setLeAudioEnabled(
@NonNull LocalBluetoothManager manager,
@NonNull CachedBluetoothDevice cachedDevice,
boolean enable) {
List<CachedBluetoothDevice> 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<CachedBluetoothDevice> devicesWithSameGroupId,
boolean enable) {
LocalBluetoothProfileManager profileManager = manager.getProfileManager();
LeAudioProfile leAudioProfile = profileManager.getLeAudioProfile();
List<CachedBluetoothDevice> 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<CachedBluetoothDevice> getDevicesWithProfile(
List<CachedBluetoothDevice> devices, LocalBluetoothProfile profile) {
List<CachedBluetoothDevice> 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<CachedBluetoothDevice> devices,
@Nullable LocalBluetoothProfile profile,
boolean enable) {
if (profile == null) {
Log.i(TAG, "profile is null");
return;
}
List<CachedBluetoothDevice> 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.");
}
}
}
} }

View File

@@ -192,7 +192,7 @@ public class AudioSharingSwitchBarController extends BasePreferenceController
Log.d(TAG, "Skip handleOnBroadcastReady, not in starting process"); Log.d(TAG, "Skip handleOnBroadcastReady, not in starting process");
return; return;
} }
handleOnBroadcastReady(); handleOnBroadcastReady(metadata);
} }
@Override @Override
@@ -273,7 +273,7 @@ public class AudioSharingSwitchBarController extends BasePreferenceController
+ mSinksInAdding); + mSinksInAdding);
if (mSinksToWaitFor.contains(sink)) { if (mSinksToWaitFor.contains(sink)) {
mSinksToWaitFor.remove(sink); mSinksToWaitFor.remove(sink);
if (mSinksToWaitFor.isEmpty()) { if (mSinksToWaitFor.isEmpty() && mBroadcast != null) {
// To avoid users advance to share then pair flow before the // To avoid users advance to share then pair flow before the
// primary/active sinks successfully join the audio sharing, // primary/active sinks successfully join the audio sharing,
// popup dialog till adding source complete for mSinksToWaitFor. // popup dialog till adding source complete for mSinksToWaitFor.
@@ -284,7 +284,8 @@ public class AudioSharingSwitchBarController extends BasePreferenceController
/* userTriggered= */ false, /* userTriggered= */ false,
/* deviceCountInSharing= */ 1, /* deviceCountInSharing= */ 1,
/* candidateDeviceCount= */ 0); /* candidateDeviceCount= */ 0);
showAudioSharingDialog(eventData); showJoinAudioSharingDialog(eventData,
mBroadcast.getLatestBluetoothLeBroadcastMetadata());
} }
} }
} }
@@ -501,9 +502,10 @@ public class AudioSharingSwitchBarController extends BasePreferenceController
mBtManager == null ? null : mBtManager.getCachedDeviceManager(); mBtManager == null ? null : mBtManager.getCachedDeviceManager();
CachedBluetoothDevice cachedDevice = CachedBluetoothDevice cachedDevice =
deviceManager == null ? null : deviceManager.findDevice(device); deviceManager == null ? null : deviceManager.findDevice(device);
if (cachedDevice != null) { if (cachedDevice != null && mBroadcast != null) {
Log.d(TAG, "handleAutoAddSourceAfterPair, device = " + device.getAnonymizedAddress()); 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(); return mAssistant != null && mAssistant.getAllConnectedDevices().isEmpty();
} }
private void handleOnBroadcastReady() { private void handleOnBroadcastReady(@NonNull BluetoothLeBroadcastMetadata metadata) {
List<BluetoothDevice> targetActiveSinks = mTargetActiveItem == null ? ImmutableList.of() List<BluetoothDevice> targetActiveSinks = mTargetActiveItem == null ? ImmutableList.of()
: mGroupedConnectedDevices.getOrDefault( : mGroupedConnectedDevices.getOrDefault(
mTargetActiveItem.getGroupId(), ImmutableList.of()); mTargetActiveItem.getGroupId(), ImmutableList.of());
@@ -656,7 +658,7 @@ public class AudioSharingSwitchBarController extends BasePreferenceController
// Auto add primary/active sinks w/o user interactions. // Auto add primary/active sinks w/o user interactions.
if (!targetActiveSinks.isEmpty() && mTargetActiveItem != null) { if (!targetActiveSinks.isEmpty() && mTargetActiveItem != null) {
Log.d(TAG, "handleOnBroadcastReady: automatically add source to active sinks."); 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 // 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 // successfully join the audio sharing, save the primary/active sinks in mSinksToWaitFor
// and popup dialog till adding source complete for these sinks. // and popup dialog till adding source complete for these sinks.
@@ -677,7 +679,7 @@ public class AudioSharingSwitchBarController extends BasePreferenceController
AudioSharingDeviceItem target = mDeviceItemsForSharing.get(0); AudioSharingDeviceItem target = mDeviceItemsForSharing.get(0);
List<BluetoothDevice> targetSinks = mGroupedConnectedDevices.getOrDefault( List<BluetoothDevice> targetSinks = mGroupedConnectedDevices.getOrDefault(
target.getGroupId(), ImmutableList.of()); target.getGroupId(), ImmutableList.of());
addSourceToTargetSinks(targetSinks, target.getName()); addSourceToTargetSinks(targetSinks, target.getName(), metadata);
cleanUpStatesForStartSharing(); cleanUpStatesForStartSharing();
// TODO: Add metric for auto add by intent // TODO: Add metric for auto add by intent
return; return;
@@ -698,20 +700,21 @@ public class AudioSharingSwitchBarController extends BasePreferenceController
// successfully join the audio sharing, popup dialog till adding source complete for // successfully join the audio sharing, popup dialog till adding source complete for
// mSinksToWaitFor. // mSinksToWaitFor.
if (mSinksToWaitFor.isEmpty() && !mStoppingSharing.get()) { if (mSinksToWaitFor.isEmpty() && !mStoppingSharing.get()) {
showAudioSharingDialog(eventData); showJoinAudioSharingDialog(eventData, metadata);
} }
} }
private void showAudioSharingDialog(Pair<Integer, Object>[] eventData) { private void showJoinAudioSharingDialog(Pair<Integer, Object>[] eventData,
@Nullable BluetoothLeBroadcastMetadata metadata) {
if (!BluetoothUtils.isBroadcasting(mBtManager)) { if (!BluetoothUtils.isBroadcasting(mBtManager)) {
Log.d(TAG, "Skip showAudioSharingDialog, broadcast is stopped"); Log.d(TAG, "Skip showJoinAudioSharingDialog, broadcast is stopped");
return; return;
} }
AudioSharingDialogFragment.DialogEventListener listener = AudioSharingDialogFragment.DialogEventListener listener =
new AudioSharingDialogFragment.DialogEventListener() { new AudioSharingDialogFragment.DialogEventListener() {
@Override @Override
public void onPositiveClick() { 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(); dismissProgressDialogIfNeeded();
cleanUpStatesForStartSharing(); cleanUpStatesForStartSharing();
} }
@@ -720,19 +723,17 @@ public class AudioSharingSwitchBarController extends BasePreferenceController
public void onItemClick(@NonNull AudioSharingDeviceItem item) { public void onItemClick(@NonNull AudioSharingDeviceItem item) {
List<BluetoothDevice> targetSinks = mGroupedConnectedDevices.getOrDefault( List<BluetoothDevice> targetSinks = mGroupedConnectedDevices.getOrDefault(
item.getGroupId(), ImmutableList.of()); item.getGroupId(), ImmutableList.of());
addSourceToTargetSinks(targetSinks, item.getName()); addSourceToTargetSinks(targetSinks, item.getName(), metadata);
cleanUpStatesForStartSharing(); cleanUpStatesForStartSharing();
} }
@Override @Override
public void onCancelClick() { 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(); dismissProgressDialogIfNeeded();
cleanUpStatesForStartSharing(); cleanUpStatesForStartSharing();
} }
}; };
BluetoothLeBroadcastMetadata metadata = mBroadcast == null ? null
: mBroadcast.getLatestBluetoothLeBroadcastMetadata();
AudioSharingUtils.postOnMainThread( AudioSharingUtils.postOnMainThread(
mContext, mContext,
() -> AudioSharingDialogFragment.show( () -> AudioSharingDialogFragment.show(
@@ -828,13 +829,27 @@ public class AudioSharingSwitchBarController extends BasePreferenceController
}); });
} }
private void addSourceToTargetSinks(List<BluetoothDevice> targetActiveSinks, private void addSourceToTargetSinks(List<BluetoothDevice> targetGroupedSinks,
@NonNull String sinkName) { @NonNull String targetSinkName, @Nullable BluetoothLeBroadcastMetadata metadata) {
mSinksInAdding.addAll(targetActiveSinks); 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( 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); showProgressDialog(progressMessage);
AudioSharingUtils.addSourceToTargetSinks(targetActiveSinks, mBtManager); for (BluetoothDevice sink : targetGroupedSinks) {
mAssistant.addSource(sink, metadata, /* isGroupOp= */ false);
}
} }
private void showProgressDialog(@NonNull String progressMessage) { private void showProgressDialog(@NonNull String progressMessage) {

View File

@@ -69,6 +69,12 @@ const val KEY_SCREEN_ATTENTION = "screen_attention"
/** Contract key for the "Use adaptive connectivity" setting. */ /** Contract key for the "Use adaptive connectivity" setting. */
const val KEY_ADAPTIVE_CONNECTIVITY = "adaptive_connectivity" 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. */ /** Contract key for the "WiFi hotspot" setting. */
const val KEY_WIFI_HOTSPOT = "enable_wifi_ap" const val KEY_WIFI_HOTSPOT = "enable_wifi_ap"

View File

@@ -65,9 +65,10 @@ public class PhoneNumberPreferenceController extends BasePreferenceController {
@Override @Override
public void displayPreference(PreferenceScreen screen) { public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen); super.displayPreference(screen);
if (!SubscriptionUtil.isSimHardwareVisible(mContext)) { if (!isAvailable()) {
return; return;
} }
final Preference preference = screen.findPreference(getPreferenceKey()); final Preference preference = screen.findPreference(getPreferenceKey());
final PreferenceCategory category = screen.findPreference(KEY_PREFERENCE_CATEGORY); final PreferenceCategory category = screen.findPreference(KEY_PREFERENCE_CATEGORY);
mPreferenceList.add(preference); mPreferenceList.add(preference);

View File

@@ -35,7 +35,6 @@ import com.android.settings.core.TogglePreferenceController;
import com.android.settings.overlay.FeatureFactory; import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import com.android.settingslib.devicestate.DeviceStateAutoRotateSettingManager; import com.android.settingslib.devicestate.DeviceStateAutoRotateSettingManager;
import com.android.settingslib.devicestate.DeviceStateRotationLockSettingsManager;
import com.android.settingslib.search.SearchIndexableRaw; import com.android.settingslib.search.SearchIndexableRaw;
import java.util.List; import java.util.List;
@@ -46,7 +45,7 @@ public class DeviceStateAutoRotateSettingController extends TogglePreferenceCont
private TwoStatePreference mPreference; private TwoStatePreference mPreference;
private final DeviceStateRotationLockSettingsManager mAutoRotateSettingsManager; private final DeviceStateAutoRotateSettingManager mAutoRotateSettingsManager;
private final int mOrder; private final int mOrder;
private final DeviceStateAutoRotateSettingManager.DeviceStateAutoRotateSettingListener private final DeviceStateAutoRotateSettingManager.DeviceStateAutoRotateSettingListener
mDeviceStateAutoRotateSettingListener = () -> updateState(mPreference); mDeviceStateAutoRotateSettingListener = () -> updateState(mPreference);
@@ -62,7 +61,8 @@ public class DeviceStateAutoRotateSettingController extends TogglePreferenceCont
mMetricsFeatureProvider = metricsFeatureProvider; mMetricsFeatureProvider = metricsFeatureProvider;
mDeviceState = deviceState; mDeviceState = deviceState;
mDeviceStateDescription = deviceStateDescription; mDeviceStateDescription = deviceStateDescription;
mAutoRotateSettingsManager = DeviceStateRotationLockSettingsManager.getInstance(context); mAutoRotateSettingsManager =
DeviceStateAutoRotateSettingManagerProvider.getSingletonInstance(context);
mOrder = order; mOrder = order;
} }

View File

@@ -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
}
}

View File

@@ -16,6 +16,8 @@
package com.android.settings.display; package com.android.settings.display;
import static com.android.settingslib.devicestate.DeviceStateAutoRotateSettingUtils.isDeviceStateRotationLockEnabled;
import android.content.Context; import android.content.Context;
import android.util.Log; import android.util.Log;
@@ -25,7 +27,6 @@ import com.android.internal.view.RotationPolicy;
import com.android.settings.R; import com.android.settings.R;
import com.android.settings.core.BasePreferenceController; import com.android.settings.core.BasePreferenceController;
import com.android.settingslib.core.AbstractPreferenceController; import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.devicestate.DeviceStateRotationLockSettingsManager;
import com.android.settingslib.devicestate.SettableDeviceState; import com.android.settingslib.devicestate.SettableDeviceState;
import com.android.settingslib.search.SearchIndexableRaw; import com.android.settingslib.search.SearchIndexableRaw;
@@ -51,8 +52,8 @@ public class DeviceStateAutoRotationHelper {
static ImmutableList<AbstractPreferenceController> createPreferenceControllers( static ImmutableList<AbstractPreferenceController> createPreferenceControllers(
Context context) { Context context) {
List<SettableDeviceState> settableDeviceStates = DeviceStateRotationLockSettingsManager List<SettableDeviceState> settableDeviceStates = DeviceStateAutoRotateSettingManagerProvider
.getInstance(context).getSettableDeviceStates(); .getSingletonInstance(context).getSettableDeviceStates();
int numDeviceStates = settableDeviceStates.size(); int numDeviceStates = settableDeviceStates.size();
if (numDeviceStates == 0) { if (numDeviceStates == 0) {
return ImmutableList.of(); return ImmutableList.of();
@@ -99,7 +100,7 @@ public class DeviceStateAutoRotationHelper {
/** Returns whether the device state based auto-rotation settings are enabled. */ /** Returns whether the device state based auto-rotation settings are enabled. */
public static boolean isDeviceStateRotationEnabled(Context context) { public static boolean isDeviceStateRotationEnabled(Context context) {
return RotationPolicy.isRotationLockToggleVisible(context) return RotationPolicy.isRotationLockToggleVisible(context)
&& DeviceStateRotationLockSettingsManager.isDeviceStateRotationLockEnabled(context); && isDeviceStateRotationLockEnabled(context);
} }
/** /**
@@ -108,6 +109,6 @@ public class DeviceStateAutoRotationHelper {
*/ */
public static boolean isDeviceStateRotationEnabledForA11y(Context context) { public static boolean isDeviceStateRotationEnabledForA11y(Context context) {
return RotationPolicy.isRotationSupported(context) return RotationPolicy.isRotationSupported(context)
&& DeviceStateRotationLockSettingsManager.isDeviceStateRotationLockEnabled(context); && isDeviceStateRotationLockEnabled(context);
} }
} }

View File

@@ -47,7 +47,6 @@ import com.android.settings.core.TogglePreferenceController;
import com.android.settings.overlay.FeatureFactory; import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import com.android.settingslib.devicestate.DeviceStateAutoRotateSettingManager; import com.android.settingslib.devicestate.DeviceStateAutoRotateSettingManager;
import com.android.settingslib.devicestate.DeviceStateRotationLockSettingsManager;
/** /**
* SmartAutoRotateController controls whether auto rotation is enabled * 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 private final DeviceStateAutoRotateSettingManager.DeviceStateAutoRotateSettingListener
mDeviceStateAutoRotateSettingListener = () -> updateState(mPreference); mDeviceStateAutoRotateSettingListener = () -> updateState(mPreference);
private RotationPolicy.RotationPolicyListener mRotationPolicyListener; private RotationPolicy.RotationPolicyListener mRotationPolicyListener;
@@ -85,8 +84,9 @@ public class SmartAutoRotateController extends TogglePreferenceController implem
mMetricsFeatureProvider = FeatureFactory.getFeatureFactory().getMetricsFeatureProvider(); mMetricsFeatureProvider = FeatureFactory.getFeatureFactory().getMetricsFeatureProvider();
mPrivacyManager = SensorPrivacyManager.getInstance(context); mPrivacyManager = SensorPrivacyManager.getInstance(context);
mPowerManager = context.getSystemService(PowerManager.class); mPowerManager = context.getSystemService(PowerManager.class);
mDeviceStateAutoRotateSettingsManager = DeviceStateRotationLockSettingsManager.getInstance( mDeviceStateAutoRotateSettingsManager =
context); DeviceStateAutoRotateSettingManagerProvider.getSingletonInstance(
context);
} }
@Override @Override

View File

@@ -159,6 +159,7 @@ public class SatelliteSettingsPreferenceCategoryController
@Override @Override
public void onResult(Boolean result) { public void onResult(Boolean result) {
mIsSatelliteSupported.set(result); mIsSatelliteSupported.set(result);
Log.d(TAG, "Satellite requestIsSupported : " + result);
SatelliteSettingsPreferenceCategoryController.this.displayPreference(); SatelliteSettingsPreferenceCategoryController.this.displayPreference();
} }
}); });

View File

@@ -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"
}
}

View File

@@ -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<String>(), KeyedObserver<String>, KeyValueStore {
override fun contains(key: String) =
key == SupervisionBlockExplicitSitesPreference.KEY ||
key == SupervisionAllowAllSitesPreference.KEY
override fun <T : Any> getValue(key: String, valueType: Class<T>): 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 <T : Any> setValue(key: String, valueType: Class<T>, 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)
}
}

View File

@@ -18,9 +18,7 @@ package com.android.settings.supervision
import android.content.Context import android.content.Context
import androidx.preference.Preference import androidx.preference.Preference
import com.android.settings.R import com.android.settings.R
import com.android.settingslib.datastore.KeyValueStore
import com.android.settingslib.datastore.Permissions import com.android.settingslib.datastore.Permissions
import com.android.settingslib.datastore.SettingsSecureStore
import com.android.settingslib.metadata.BooleanValuePreference import com.android.settingslib.metadata.BooleanValuePreference
import com.android.settingslib.metadata.PreferenceMetadata import com.android.settingslib.metadata.PreferenceMetadata
import com.android.settingslib.metadata.ReadWritePermit import com.android.settingslib.metadata.ReadWritePermit
@@ -30,9 +28,10 @@ import com.android.settingslib.preference.forEachRecursively
import com.android.settingslib.widget.SelectorWithWidgetPreference import com.android.settingslib.widget.SelectorWithWidgetPreference
/** Base class of web content filters Safe sites preferences. */ /** Base class of web content filters Safe sites preferences. */
sealed class SupervisionSafeSitesPreference : sealed class SupervisionSafeSitesPreference(
BooleanValuePreference, SelectorWithWidgetPreference.OnClickListener, PreferenceBinding { protected val dataStore: SupervisionSafeSitesDataStore
override fun storage(context: Context): KeyValueStore = SettingsSecureStore.get(context) ) : BooleanValuePreference, SelectorWithWidgetPreference.OnClickListener, PreferenceBinding {
override fun storage(context: Context) = dataStore
override fun getReadPermissions(context: Context) = Permissions.EMPTY override fun getReadPermissions(context: Context) = Permissions.EMPTY
@@ -64,15 +63,15 @@ sealed class SupervisionSafeSitesPreference :
override fun bind(preference: Preference, metadata: PreferenceMetadata) { override fun bind(preference: Preference, metadata: PreferenceMetadata) {
super.bind(preference, metadata) super.bind(preference, metadata)
(preference as SelectorWithWidgetPreference).also { (preference as SelectorWithWidgetPreference).also {
// TODO(b/401568468): Set the isChecked value using stored values. it.isChecked = (dataStore.getBoolean(it.key) == true)
it.isChecked = (it.key == SupervisionAllowAllSitesPreference.KEY)
it.setOnClickListener(this) it.setOnClickListener(this)
} }
} }
} }
/** The "Try to block explicit sites" preference. */ /** The "Try to block explicit sites" preference. */
class SupervisionBlockExplicitSitesPreference : SupervisionSafeSitesPreference() { class SupervisionBlockExplicitSitesPreference(dataStore: SupervisionSafeSitesDataStore) :
SupervisionSafeSitesPreference(dataStore) {
override val key override val key
get() = KEY get() = KEY
@@ -89,7 +88,8 @@ class SupervisionBlockExplicitSitesPreference : SupervisionSafeSitesPreference()
} }
/** The "Allow all sites" preference. */ /** The "Allow all sites" preference. */
class SupervisionAllowAllSitesPreference : SupervisionSafeSitesPreference() { class SupervisionAllowAllSitesPreference(dataStore: SupervisionSafeSitesDataStore) :
SupervisionSafeSitesPreference(dataStore) {
override val key override val key
get() = KEY get() = KEY

View File

@@ -47,14 +47,23 @@ class SupervisionWebContentFiltersScreen : PreferenceScreenCreator {
R.string.supervision_web_content_filters_browser_title, R.string.supervision_web_content_filters_browser_title,
) += ) +=
{ {
+SupervisionBlockExplicitSitesPreference() val dataStore = SupervisionSafeSitesDataStore(context)
+SupervisionAllowAllSitesPreference() +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 { companion object {
const val KEY = "supervision_web_content_filters" const val KEY = "supervision_web_content_filters"
internal const val BROWSER_RADIO_BUTTON_GROUP = "browser_radio_button_group" internal const val BROWSER_RADIO_BUTTON_GROUP = "browser_radio_button_group"
internal const val SEARCH_RADIO_BUTTON_GROUP = "search_radio_button_group"
} }
} }

View File

@@ -16,9 +16,14 @@
package com.android.settings.accessibility; package com.android.settings.accessibility;
import static com.android.settings.testutils.DeviceStateAutoRotateSettingTestUtils.setDeviceStateRotationLockEnabled;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.when;
import android.content.Context; import android.content.Context;
import android.content.res.Resources;
import android.os.UserHandle; import android.os.UserHandle;
import android.provider.Settings; import android.provider.Settings;
@@ -26,12 +31,14 @@ import androidx.preference.SwitchPreference;
import com.android.internal.view.RotationPolicy; import com.android.internal.view.RotationPolicy;
import com.android.settings.core.BasePreferenceController; import com.android.settings.core.BasePreferenceController;
import com.android.settings.testutils.shadow.ShadowDeviceStateRotationLockSettingsManager;
import com.android.settings.testutils.shadow.ShadowRotationPolicy; import com.android.settings.testutils.shadow.ShadowRotationPolicy;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner; import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment; import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config; import org.robolectric.annotation.Config;
@@ -41,48 +48,45 @@ import org.robolectric.annotation.Config;
com.android.settings.testutils.shadow.ShadowSystemSettings.class, com.android.settings.testutils.shadow.ShadowSystemSettings.class,
}) })
public class LockScreenRotationPreferenceControllerTest { public class LockScreenRotationPreferenceControllerTest {
@Mock
private Resources mResources;
private Context mContext; private Context mContext;
private SwitchPreference mPreference; private SwitchPreference mPreference;
private LockScreenRotationPreferenceController mController; private LockScreenRotationPreferenceController mController;
@Before @Before
public void setUp() { public void setUp() {
mContext = RuntimeEnvironment.application; MockitoAnnotations.initMocks(this);
mContext = Mockito.spy(RuntimeEnvironment.application);
mPreference = new SwitchPreference(mContext); mPreference = new SwitchPreference(mContext);
when(mContext.getResources()).thenReturn(mResources);
mController = new LockScreenRotationPreferenceController(mContext, "lock_screen"); mController = new LockScreenRotationPreferenceController(mContext, "lock_screen");
} }
@Test @Test
@Config(shadows = { @Config(shadows = {ShadowRotationPolicy.class})
ShadowRotationPolicy.class,
ShadowDeviceStateRotationLockSettingsManager.class
})
public void getAvailabilityStatus_supportedRotation_shouldReturnAvailable() { public void getAvailabilityStatus_supportedRotation_shouldReturnAvailable() {
ShadowRotationPolicy.setRotationSupported(true /* supported */); ShadowRotationPolicy.setRotationSupported(true /* supported */);
setDeviceStateRotationLockEnabled(false, mResources);
assertThat(mController.getAvailabilityStatus()).isEqualTo( assertThat(mController.getAvailabilityStatus()).isEqualTo(
BasePreferenceController.AVAILABLE); BasePreferenceController.AVAILABLE);
} }
@Test @Test
@Config(shadows = { @Config(shadows = {ShadowRotationPolicy.class})
ShadowRotationPolicy.class,
ShadowDeviceStateRotationLockSettingsManager.class
})
public void getAvailabilityStatus_deviceStateRotationEnabled_returnsUnsupported() { public void getAvailabilityStatus_deviceStateRotationEnabled_returnsUnsupported() {
ShadowRotationPolicy.setRotationSupported(true /* supported */); ShadowRotationPolicy.setRotationSupported(true /* supported */);
ShadowDeviceStateRotationLockSettingsManager.setDeviceStateRotationLockEnabled(true); setDeviceStateRotationLockEnabled(true, mResources);
assertThat(mController.getAvailabilityStatus()).isEqualTo( assertThat(mController.getAvailabilityStatus()).isEqualTo(
BasePreferenceController.UNSUPPORTED_ON_DEVICE); BasePreferenceController.UNSUPPORTED_ON_DEVICE);
} }
@Test @Test
@Config(shadows = { @Config(shadows = {ShadowRotationPolicy.class})
ShadowRotationPolicy.class, public void getAvailabilityStatus_unsupportedRotation_shouldReturnUnsupportedOnDevice() {
ShadowDeviceStateRotationLockSettingsManager.class
}) public void getAvailabilityStatus_unsupportedRotation_shouldReturnUnsupportedOnDevice() {
ShadowRotationPolicy.setRotationSupported(false /* supported */); ShadowRotationPolicy.setRotationSupported(false /* supported */);
assertThat(mController.getAvailabilityStatus()).isEqualTo( assertThat(mController.getAvailabilityStatus()).isEqualTo(

View File

@@ -127,6 +127,7 @@ public class BluetoothKeyMissingReceiverTest {
public void broadcastReceiver_background_showNotification() { public void broadcastReceiver_background_showNotification() {
Intent intent = spy(new Intent(BluetoothDevice.ACTION_KEY_MISSING)); Intent intent = spy(new Intent(BluetoothDevice.ACTION_KEY_MISSING));
when(intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE)).thenReturn(mBluetoothDevice); when(intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE)).thenReturn(mBluetoothDevice);
when(mBluetoothDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
BluetoothKeyMissingReceiver bluetoothKeyMissingReceiver = getReceiver(intent); BluetoothKeyMissingReceiver bluetoothKeyMissingReceiver = getReceiver(intent);
bluetoothKeyMissingReceiver.onReceive(mContext, intent); bluetoothKeyMissingReceiver.onReceive(mContext, intent);
@@ -141,6 +142,7 @@ public class BluetoothKeyMissingReceiverTest {
when(mLocalBtManager.isForegroundActivity()).thenReturn(true); when(mLocalBtManager.isForegroundActivity()).thenReturn(true);
Intent intent = spy(new Intent(BluetoothDevice.ACTION_KEY_MISSING)); Intent intent = spy(new Intent(BluetoothDevice.ACTION_KEY_MISSING));
when(intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE)).thenReturn(mBluetoothDevice); when(intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE)).thenReturn(mBluetoothDevice);
when(mBluetoothDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
BluetoothKeyMissingReceiver bluetoothKeyMissingReceiver = getReceiver(intent); BluetoothKeyMissingReceiver bluetoothKeyMissingReceiver = getReceiver(intent);
bluetoothKeyMissingReceiver.onReceive(mContext, intent); bluetoothKeyMissingReceiver.onReceive(mContext, intent);

View File

@@ -18,22 +18,29 @@ package com.android.settings.bluetooth;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import android.bluetooth.BluetoothCsipSetCoordinator;
import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothLeBroadcastReceiveState; import android.bluetooth.BluetoothLeBroadcastReceiveState;
import android.content.Context; import android.content.Context;
import android.os.SystemProperties;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.testutils.FakeFeatureFactory; 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.CachedBluetoothDevice;
import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager; 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.LocalBluetoothLeBroadcast;
import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant; import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant;
import com.android.settingslib.bluetooth.LocalBluetoothManager; 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.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import org.junit.After;
import org.junit.Before; import org.junit.Before;
import org.junit.Rule; import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
@@ -52,10 +59,8 @@ import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule; import org.mockito.junit.MockitoRule;
import org.robolectric.RobolectricTestRunner; import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
@RunWith(RobolectricTestRunner.class) @RunWith(RobolectricTestRunner.class)
@Config(shadows = {ShadowBluetoothUtils.class})
public class UtilsTest { public class UtilsTest {
private static final int METADATA_FAST_PAIR_CUSTOMIZED_FIELDS = 25; private static final int METADATA_FAST_PAIR_CUSTOMIZED_FIELDS = 25;
private static final String TEMP_BOND_METADATA = private static final String TEMP_BOND_METADATA =
@@ -73,6 +78,14 @@ public class UtilsTest {
@Mock @Mock
private LocalBluetoothLeBroadcastAssistant mAssistant; private LocalBluetoothLeBroadcastAssistant mAssistant;
@Mock @Mock
private A2dpProfile mA2dpProfile;
@Mock
private HeadsetProfile mHeadsetProfile;
@Mock
private LeAudioProfile mLeAudioProfile;
@Mock
private HearingAidProfile mHearingAidProfile;
@Mock
private CachedBluetoothDeviceManager mDeviceManager; private CachedBluetoothDeviceManager mDeviceManager;
private MetricsFeatureProvider mMetricsFeatureProvider; private MetricsFeatureProvider mMetricsFeatureProvider;
@@ -80,17 +93,14 @@ public class UtilsTest {
@Before @Before
public void setUp() { public void setUp() {
mMetricsFeatureProvider = FakeFeatureFactory.setupForTest().getMetricsFeatureProvider(); mMetricsFeatureProvider = FakeFeatureFactory.setupForTest().getMetricsFeatureProvider();
ShadowBluetoothUtils.sLocalBluetoothManager = mLocalBtManager;
mLocalBtManager = Utils.getLocalBtManager(mContext);
when(mLocalBtManager.getProfileManager()).thenReturn(mProfileManager); when(mLocalBtManager.getProfileManager()).thenReturn(mProfileManager);
when(mLocalBtManager.getCachedDeviceManager()).thenReturn(mDeviceManager); when(mLocalBtManager.getCachedDeviceManager()).thenReturn(mDeviceManager);
when(mProfileManager.getLeAudioBroadcastProfile()).thenReturn(mBroadcast); when(mProfileManager.getLeAudioBroadcastProfile()).thenReturn(mBroadcast);
when(mProfileManager.getLeAudioBroadcastAssistantProfile()).thenReturn(mAssistant); when(mProfileManager.getLeAudioBroadcastAssistantProfile()).thenReturn(mAssistant);
} when(mProfileManager.getA2dpProfile()).thenReturn(mA2dpProfile);
when(mProfileManager.getHeadsetProfile()).thenReturn(mHeadsetProfile);
@After when(mProfileManager.getLeAudioProfile()).thenReturn(mLeAudioProfile);
public void tearDown() { when(mProfileManager.getHearingAidProfile()).thenReturn(mHearingAidProfile);
ShadowBluetoothUtils.reset();
} }
@Test @Test
@@ -170,4 +180,148 @@ public class UtilsTest {
when(mAssistant.getAllSources(any())).thenReturn(ImmutableList.of(state)); when(mAssistant.getAllSources(any())).thenReturn(ImmutableList.of(state));
assertThat(Utils.shouldBlockPairingInAudioSharing(mLocalBtManager)).isTrue(); 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);
}
} }

View File

@@ -39,7 +39,6 @@ import android.hardware.devicestate.DeviceStateManager;
import com.android.settings.R; import com.android.settings.R;
import com.android.settingslib.core.AbstractPreferenceController; import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.devicestate.DeviceStateRotationLockSettingsManager;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
@@ -144,16 +143,15 @@ public class DeviceStateAutoRotateDetailsFragmentTest {
} }
private void enableDeviceStateSettableRotationStates(String[] settableStates, private void enableDeviceStateSettableRotationStates(String[] settableStates,
String[] settableStatesDescriptions) { String[] settableStatesDescriptions) {
when(mResources.getStringArray( when(mResources.getStringArray(
com.android.internal.R.array.config_perDeviceStateRotationLockDefaults)).thenReturn( com.android.internal.R.array.config_perDeviceStateRotationLockDefaults)).thenReturn(
settableStates); settableStates);
when(mResources.getStringArray( when(mResources.getStringArray(
R.array.config_settableAutoRotationDeviceStatesDescriptions)).thenReturn( R.array.config_settableAutoRotationDeviceStatesDescriptions)).thenReturn(
settableStatesDescriptions); settableStatesDescriptions);
DeviceStateRotationLockSettingsManager.resetInstance(); DeviceStateAutoRotateSettingManagerProvider.resetInstance();
DeviceStateRotationLockSettingsManager.getInstance(mContext) when(mContext.getResources()).thenReturn(mResources);
.resetStateForTesting(mResources);
} }
// Sets up posture mappings for PosturesHelper // Sets up posture mappings for PosturesHelper

View File

@@ -18,30 +18,48 @@ package com.android.settings.display;
import static com.android.settings.core.BasePreferenceController.AVAILABLE; import static com.android.settings.core.BasePreferenceController.AVAILABLE;
import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_DEVICE; 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 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 com.android.settings.testutils.shadow.ShadowRotationPolicy;
import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner; import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment; import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config; import org.robolectric.annotation.Config;
@RunWith(RobolectricTestRunner.class) @RunWith(RobolectricTestRunner.class)
@Config(shadows = {ShadowRotationPolicy.class, ShadowDeviceStateRotationLockSettingsManager.class}) @Config(shadows = {ShadowRotationPolicy.class})
public class DeviceStateAutoRotateOverviewControllerTest { public class DeviceStateAutoRotateOverviewControllerTest {
@Mock
private Resources mResources;
private DeviceStateAutoRotateOverviewController mController;
private final DeviceStateAutoRotateOverviewController mController = @Before
new DeviceStateAutoRotateOverviewController( public void setUp() {
RuntimeEnvironment.application, "device_state_auto_rotate"); MockitoAnnotations.initMocks(this);
Context context = Mockito.spy(RuntimeEnvironment.application);
when(context.getResources()).thenReturn(mResources);
mController = new DeviceStateAutoRotateOverviewController(
context, "device_state_auto_rotate");
}
@Test @Test
public void getAvailabilityStatus_rotationAndDeviceStateRotationEnabled_returnsAvailable() { public void getAvailabilityStatus_rotationAndDeviceStateRotationEnabled_returnsAvailable() {
ShadowRotationPolicy.setRotationSupported(true); ShadowRotationPolicy.setRotationSupported(true);
ShadowDeviceStateRotationLockSettingsManager.setDeviceStateRotationLockEnabled(true); setDeviceStateRotationLockEnabled(true, mResources);
int availability = mController.getAvailabilityStatus(); int availability = mController.getAvailabilityStatus();
@@ -51,7 +69,7 @@ public class DeviceStateAutoRotateOverviewControllerTest {
@Test @Test
public void getAvailabilityStatus_rotationNotSupported_returnsUnsupportedOnDevice() { public void getAvailabilityStatus_rotationNotSupported_returnsUnsupportedOnDevice() {
ShadowRotationPolicy.setRotationSupported(false); ShadowRotationPolicy.setRotationSupported(false);
ShadowDeviceStateRotationLockSettingsManager.setDeviceStateRotationLockEnabled(true); setDeviceStateRotationLockEnabled(true, mResources);
int availability = mController.getAvailabilityStatus(); int availability = mController.getAvailabilityStatus();
@@ -61,7 +79,7 @@ public class DeviceStateAutoRotateOverviewControllerTest {
@Test @Test
public void getAvailabilityStatus_deviceStateRotationNotSupported_returnsUnsupportedOnDevice() { public void getAvailabilityStatus_deviceStateRotationNotSupported_returnsUnsupportedOnDevice() {
ShadowRotationPolicy.setRotationSupported(true); ShadowRotationPolicy.setRotationSupported(true);
ShadowDeviceStateRotationLockSettingsManager.setDeviceStateRotationLockEnabled(false); setDeviceStateRotationLockEnabled(false, mResources);
int availability = mController.getAvailabilityStatus(); int availability = mController.getAvailabilityStatus();

View File

@@ -18,14 +18,17 @@ package com.android.settings.display;
import static com.android.settings.core.BasePreferenceController.AVAILABLE; import static com.android.settings.core.BasePreferenceController.AVAILABLE;
import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_DEVICE; 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 com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.settings.SettingsEnums; import android.app.settings.SettingsEnums;
import android.content.Context; import android.content.Context;
import android.content.res.Resources;
import android.hardware.devicestate.DeviceState; import android.hardware.devicestate.DeviceState;
import android.hardware.devicestate.DeviceStateManager; import android.hardware.devicestate.DeviceStateManager;
@@ -34,10 +37,9 @@ import androidx.preference.PreferenceManager;
import androidx.preference.PreferenceScreen; import androidx.preference.PreferenceScreen;
import com.android.settings.R; import com.android.settings.R;
import com.android.settings.testutils.shadow.ShadowDeviceStateRotationLockSettingsManager;
import com.android.settings.testutils.shadow.ShadowRotationPolicy; import com.android.settings.testutils.shadow.ShadowRotationPolicy;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; 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 com.android.settingslib.search.SearchIndexableRaw;
import org.junit.Before; import org.junit.Before;
@@ -54,10 +56,7 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
@RunWith(RobolectricTestRunner.class) @RunWith(RobolectricTestRunner.class)
@Config(shadows = { @Config(shadows = {ShadowRotationPolicy.class})
ShadowRotationPolicy.class,
ShadowDeviceStateRotationLockSettingsManager.class
})
public class DeviceStateAutoRotateSettingControllerTest { public class DeviceStateAutoRotateSettingControllerTest {
private static final DeviceState DEFAULT_DEVICE_STATE = new DeviceState( private static final DeviceState DEFAULT_DEVICE_STATE = new DeviceState(
@@ -66,10 +65,11 @@ public class DeviceStateAutoRotateSettingControllerTest {
private static final int DEFAULT_ORDER = -10; private static final int DEFAULT_ORDER = -10;
private final Context mContext = Mockito.spy(RuntimeEnvironment.application); private final Context mContext = Mockito.spy(RuntimeEnvironment.application);
private DeviceStateRotationLockSettingsManager mAutoRotateSettingsManager; private DeviceStateAutoRotateSettingManager mAutoRotateSettingsManager;
@Mock private MetricsFeatureProvider mMetricsFeatureProvider; @Mock private MetricsFeatureProvider mMetricsFeatureProvider;
@Mock private DeviceStateManager mDeviceStateManager; @Mock private DeviceStateManager mDeviceStateManager;
@Mock private Resources mResources;
private DeviceStateAutoRotateSettingController mController; private DeviceStateAutoRotateSettingController mController;
@@ -78,11 +78,14 @@ public class DeviceStateAutoRotateSettingControllerTest {
MockitoAnnotations.initMocks(this); MockitoAnnotations.initMocks(this);
doReturn(mContext).when(mContext).getApplicationContext(); doReturn(mContext).when(mContext).getApplicationContext();
when(mContext.getResources()).thenReturn(mResources);
doReturn(mDeviceStateManager).when(mContext).getSystemService(DeviceStateManager.class); doReturn(mDeviceStateManager).when(mContext).getSystemService(DeviceStateManager.class);
doReturn(List.of(DEFAULT_DEVICE_STATE)).when( doReturn(List.of(DEFAULT_DEVICE_STATE)).when(
mDeviceStateManager).getSupportedDeviceStates(); mDeviceStateManager).getSupportedDeviceStates();
setDeviceStateRotationLockEnabled(false, mResources);
mAutoRotateSettingsManager = mAutoRotateSettingsManager =
DeviceStateRotationLockSettingsManager.getInstance(mContext); DeviceStateAutoRotateSettingManagerProvider.getSingletonInstance(mContext);
mController = new DeviceStateAutoRotateSettingController( mController = new DeviceStateAutoRotateSettingController(
mContext, mContext,
DEFAULT_DEVICE_STATE.getIdentifier(), DEFAULT_DEVICE_STATE.getIdentifier(),
@@ -108,7 +111,7 @@ public class DeviceStateAutoRotateSettingControllerTest {
@Test @Test
public void getAvailabilityStatus_rotationAndDeviceStateRotationEnabled_returnsAvailable() { public void getAvailabilityStatus_rotationAndDeviceStateRotationEnabled_returnsAvailable() {
ShadowRotationPolicy.setRotationSupported(true); ShadowRotationPolicy.setRotationSupported(true);
ShadowDeviceStateRotationLockSettingsManager.setDeviceStateRotationLockEnabled(true); setDeviceStateRotationLockEnabled(true, mResources);
int availability = mController.getAvailabilityStatus(); int availability = mController.getAvailabilityStatus();
@@ -118,7 +121,7 @@ public class DeviceStateAutoRotateSettingControllerTest {
@Test @Test
public void getAvailabilityStatus_deviceStateRotationDisabled_returnsUnsupported() { public void getAvailabilityStatus_deviceStateRotationDisabled_returnsUnsupported() {
ShadowRotationPolicy.setRotationSupported(true); ShadowRotationPolicy.setRotationSupported(true);
ShadowDeviceStateRotationLockSettingsManager.setDeviceStateRotationLockEnabled(false); setDeviceStateRotationLockEnabled(false, mResources);
int availability = mController.getAvailabilityStatus(); int availability = mController.getAvailabilityStatus();
@@ -128,7 +131,7 @@ public class DeviceStateAutoRotateSettingControllerTest {
@Test @Test
public void getAvailabilityStatus_rotationDisabled_returnsUnsupported() { public void getAvailabilityStatus_rotationDisabled_returnsUnsupported() {
ShadowRotationPolicy.setRotationSupported(false); ShadowRotationPolicy.setRotationSupported(false);
ShadowDeviceStateRotationLockSettingsManager.setDeviceStateRotationLockEnabled(true); setDeviceStateRotationLockEnabled(true, mResources);
int availability = mController.getAvailabilityStatus(); int availability = mController.getAvailabilityStatus();

View File

@@ -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)
}
}

View File

@@ -19,6 +19,7 @@ package com.android.settings.display;
import static com.android.settings.core.BasePreferenceController.AVAILABLE; 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.DISABLED_DEPENDENT_SETTING;
import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_DEVICE; 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 com.google.common.truth.Truth.assertThat;
@@ -33,6 +34,7 @@ import android.content.Context;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo; import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo; import android.content.pm.ServiceInfo;
import android.content.res.Resources;
import android.hardware.devicestate.DeviceState; import android.hardware.devicestate.DeviceState;
import android.hardware.devicestate.DeviceStateManager; import android.hardware.devicestate.DeviceStateManager;
import android.os.UserHandle; import android.os.UserHandle;
@@ -41,11 +43,11 @@ import android.provider.Settings;
import androidx.preference.Preference; import androidx.preference.Preference;
import com.android.settings.testutils.ResolveInfoBuilder; 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.ShadowRotationPolicy;
import com.android.settings.testutils.shadow.ShadowSensorPrivacyManager; import com.android.settings.testutils.shadow.ShadowSensorPrivacyManager;
import com.android.settings.testutils.shadow.ShadowSystemSettings; 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.Before;
import org.junit.Test; import org.junit.Test;
@@ -73,17 +75,21 @@ public class SmartAutoRotateControllerTest {
private Preference mPreference; private Preference mPreference;
@Mock @Mock
private DeviceStateManager mDeviceStateManager; private DeviceStateManager mDeviceStateManager;
@Mock
private Resources mResources;
private ContentResolver mContentResolver; private ContentResolver mContentResolver;
private DeviceStateRotationLockSettingsManager mDeviceStateAutoRotateSettingsManager; private DeviceStateAutoRotateSettingManager mDeviceStateAutoRotateSettingManager;
@Before @Before
public void setUp() { public void setUp() {
MockitoAnnotations.initMocks(this); MockitoAnnotations.initMocks(this);
final Context context = Mockito.spy(RuntimeEnvironment.application); final Context context = Mockito.spy(RuntimeEnvironment.application);
mContentResolver = RuntimeEnvironment.application.getContentResolver(); mContentResolver = RuntimeEnvironment.application.getContentResolver();
mResources = Mockito.spy(RuntimeEnvironment.application.getResources());
when(context.getPackageManager()).thenReturn(mPackageManager); when(context.getPackageManager()).thenReturn(mPackageManager);
when(context.getContentResolver()).thenReturn(mContentResolver); when(context.getContentResolver()).thenReturn(mContentResolver);
when(context.getResources()).thenReturn(mResources);
doReturn(PACKAGE_NAME).when(mPackageManager).getRotationResolverPackageName(); doReturn(PACKAGE_NAME).when(mPackageManager).getRotationResolverPackageName();
doReturn(PackageManager.PERMISSION_GRANTED).when(mPackageManager).checkPermission( doReturn(PackageManager.PERMISSION_GRANTED).when(mPackageManager).checkPermission(
Manifest.permission.CAMERA, PACKAGE_NAME); Manifest.permission.CAMERA, PACKAGE_NAME);
@@ -91,8 +97,9 @@ public class SmartAutoRotateControllerTest {
doReturn(context).when(context).getApplicationContext(); doReturn(context).when(context).getApplicationContext();
doReturn(mDeviceStateManager).when(context).getSystemService(DeviceStateManager.class); doReturn(mDeviceStateManager).when(context).getSystemService(DeviceStateManager.class);
doReturn(getDeviceStateList()).when(mDeviceStateManager).getSupportedDeviceStates(); doReturn(getDeviceStateList()).when(mDeviceStateManager).getSupportedDeviceStates();
mDeviceStateAutoRotateSettingsManager = DeviceStateRotationLockSettingsManager.getInstance( setDeviceStateRotationLockEnabled(false, mResources);
context); mDeviceStateAutoRotateSettingManager =
DeviceStateAutoRotateSettingManagerProvider.getSingletonInstance(context);
mController = Mockito.spy(new SmartAutoRotateController(context, "test_key")); mController = Mockito.spy(new SmartAutoRotateController(context, "test_key"));
when(mController.isCameraLocked()).thenReturn(false); when(mController.isCameraLocked()).thenReturn(false);
@@ -144,7 +151,7 @@ public class SmartAutoRotateControllerTest {
@Test @Test
@Config(shadows = { @Config(shadows = {
ShadowDeviceStateRotationLockSettingsManager.class, ShadowDeviceStateAutoRotateSettingManager.class,
ShadowRotationPolicy.class ShadowRotationPolicy.class
}) })
public void getAvailabilityStatus_deviceStateRotationLocked_returnDisableDependentSetting() { public void getAvailabilityStatus_deviceStateRotationLocked_returnDisableDependentSetting() {
@@ -158,7 +165,7 @@ public class SmartAutoRotateControllerTest {
@Test @Test
@Config(shadows = { @Config(shadows = {
ShadowDeviceStateRotationLockSettingsManager.class, ShadowDeviceStateAutoRotateSettingManager.class,
ShadowRotationPolicy.class ShadowRotationPolicy.class
}) })
public void getAvailabilityStatus_deviceStateRotationUnlocked_returnAvailable() { public void getAvailabilityStatus_deviceStateRotationUnlocked_returnAvailable() {
@@ -182,18 +189,18 @@ public class SmartAutoRotateControllerTest {
private void enableDeviceStateRotation() { private void enableDeviceStateRotation() {
ShadowRotationPolicy.setRotationSupported(true); ShadowRotationPolicy.setRotationSupported(true);
ShadowDeviceStateRotationLockSettingsManager.setDeviceStateRotationLockEnabled(true); setDeviceStateRotationLockEnabled(true, mResources);
} }
private void lockDeviceStateRotation() { private void lockDeviceStateRotation() {
ShadowDeviceStateRotationLockSettingsManager shadowManager = ShadowDeviceStateAutoRotateSettingManager shadowManager =
Shadow.extract(mDeviceStateAutoRotateSettingsManager); Shadow.extract(mDeviceStateAutoRotateSettingManager);
shadowManager.setRotationLockedForAllStates(true); shadowManager.setRotationLockedForAllStates(true);
} }
private void unlockDeviceStateRotation() { private void unlockDeviceStateRotation() {
ShadowDeviceStateRotationLockSettingsManager shadowManager = ShadowDeviceStateAutoRotateSettingManager shadowManager =
Shadow.extract(mDeviceStateAutoRotateSettingsManager); Shadow.extract(mDeviceStateAutoRotateSettingManager);
shadowManager.setRotationLockedForAllStates(false); shadowManager.setRotationLockedForAllStates(false);
} }

View File

@@ -18,6 +18,8 @@ package com.android.settings.display;
import static android.provider.Settings.Secure.CAMERA_AUTOROTATE; 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 com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any; 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.core.BasePreferenceController;
import com.android.settings.testutils.FakeFeatureFactory; import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.testutils.ResolveInfoBuilder; 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.ShadowSensorPrivacyManager;
import com.android.settings.testutils.shadow.ShadowSystemSettings; import com.android.settings.testutils.shadow.ShadowSystemSettings;
@@ -57,8 +58,7 @@ import org.robolectric.annotation.Config;
@RunWith(RobolectricTestRunner.class) @RunWith(RobolectricTestRunner.class)
@Config(shadows = { @Config(shadows = {
ShadowSystemSettings.class, ShadowSystemSettings.class,
ShadowSensorPrivacyManager.class, ShadowSensorPrivacyManager.class
ShadowDeviceStateRotationLockSettingsManager.class
}) })
public class SmartAutoRotatePreferenceControllerTest { public class SmartAutoRotatePreferenceControllerTest {
@@ -104,7 +104,7 @@ public class SmartAutoRotatePreferenceControllerTest {
new SmartAutoRotatePreferenceController(mContext, "smart_auto_rotate")); new SmartAutoRotatePreferenceController(mContext, "smart_auto_rotate"));
when(mController.isCameraLocked()).thenReturn(false); when(mController.isCameraLocked()).thenReturn(false);
when(mController.isPowerSaveMode()).thenReturn(false); when(mController.isPowerSaveMode()).thenReturn(false);
ShadowDeviceStateRotationLockSettingsManager.setDeviceStateRotationLockEnabled(false); setDeviceStateRotationLockEnabled(false, mResources);
} }
@Test @Test
@@ -213,7 +213,7 @@ public class SmartAutoRotatePreferenceControllerTest {
@Test @Test
public void getAvailabilityStatus_deviceStateRotationEnabled_returnsUnsupported() { public void getAvailabilityStatus_deviceStateRotationEnabled_returnsUnsupported() {
enableAutoRotationPreference(); enableAutoRotationPreference();
ShadowDeviceStateRotationLockSettingsManager.setDeviceStateRotationLockEnabled(true); setDeviceStateRotationLockEnabled(true, mResources);
assertThat(mController.getAvailabilityStatus()).isEqualTo( assertThat(mController.getAvailabilityStatus()).isEqualTo(
BasePreferenceController.UNSUPPORTED_ON_DEVICE); BasePreferenceController.UNSUPPORTED_ON_DEVICE);

View File

@@ -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_MAIN_SWITCH_PREFERENCE_KEY;
import static com.android.settings.display.SmartAutoRotatePreferenceFragment.AUTO_ROTATE_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; 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.R;
import com.android.settings.SettingsActivity; import com.android.settings.SettingsActivity;
import com.android.settings.testutils.ResolveInfoBuilder; import com.android.settings.testutils.ResolveInfoBuilder;
import com.android.settings.testutils.shadow.ShadowDeviceStateRotationLockSettingsManager;
import com.android.settings.testutils.shadow.ShadowRotationPolicy; import com.android.settings.testutils.shadow.ShadowRotationPolicy;
import com.android.settingslib.core.AbstractPreferenceController; import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.devicestate.DeviceStateRotationLockSettingsManager;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
@@ -75,7 +74,6 @@ import java.util.Set;
@RunWith(RobolectricTestRunner.class) @RunWith(RobolectricTestRunner.class)
@Config(shadows = { @Config(shadows = {
com.android.settings.testutils.shadow.ShadowFragment.class, com.android.settings.testutils.shadow.ShadowFragment.class,
ShadowDeviceStateRotationLockSettingsManager.class,
ShadowRotationPolicy.class ShadowRotationPolicy.class
}) })
public class SmartAutoRotatePreferenceFragmentTest { public class SmartAutoRotatePreferenceFragmentTest {
@@ -174,7 +172,7 @@ public class SmartAutoRotatePreferenceFragmentTest {
@Test @Test
public void createHeader_faceDetectionSupported_switchBarIsEnabled() { public void createHeader_faceDetectionSupported_switchBarIsEnabled() {
ShadowDeviceStateRotationLockSettingsManager.setDeviceStateRotationLockEnabled(false); setDeviceStateRotationLockEnabled(false, mResources);
mFragment.createHeader(mActivity); mFragment.createHeader(mActivity);
verify(mRotateMainSwitchPreference, never()).setVisible(false); verify(mRotateMainSwitchPreference, never()).setVisible(false);
@@ -184,7 +182,7 @@ public class SmartAutoRotatePreferenceFragmentTest {
@Test @Test
public void createHeader_deviceStateRotationSupported_switchBarIsDisabled() { public void createHeader_deviceStateRotationSupported_switchBarIsDisabled() {
ShadowRotationPolicy.setRotationSupported(true); ShadowRotationPolicy.setRotationSupported(true);
ShadowDeviceStateRotationLockSettingsManager.setDeviceStateRotationLockEnabled(true); setDeviceStateRotationLockEnabled(true, mResources);
mFragment.createHeader(mActivity); mFragment.createHeader(mActivity);
@@ -258,15 +256,14 @@ public class SmartAutoRotatePreferenceFragmentTest {
private void enableDeviceStateSettableRotationStates( private void enableDeviceStateSettableRotationStates(
String[] settableStates, String[] settableStatesDescriptions) { String[] settableStates, String[] settableStatesDescriptions) {
when(mResources.getStringArray( when(mResources.getStringArray(
com.android.internal.R.array.config_perDeviceStateRotationLockDefaults)) com.android.internal.R.array.config_perDeviceStateRotationLockDefaults))
.thenReturn(settableStates); .thenReturn(settableStates);
when(mResources.getStringArray(R.array.config_settableAutoRotationDeviceStatesDescriptions)) when(mResources.getStringArray(R.array.config_settableAutoRotationDeviceStatesDescriptions))
.thenReturn(settableStatesDescriptions); .thenReturn(settableStatesDescriptions);
when(mResources.getBoolean(R.bool.config_auto_rotate_face_detection_available)) when(mResources.getBoolean(R.bool.config_auto_rotate_face_detection_available))
.thenReturn(true); .thenReturn(true);
DeviceStateRotationLockSettingsManager.resetInstance(); DeviceStateAutoRotateSettingManagerProvider.resetInstance();
DeviceStateRotationLockSettingsManager.getInstance(mContext) when(mContext.getResources()).thenReturn(mResources);
.resetStateForTesting(mResources);
} }
// Sets up posture mappings for PosturesHelper // Sets up posture mappings for PosturesHelper

View File

@@ -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
)
}
}

View File

@@ -16,20 +16,33 @@
package com.android.settings.supervision package com.android.settings.supervision
import android.content.Context 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.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.settings.R 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 com.google.common.truth.Truth.assertThat
import org.junit.Assert.assertThrows
import org.junit.Before
import org.junit.Test import org.junit.Test
import org.junit.runner.RunWith import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class) @RunWith(AndroidJUnit4::class)
class SupervisionSafeSitesPreferenceTest { class SupervisionSafeSitesPreferenceTest {
private val context: Context = ApplicationProvider.getApplicationContext() 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() @Before
fun setUp() {
private val blockExplicitSitesPreference = SupervisionBlockExplicitSitesPreference() dataStore = SupervisionSafeSitesDataStore(context)
allowAllSitesPreference = SupervisionAllowAllSitesPreference(dataStore)
blockExplicitSitesPreference = SupervisionBlockExplicitSitesPreference(dataStore)
}
@Test @Test
fun getTitle_allowAllSites() { fun getTitle_allowAllSites() {
@@ -50,4 +63,64 @@ class SupervisionSafeSitesPreferenceTest {
R.string.supervision_web_content_filters_browser_block_explicit_sites_summary 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)
}
} }

View File

@@ -15,18 +15,32 @@
*/ */
package com.android.settings.supervision package com.android.settings.supervision
import android.app.supervision.flags.Flags
import android.content.Context 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.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.settings.R import com.android.settings.R
import com.android.settingslib.widget.SelectorWithWidgetPreference
import com.google.common.truth.Truth.assertThat import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Rule
import org.junit.Test import org.junit.Test
import org.junit.runner.RunWith import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class) @RunWith(AndroidJUnit4::class)
class SupervisionWebContentFiltersScreenTest { class SupervisionWebContentFiltersScreenTest {
@get:Rule val setFlagsRule = SetFlagsRule()
private val context: Context = ApplicationProvider.getApplicationContext() private val context: Context = ApplicationProvider.getApplicationContext()
private val supervisionWebContentFiltersScreen = SupervisionWebContentFiltersScreen() private lateinit var supervisionWebContentFiltersScreen: SupervisionWebContentFiltersScreen
@Before
fun setUp() {
supervisionWebContentFiltersScreen = SupervisionWebContentFiltersScreen()
}
@Test @Test
fun key() { fun key() {
@@ -39,4 +53,40 @@ class SupervisionWebContentFiltersScreenTest {
assertThat(supervisionWebContentFiltersScreen.title) assertThat(supervisionWebContentFiltersScreen.title)
.isEqualTo(R.string.supervision_web_content_filters_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<SelectorWithWidgetPreference>(
SupervisionAllowAllSitesPreference.KEY
)!!
val blockExplicitSitesPreference =
fragment.findPreference<SelectorWithWidgetPreference>(
SupervisionBlockExplicitSitesPreference.KEY
)!!
assertThat(allowAllSitesPreference.isChecked).isTrue()
assertThat(blockExplicitSitesPreference.isChecked).isFalse()
blockExplicitSitesPreference.performClick()
assertThat(blockExplicitSitesPreference.isChecked).isTrue()
assertThat(allowAllSitesPreference.isChecked).isFalse()
}
}
} }

View File

@@ -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);
}
}

View File

@@ -16,28 +16,16 @@
package com.android.settings.testutils.shadow; package com.android.settings.testutils.shadow;
import android.content.Context;
import com.android.settingslib.devicestate.DeviceStateRotationLockSettingsManager; import com.android.settingslib.devicestate.DeviceStateRotationLockSettingsManager;
import org.robolectric.annotation.Implementation; import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements; import org.robolectric.annotation.Implements;
@Implements(DeviceStateRotationLockSettingsManager.class) @Implements(DeviceStateRotationLockSettingsManager.class)
public class ShadowDeviceStateRotationLockSettingsManager { public class ShadowDeviceStateAutoRotateSettingManager {
private static boolean sDeviceStateRotationLockEnabled;
private boolean mIsRotationLockedForAllStates; private boolean mIsRotationLockedForAllStates;
@Implementation
public static boolean isDeviceStateRotationLockEnabled(Context context) {
return sDeviceStateRotationLockEnabled;
}
public static void setDeviceStateRotationLockEnabled(boolean enabled) {
sDeviceStateRotationLockEnabled = enabled;
}
@Implementation @Implementation
public boolean isRotationLockedForAllStates() { public boolean isRotationLockedForAllStates() {
return mIsRotationLockedForAllStates; return mIsRotationLockedForAllStates;

View File

@@ -18,24 +18,48 @@ package com.android.settings.testutils.shadow;
import android.content.Context; import android.content.Context;
import androidx.annotation.NonNull;
import com.android.settings.bluetooth.Utils; import com.android.settings.bluetooth.Utils;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.bluetooth.LocalBluetoothManager; import com.android.settingslib.bluetooth.LocalBluetoothManager;
import org.robolectric.annotation.Implementation; import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements; import org.robolectric.annotation.Implements;
import org.robolectric.annotation.Resetter; import org.robolectric.annotation.Resetter;
import java.util.HashMap;
import java.util.Map;
/** Robolectric shadow for the bluetooth utils. */ /** Robolectric shadow for the bluetooth utils. */
@Implements(Utils.class) @Implements(Utils.class)
public class ShadowBluetoothUtils { public class ShadowBluetoothUtils {
public static LocalBluetoothManager sLocalBluetoothManager; public static LocalBluetoothManager sLocalBluetoothManager;
private static final Map<CachedBluetoothDevice, Boolean> sLeAudioState = new HashMap<>();
@Implementation @Implementation
protected static LocalBluetoothManager getLocalBtManager(Context context) { protected static LocalBluetoothManager getLocalBtManager(Context context) {
return sLocalBluetoothManager; 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. */ /** Resets the local bluetooth manager to null. */
@Resetter @Resetter
public static void reset() { public static void reset() {