mSideToSliderMap = new ArrayMap<>();
-
- /**
- * Ambient volume level for hearing device ambient control icon
- *
- * This icon visually represents the current ambient gain setting.
- * It displays separate levels for the left and right sides, each with 5 levels ranging from 0
- * to 4.
- *
- * To represent the combined left/right levels with a single value, the following calculation
- * is used:
- * finalLevel = (leftLevel * 5) + rightLevel
- * For example:
- *
- * - If left level is 2 and right level is 3, the final level will be 13 (2 * 5 + 3)
- * - If both left and right levels are 0, the final level will be 0
- * - If both left and right levels are 4, the final level will be 24
- *
- */
+ private final BiMap mSideToSliderMap = HashBiMap.create();
private int mVolumeLevel = AMBIENT_VOLUME_LEVEL_DEFAULT;
+ private final OnPreferenceChangeListener mPreferenceChangeListener =
+ (slider, v) -> {
+ if (slider instanceof SeekBarPreference && v instanceof final Integer value) {
+ final Integer side = mSideToSliderMap.inverse().get(slider);
+ if (mListener != null && side != null) {
+ mListener.onSliderValueChange(side, value);
+ }
+ return true;
+ }
+ return false;
+ };
+
public AmbientVolumePreference(@NonNull Context context) {
super(context, null);
setLayoutResource(R.layout.preference_ambient_volume);
@@ -138,7 +122,8 @@ public class AmbientVolumePreference extends PreferenceGroup {
updateExpandIcon();
}
- void setExpandable(boolean expandable) {
+ @Override
+ public void setExpandable(boolean expandable) {
mExpandable = expandable;
if (!mExpandable) {
setExpanded(false);
@@ -146,11 +131,13 @@ public class AmbientVolumePreference extends PreferenceGroup {
updateExpandIcon();
}
- boolean isExpandable() {
+ @Override
+ public boolean isExpandable() {
return mExpandable;
}
- void setExpanded(boolean expanded) {
+ @Override
+ public void setExpanded(boolean expanded) {
if (!mExpandable && expanded) {
return;
}
@@ -159,11 +146,13 @@ public class AmbientVolumePreference extends PreferenceGroup {
updateLayout();
}
- boolean isExpanded() {
+ @Override
+ public boolean isExpanded() {
return mExpanded;
}
- void setMutable(boolean mutable) {
+ @Override
+ public void setMutable(boolean mutable) {
mMutable = mutable;
if (!mMutable) {
mVolumeLevel = AMBIENT_VOLUME_LEVEL_DEFAULT;
@@ -172,11 +161,13 @@ public class AmbientVolumePreference extends PreferenceGroup {
updateVolumeIcon();
}
- boolean isMutable() {
+ @Override
+ public boolean isMutable() {
return mMutable;
}
- void setMuted(boolean muted) {
+ @Override
+ public void setMuted(boolean muted) {
if (!mMutable && muted) {
return;
}
@@ -189,25 +180,35 @@ public class AmbientVolumePreference extends PreferenceGroup {
updateVolumeIcon();
}
- boolean isMuted() {
+ @Override
+ public boolean isMuted() {
return mMuted;
}
- void setOnIconClickListener(@Nullable OnIconClickListener listener) {
+ @Override
+ public void setListener(@Nullable AmbientVolumeUiListener listener) {
mListener = listener;
}
- void setSliders(Map sideToSliderMap) {
- mSideToSliderMap = sideToSliderMap;
- for (SeekBarPreference preference : sideToSliderMap.values()) {
- if (findPreference(preference.getKey()) == null) {
- addPreference(preference);
+ @Override
+ public void setupSliders(@NonNull Map sideToDeviceMap) {
+ sideToDeviceMap.forEach((side, device) ->
+ createSlider(side, ORDER_AMBIENT_VOLUME_CONTROL_SEPARATED + side));
+ createSlider(SIDE_UNIFIED, ORDER_AMBIENT_VOLUME_CONTROL_UNIFIED);
+
+ if (!mSideToSliderMap.isEmpty()) {
+ for (int side : VALID_SIDES) {
+ final SeekBarPreference slider = mSideToSliderMap.get(side);
+ if (slider != null && findPreference(slider.getKey()) == null) {
+ addPreference(slider);
+ }
}
}
updateLayout();
}
- void setSliderEnabled(int side, boolean enabled) {
+ @Override
+ public void setSliderEnabled(int side, boolean enabled) {
SeekBarPreference slider = mSideToSliderMap.get(side);
if (slider != null && slider.isEnabled() != enabled) {
slider.setEnabled(enabled);
@@ -215,7 +216,8 @@ public class AmbientVolumePreference extends PreferenceGroup {
}
}
- void setSliderValue(int side, int value) {
+ @Override
+ public void setSliderValue(int side, int value) {
SeekBarPreference slider = mSideToSliderMap.get(side);
if (slider != null && slider.getProgress() != value) {
slider.setProgress(value);
@@ -223,7 +225,8 @@ public class AmbientVolumePreference extends PreferenceGroup {
}
}
- void setSliderRange(int side, int min, int max) {
+ @Override
+ public void setSliderRange(int side, int min, int max) {
SeekBarPreference slider = mSideToSliderMap.get(side);
if (slider != null) {
slider.setMin(min);
@@ -231,7 +234,8 @@ public class AmbientVolumePreference extends PreferenceGroup {
}
}
- void updateLayout() {
+ @Override
+ public void updateLayout() {
mSideToSliderMap.forEach((side, slider) -> {
if (side == SIDE_UNIFIED) {
slider.setVisible(!mExpanded);
@@ -279,8 +283,7 @@ public class AmbientVolumePreference extends PreferenceGroup {
mExpandIcon.setVisibility(mExpandable ? VISIBLE : GONE);
mExpandIcon.setRotation(mExpanded ? ROTATION_EXPANDED : ROTATION_COLLAPSED);
if (mExpandable) {
- final int stringRes = mExpanded
- ? R.string.bluetooth_ambient_volume_control_collapse
+ final int stringRes = mExpanded ? R.string.bluetooth_ambient_volume_control_collapse
: R.string.bluetooth_ambient_volume_control_expand;
mExpandIcon.setContentDescription(getContext().getString(stringRes));
} else {
@@ -294,8 +297,7 @@ public class AmbientVolumePreference extends PreferenceGroup {
}
mVolumeIcon.setImageLevel(mMuted ? 0 : mVolumeLevel);
if (mMutable) {
- final int stringRes = mMuted
- ? R.string.bluetooth_ambient_volume_unmute
+ final int stringRes = mMuted ? R.string.bluetooth_ambient_volume_unmute
: R.string.bluetooth_ambient_volume_mute;
mVolumeIcon.setContentDescription(getContext().getString(stringRes));
mVolumeIcon.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
@@ -304,4 +306,27 @@ public class AmbientVolumePreference extends PreferenceGroup {
mVolumeIcon.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO);
}
}
+
+ private void createSlider(int side, int order) {
+ if (mSideToSliderMap.containsKey(side)) {
+ return;
+ }
+ SeekBarPreference slider = new SeekBarPreference(getContext());
+ slider.setKey(KEY_AMBIENT_VOLUME_SLIDER + "_" + side);
+ slider.setOrder(order);
+ slider.setOnPreferenceChangeListener(mPreferenceChangeListener);
+ if (side == SIDE_LEFT) {
+ slider.setTitle(
+ getContext().getString(R.string.bluetooth_ambient_volume_control_left));
+ } else if (side == SIDE_RIGHT) {
+ slider.setTitle(
+ getContext().getString(R.string.bluetooth_ambient_volume_control_right));
+ }
+ mSideToSliderMap.put(side, slider);
+ }
+
+ @VisibleForTesting
+ Map getSliders() {
+ return mSideToSliderMap;
+ }
}
diff --git a/src/com/android/settings/bluetooth/BluetoothDetailsAmbientVolumePreferenceController.java b/src/com/android/settings/bluetooth/BluetoothDetailsAmbientVolumePreferenceController.java
index f237ffe50c3..4b0b5d4d309 100644
--- a/src/com/android/settings/bluetooth/BluetoothDetailsAmbientVolumePreferenceController.java
+++ b/src/com/android/settings/bluetooth/BluetoothDetailsAmbientVolumePreferenceController.java
@@ -16,41 +16,20 @@
package com.android.settings.bluetooth;
-import static android.bluetooth.AudioInputControl.MUTE_NOT_MUTED;
-import static android.bluetooth.AudioInputControl.MUTE_MUTED;
-import static android.bluetooth.BluetoothDevice.BOND_BONDED;
-
-import static com.android.settings.bluetooth.AmbientVolumePreference.SIDE_UNIFIED;
-import static com.android.settings.bluetooth.AmbientVolumePreference.VALID_SIDES;
import static com.android.settings.bluetooth.BluetoothDetailsHearingDeviceController.KEY_HEARING_DEVICE_GROUP;
import static com.android.settings.bluetooth.BluetoothDetailsHearingDeviceController.ORDER_AMBIENT_VOLUME;
-import static com.android.settingslib.bluetooth.HearingAidInfo.DeviceSide.SIDE_INVALID;
-import static com.android.settingslib.bluetooth.HearingAidInfo.DeviceSide.SIDE_LEFT;
-import static com.android.settingslib.bluetooth.HearingAidInfo.DeviceSide.SIDE_RIGHT;
-import static com.android.settingslib.bluetooth.HearingDeviceLocalDataManager.Data.INVALID_VOLUME;
-import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothProfile;
import android.content.Context;
-import android.util.ArraySet;
-import android.util.Log;
-import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
-import androidx.preference.Preference;
import androidx.preference.PreferenceCategory;
import androidx.preference.PreferenceFragmentCompat;
import androidx.preference.PreferenceScreen;
-import com.android.settings.R;
-import com.android.settings.widget.SeekBarPreference;
-import com.android.settingslib.bluetooth.AmbientVolumeController;
-import com.android.settingslib.bluetooth.BluetoothCallback;
+import com.android.settingslib.bluetooth.AmbientVolumeUiController;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
-import com.android.settingslib.bluetooth.HearingDeviceLocalDataManager;
-import com.android.settingslib.bluetooth.HearingDeviceLocalDataManager.Data;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.settingslib.bluetooth.VolumeControlProfile;
import com.android.settingslib.core.lifecycle.Lifecycle;
@@ -58,39 +37,21 @@ import com.android.settingslib.core.lifecycle.events.OnStart;
import com.android.settingslib.core.lifecycle.events.OnStop;
import com.android.settingslib.utils.ThreadUtils;
-import com.google.common.collect.BiMap;
-import com.google.common.collect.HashBiMap;
-
-import java.util.Map;
-import java.util.Set;
-
-/** A {@link BluetoothDetailsController} that manages ambient volume control preferences. */
-public class BluetoothDetailsAmbientVolumePreferenceController extends
- BluetoothDetailsController implements Preference.OnPreferenceChangeListener,
- HearingDeviceLocalDataManager.OnDeviceLocalDataChangeListener, OnStart, OnStop,
- AmbientVolumeController.AmbientVolumeControlCallback, BluetoothCallback {
+/** A {@link BluetoothDetailsController} that manages ambient volume preference. */
+public class BluetoothDetailsAmbientVolumePreferenceController extends BluetoothDetailsController
+ implements OnStart, OnStop {
private static final boolean DEBUG = true;
private static final String TAG = "AmbientPrefController";
static final String KEY_AMBIENT_VOLUME = "ambient_volume";
static final String KEY_AMBIENT_VOLUME_SLIDER = "ambient_volume_slider";
- private static final int ORDER_AMBIENT_VOLUME_CONTROL_UNIFIED = 0;
- private static final int ORDER_AMBIENT_VOLUME_CONTROL_SEPARATED = 1;
private final LocalBluetoothManager mBluetoothManager;
- private final Set mCachedDevices = new ArraySet<>();
- private final BiMap mSideToDeviceMap = HashBiMap.create();
- private final BiMap mSideToSliderMap = HashBiMap.create();
- private final HearingDeviceLocalDataManager mLocalDataManager;
- private final AmbientVolumeController mVolumeController;
-
- @Nullable
- private PreferenceCategory mDeviceControls;
@Nullable
private AmbientVolumePreference mPreference;
@Nullable
- private Toast mToast;
+ private AmbientVolumeUiController mAmbientUiController;
public BluetoothDetailsAmbientVolumePreferenceController(@NonNull Context context,
@NonNull LocalBluetoothManager manager,
@@ -99,45 +60,42 @@ public class BluetoothDetailsAmbientVolumePreferenceController extends
@NonNull Lifecycle lifecycle) {
super(context, fragment, device, lifecycle);
mBluetoothManager = manager;
- mLocalDataManager = new HearingDeviceLocalDataManager(context);
- mLocalDataManager.setOnDeviceLocalDataChangeListener(this,
- ThreadUtils.getBackgroundExecutor());
- mVolumeController = new AmbientVolumeController(manager.getProfileManager(), this);
}
@VisibleForTesting
- BluetoothDetailsAmbientVolumePreferenceController(@NonNull Context context,
+ public BluetoothDetailsAmbientVolumePreferenceController(@NonNull Context context,
@NonNull LocalBluetoothManager manager,
@NonNull PreferenceFragmentCompat fragment,
@NonNull CachedBluetoothDevice device,
@NonNull Lifecycle lifecycle,
- @NonNull HearingDeviceLocalDataManager localSettings,
- @NonNull AmbientVolumeController volumeController) {
+ @NonNull AmbientVolumeUiController uiController) {
super(context, fragment, device, lifecycle);
mBluetoothManager = manager;
- mLocalDataManager = localSettings;
- mVolumeController = volumeController;
+ mAmbientUiController = uiController;
}
@Override
protected void init(PreferenceScreen screen) {
- mDeviceControls = screen.findPreference(KEY_HEARING_DEVICE_GROUP);
- if (mDeviceControls == null) {
+ PreferenceCategory deviceControls = screen.findPreference(KEY_HEARING_DEVICE_GROUP);
+ if (deviceControls == null) {
return;
}
- loadDevices();
+ mPreference = new AmbientVolumePreference(deviceControls.getContext());
+ mPreference.setKey(KEY_AMBIENT_VOLUME);
+ mPreference.setOrder(ORDER_AMBIENT_VOLUME);
+ deviceControls.addPreference(mPreference);
+
+ mAmbientUiController = new AmbientVolumeUiController(mContext, mBluetoothManager,
+ mPreference);
+ mAmbientUiController.loadDevice(mCachedDevice);
}
@Override
public void onStart() {
ThreadUtils.postOnBackgroundThread(() -> {
- mBluetoothManager.getEventManager().registerCallback(this);
- mLocalDataManager.start();
- mCachedDevices.forEach(device -> {
- device.registerCallback(ThreadUtils.getBackgroundExecutor(), this);
- mVolumeController.registerCallback(ThreadUtils.getBackgroundExecutor(),
- device.getDevice());
- });
+ if (mAmbientUiController != null) {
+ mAmbientUiController.start();
+ }
});
}
@@ -153,12 +111,9 @@ public class BluetoothDetailsAmbientVolumePreferenceController extends
@Override
public void onStop() {
ThreadUtils.postOnBackgroundThread(() -> {
- mBluetoothManager.getEventManager().unregisterCallback(this);
- mLocalDataManager.stop();
- mCachedDevices.forEach(device -> {
- device.unregisterCallback(this);
- mVolumeController.unregisterCallback(device.getDevice());
- });
+ if (mAmbientUiController != null) {
+ mAmbientUiController.stop();
+ }
});
}
@@ -167,16 +122,8 @@ public class BluetoothDetailsAmbientVolumePreferenceController extends
if (!isAvailable()) {
return;
}
- boolean shouldShowAmbientControl = isAmbientControlAvailable();
- if (shouldShowAmbientControl) {
- if (mPreference != null) {
- mPreference.setVisible(true);
- }
- loadRemoteDataToUi();
- } else {
- if (mPreference != null) {
- mPreference.setVisible(false);
- }
+ if (mAmbientUiController != null) {
+ mAmbientUiController.refresh();
}
}
@@ -191,424 +138,4 @@ public class BluetoothDetailsAmbientVolumePreferenceController extends
public String getPreferenceKey() {
return KEY_AMBIENT_VOLUME;
}
-
- @Override
- public boolean onPreferenceChange(@NonNull Preference preference, @Nullable Object newValue) {
- if (preference instanceof SeekBarPreference && newValue instanceof final Integer value) {
- final int side = mSideToSliderMap.inverse().getOrDefault(preference, SIDE_INVALID);
- if (DEBUG) {
- Log.d(TAG, "onPreferenceChange: side=" + side + ", value=" + value);
- }
- setVolumeIfValid(side, value);
-
- Runnable setAmbientRunnable = () -> {
- if (side == SIDE_UNIFIED) {
- mSideToDeviceMap.forEach((s, d) -> mVolumeController.setAmbient(d, value));
- } else {
- final BluetoothDevice device = mSideToDeviceMap.get(side);
- mVolumeController.setAmbient(device, value);
- }
- };
-
- if (isControlMuted()) {
- // User drag on the volume slider when muted. Unmute the devices first.
- if (mPreference != null) {
- mPreference.setMuted(false);
- }
- for (BluetoothDevice device : mSideToDeviceMap.values()) {
- mVolumeController.setMuted(device, false);
- }
- // Restore the value before muted
- loadLocalDataToUi();
- // Delay set ambient on remote device since the immediately sequential command
- // might get failed sometimes
- mContext.getMainThreadHandler().postDelayed(setAmbientRunnable, 1000L);
- } else {
- setAmbientRunnable.run();
- }
- return true;
- }
- return false;
- }
-
- @Override
- public void onProfileConnectionStateChanged(@NonNull CachedBluetoothDevice cachedDevice,
- int state, int bluetoothProfile) {
- if (bluetoothProfile == BluetoothProfile.VOLUME_CONTROL
- && state == BluetoothProfile.STATE_CONNECTED
- && mCachedDevices.contains(cachedDevice)) {
- // After VCP connected, AICS may not ready yet and still return invalid value, delay
- // a while to wait AICS ready as a workaround
- mContext.getMainThreadHandler().postDelayed(this::refresh, 1000L);
- }
- }
-
- @Override
- public void onDeviceAttributesChanged() {
- mCachedDevices.forEach(device -> {
- device.unregisterCallback(this);
- mVolumeController.unregisterCallback(device.getDevice());
- });
- mContext.getMainExecutor().execute(() -> {
- loadDevices();
- if (!mCachedDevices.isEmpty()) {
- refresh();
- }
- ThreadUtils.postOnBackgroundThread(() ->
- mCachedDevices.forEach(device -> {
- device.registerCallback(ThreadUtils.getBackgroundExecutor(), this);
- mVolumeController.registerCallback(ThreadUtils.getBackgroundExecutor(),
- device.getDevice());
- })
- );
- });
- }
-
- @Override
- public void onDeviceLocalDataChange(@NonNull String address, @Nullable Data data) {
- if (data == null) {
- // The local data is removed because the device is unpaired, do nothing
- return;
- }
- for (BluetoothDevice device : mSideToDeviceMap.values()) {
- if (device.getAnonymizedAddress().equals(address)) {
- mContext.getMainExecutor().execute(() -> loadLocalDataToUi(device));
- return;
- }
- }
- }
-
- @Override
- public void onVolumeControlServiceConnected() {
- mCachedDevices.forEach(
- device -> mVolumeController.registerCallback(ThreadUtils.getBackgroundExecutor(),
- device.getDevice()));
- }
-
- @Override
- public void onAmbientChanged(@NonNull BluetoothDevice device, int gainSettings) {
- if (DEBUG) {
- Log.d(TAG, "onAmbientChanged, value:" + gainSettings + ", device:" + device);
- }
- Data data = mLocalDataManager.get(device);
- boolean isInitiatedFromUi = (isControlExpanded() && data.ambient() == gainSettings)
- || (!isControlExpanded() && data.groupAmbient() == gainSettings);
- if (isInitiatedFromUi) {
- // The change is initiated from UI, no need to update UI
- return;
- }
-
- // We have to check if we need to expand the controls by getting all remote
- // device's ambient value, delay for a while to wait all remote devices update
- // to the latest value to avoid unnecessary expand action.
- mContext.getMainThreadHandler().postDelayed(this::refresh, 1200L);
- }
-
- @Override
- public void onMuteChanged(@NonNull BluetoothDevice device, int mute) {
- if (DEBUG) {
- Log.d(TAG, "onMuteChanged, mute:" + mute + ", device:" + device);
- }
- boolean isInitiatedFromUi = (isControlMuted() && mute == MUTE_MUTED)
- || (!isControlMuted() && mute == MUTE_NOT_MUTED);
- if (isInitiatedFromUi) {
- // The change is initiated from UI, no need to update UI
- return;
- }
-
- // We have to check if we need to mute the devices by getting all remote
- // device's mute state, delay for a while to wait all remote devices update
- // to the latest value.
- mContext.getMainThreadHandler().postDelayed(this::refresh, 1200L);
- }
-
- @Override
- public void onCommandFailed(@NonNull BluetoothDevice device) {
- Log.w(TAG, "onCommandFailed, device:" + device);
- mContext.getMainExecutor().execute(() -> {
- showErrorToast();
- refresh();
- });
- }
-
- private void loadDevices() {
- mSideToDeviceMap.clear();
- mCachedDevices.clear();
- if (VALID_SIDES.contains(mCachedDevice.getDeviceSide())
- && mCachedDevice.getBondState() == BOND_BONDED) {
- mSideToDeviceMap.put(mCachedDevice.getDeviceSide(), mCachedDevice.getDevice());
- mCachedDevices.add(mCachedDevice);
- }
- for (CachedBluetoothDevice memberDevice : mCachedDevice.getMemberDevice()) {
- if (VALID_SIDES.contains(memberDevice.getDeviceSide())
- && memberDevice.getBondState() == BOND_BONDED) {
- mSideToDeviceMap.put(memberDevice.getDeviceSide(), memberDevice.getDevice());
- mCachedDevices.add(memberDevice);
- }
- }
- createAmbientVolumePreference();
- createSliderPreferences();
- if (mPreference != null) {
- mPreference.setExpandable(mSideToDeviceMap.size() > 1);
- mPreference.setSliders((mSideToSliderMap));
- }
- }
-
- private void createAmbientVolumePreference() {
- if (mPreference != null || mDeviceControls == null) {
- return;
- }
-
- mPreference = new AmbientVolumePreference(mDeviceControls.getContext());
- mPreference.setKey(KEY_AMBIENT_VOLUME);
- mPreference.setOrder(ORDER_AMBIENT_VOLUME);
- mPreference.setOnIconClickListener(
- new AmbientVolumePreference.OnIconClickListener() {
- @Override
- public void onExpandIconClick() {
- mSideToDeviceMap.forEach((s, d) -> {
- if (!isControlMuted()) {
- // Apply previous collapsed/expanded volume to remote device
- Data data = mLocalDataManager.get(d);
- int volume = isControlExpanded()
- ? data.ambient() : data.groupAmbient();
- mVolumeController.setAmbient(d, volume);
- }
- // Update new value to local data
- mLocalDataManager.updateAmbientControlExpanded(d, isControlExpanded());
- });
- }
-
- @Override
- public void onAmbientVolumeIconClick() {
- if (!isControlMuted()) {
- loadLocalDataToUi();
- }
- for (BluetoothDevice device : mSideToDeviceMap.values()) {
- mVolumeController.setMuted(device, isControlMuted());
- }
- }
- });
- if (mDeviceControls.findPreference(mPreference.getKey()) == null) {
- mDeviceControls.addPreference(mPreference);
- }
- }
-
- private void createSliderPreferences() {
- mSideToDeviceMap.forEach((s, d) ->
- createSliderPreference(s, ORDER_AMBIENT_VOLUME_CONTROL_SEPARATED + s));
- createSliderPreference(SIDE_UNIFIED, ORDER_AMBIENT_VOLUME_CONTROL_UNIFIED);
- }
-
- private void createSliderPreference(int side, int order) {
- if (mSideToSliderMap.containsKey(side) || mDeviceControls == null) {
- return;
- }
- SeekBarPreference preference = new SeekBarPreference(mDeviceControls.getContext());
- preference.setKey(KEY_AMBIENT_VOLUME_SLIDER + "_" + side);
- preference.setOrder(order);
- preference.setOnPreferenceChangeListener(this);
- if (side == SIDE_LEFT) {
- preference.setTitle(mContext.getString(R.string.bluetooth_ambient_volume_control_left));
- } else if (side == SIDE_RIGHT) {
- preference.setTitle(
- mContext.getString(R.string.bluetooth_ambient_volume_control_right));
- }
- mSideToSliderMap.put(side, preference);
- }
-
- /** Refreshes the control UI visibility and enabled state. */
- private void refreshControlUi() {
- if (mPreference != null) {
- boolean isAnySliderEnabled = false;
- for (Map.Entry entry : mSideToDeviceMap.entrySet()) {
- final int side = entry.getKey();
- final BluetoothDevice device = entry.getValue();
- final boolean enabled = isDeviceConnectedToVcp(device)
- && mVolumeController.isAmbientControlAvailable(device);
- isAnySliderEnabled |= enabled;
- mPreference.setSliderEnabled(side, enabled);
- }
- mPreference.setSliderEnabled(SIDE_UNIFIED, isAnySliderEnabled);
- mPreference.updateLayout();
- }
- }
-
- /** Sets the volume to the corresponding control slider. */
- private void setVolumeIfValid(int side, int volume) {
- if (volume == INVALID_VOLUME) {
- return;
- }
- if (mPreference != null) {
- mPreference.setSliderValue(side, volume);
- }
- // Update new value to local data
- if (side == SIDE_UNIFIED) {
- mSideToDeviceMap.forEach((s, d) -> mLocalDataManager.updateGroupAmbient(d, volume));
- } else {
- mLocalDataManager.updateAmbient(mSideToDeviceMap.get(side), volume);
- }
- }
-
- private void loadLocalDataToUi() {
- mSideToDeviceMap.forEach((s, d) -> loadLocalDataToUi(d));
- }
-
- private void loadLocalDataToUi(BluetoothDevice device) {
- final Data data = mLocalDataManager.get(device);
- if (DEBUG) {
- Log.d(TAG, "loadLocalDataToUi, data=" + data + ", device=" + device);
- }
- final int side = mSideToDeviceMap.inverse().getOrDefault(device, SIDE_INVALID);
- if (isDeviceConnectedToVcp(device) && !isControlMuted()) {
- setVolumeIfValid(side, data.ambient());
- setVolumeIfValid(SIDE_UNIFIED, data.groupAmbient());
- }
- setControlExpanded(data.ambientControlExpanded());
- refreshControlUi();
- }
-
- private void loadRemoteDataToUi() {
- BluetoothDevice leftDevice = mSideToDeviceMap.get(SIDE_LEFT);
- AmbientVolumeController.RemoteAmbientState leftState =
- mVolumeController.refreshAmbientState(leftDevice);
- BluetoothDevice rightDevice = mSideToDeviceMap.get(SIDE_RIGHT);
- AmbientVolumeController.RemoteAmbientState rightState =
- mVolumeController.refreshAmbientState(rightDevice);
- if (DEBUG) {
- Log.d(TAG, "loadRemoteDataToUi, left=" + leftState + ", right=" + rightState);
- }
-
- if (mPreference != null) {
- mSideToDeviceMap.forEach((side, device) -> {
- int ambientMax = mVolumeController.getAmbientMax(device);
- int ambientMin = mVolumeController.getAmbientMin(device);
- if (ambientMin != ambientMax) {
- mPreference.setSliderRange(side, ambientMin, ambientMax);
- mPreference.setSliderRange(SIDE_UNIFIED, ambientMin, ambientMax);
- }
- });
- }
-
- // Update ambient volume
- final int leftAmbient = leftState != null ? leftState.gainSetting() : INVALID_VOLUME;
- final int rightAmbient = rightState != null ? rightState.gainSetting() : INVALID_VOLUME;
- if (isControlExpanded()) {
- setVolumeIfValid(SIDE_LEFT, leftAmbient);
- setVolumeIfValid(SIDE_RIGHT, rightAmbient);
- } else {
- if (leftAmbient != rightAmbient && leftAmbient != INVALID_VOLUME
- && rightAmbient != INVALID_VOLUME) {
- setVolumeIfValid(SIDE_LEFT, leftAmbient);
- setVolumeIfValid(SIDE_RIGHT, rightAmbient);
- setControlExpanded(true);
- } else {
- int unifiedAmbient = leftAmbient != INVALID_VOLUME ? leftAmbient : rightAmbient;
- setVolumeIfValid(SIDE_UNIFIED, unifiedAmbient);
- }
- }
- // Initialize local data between side and group value
- initLocalDataIfNeeded();
-
- // Update mute state
- boolean mutable = true;
- boolean muted = true;
- if (isDeviceConnectedToVcp(leftDevice) && leftState != null) {
- mutable &= leftState.isMutable();
- muted &= leftState.isMuted();
- }
- if (isDeviceConnectedToVcp(rightDevice) && rightState != null) {
- mutable &= rightState.isMutable();
- muted &= rightState.isMuted();
- }
- if (mPreference != null) {
- mPreference.setMutable(mutable);
- mPreference.setMuted(muted);
- }
-
- // Ensure remote device mute state is synced
- syncMuteStateIfNeeded(leftDevice, leftState, muted);
- syncMuteStateIfNeeded(rightDevice, rightState, muted);
-
- refreshControlUi();
- }
-
- /** Check if any device in the group has valid ambient control points */
- private boolean isAmbientControlAvailable() {
- for (BluetoothDevice device : mSideToDeviceMap.values()) {
- // Found ambient local data for this device, show the ambient control
- if (mLocalDataManager.get(device).hasAmbientData()) {
- return true;
- }
- // Found remote ambient control points on this device, show the ambient control
- if (mVolumeController.isAmbientControlAvailable(device)) {
- return true;
- }
- }
- return false;
- }
-
- private boolean isControlExpanded() {
- return mPreference != null && mPreference.isExpanded();
- }
-
- private void setControlExpanded(boolean expanded) {
- if (mPreference != null && mPreference.isExpanded() != expanded) {
- mPreference.setExpanded(expanded);
- }
- mSideToDeviceMap.forEach((s, d) -> {
- // Update new value to local data
- mLocalDataManager.updateAmbientControlExpanded(d, expanded);
- });
- }
-
- private boolean isControlMuted() {
- return mPreference != null && mPreference.isMuted();
- }
-
- private void initLocalDataIfNeeded() {
- int smallerVolumeAmongGroup = Integer.MAX_VALUE;
- for (BluetoothDevice device : mSideToDeviceMap.values()) {
- Data data = mLocalDataManager.get(device);
- if (data.ambient() != INVALID_VOLUME) {
- smallerVolumeAmongGroup = Math.min(data.ambient(), smallerVolumeAmongGroup);
- } else if (data.groupAmbient() != INVALID_VOLUME) {
- // Initialize side ambient from group ambient value
- mLocalDataManager.updateAmbient(device, data.groupAmbient());
- }
- }
- if (smallerVolumeAmongGroup != Integer.MAX_VALUE) {
- for (BluetoothDevice device : mSideToDeviceMap.values()) {
- Data data = mLocalDataManager.get(device);
- if (data.groupAmbient() == INVALID_VOLUME) {
- // Initialize group ambient from smaller side ambient value
- mLocalDataManager.updateGroupAmbient(device, smallerVolumeAmongGroup);
- }
- }
- }
- }
-
- private void syncMuteStateIfNeeded(@Nullable BluetoothDevice device,
- @Nullable AmbientVolumeController.RemoteAmbientState state, boolean muted) {
- if (isDeviceConnectedToVcp(device) && state != null && state.isMutable()) {
- if (state.isMuted() != muted) {
- mVolumeController.setMuted(device, muted);
- }
- }
- }
-
- private boolean isDeviceConnectedToVcp(@Nullable BluetoothDevice device) {
- return device != null && device.isConnected()
- && mBluetoothManager.getProfileManager().getVolumeControlProfile()
- .getConnectionStatus(device) == BluetoothProfile.STATE_CONNECTED;
- }
-
- private void showErrorToast() {
- if (mToast != null) {
- mToast.cancel();
- }
- mToast = Toast.makeText(mContext, R.string.bluetooth_ambient_volume_error,
- Toast.LENGTH_SHORT);
- mToast.show();
- }
}
diff --git a/src/com/android/settings/display/BrightnessLevelPreference.kt b/src/com/android/settings/display/BrightnessLevelPreference.kt
index 73a2280ee9e..ca54d78b8ed 100644
--- a/src/com/android/settings/display/BrightnessLevelPreference.kt
+++ b/src/com/android/settings/display/BrightnessLevelPreference.kt
@@ -40,7 +40,7 @@ import com.android.settingslib.datastore.SettingsSystemStore
import com.android.settingslib.display.BrightnessUtils.GAMMA_SPACE_MAX
import com.android.settingslib.display.BrightnessUtils.GAMMA_SPACE_MIN
import com.android.settingslib.display.BrightnessUtils.convertLinearToGammaFloat
-import com.android.settingslib.metadata.PersistentPreference
+import com.android.settingslib.metadata.FloatPersistentPreference
import com.android.settingslib.metadata.PreferenceMetadata
import com.android.settingslib.metadata.PreferenceSummaryProvider
import com.android.settingslib.metadata.ReadWritePermit
@@ -52,7 +52,7 @@ import java.text.NumberFormat
// LINT.IfChange
class BrightnessLevelPreference :
PreferenceMetadata,
- PersistentPreference,
+ FloatPersistentPreference,
PreferenceBinding,
PreferenceRestrictionMixin,
PreferenceSummaryProvider,
@@ -78,7 +78,7 @@ class BrightnessLevelPreference :
override val useAdminDisabledSummary: Boolean
get() = true
- override fun intent(context: Context) =
+ override fun intent(context: Context): Intent? =
Intent(ACTION_SHOW_BRIGHTNESS_DIALOG)
.setPackage(Utils.SYSTEMUI_PACKAGE_NAME)
.putExtra(
diff --git a/src/com/android/settings/enterprise/ActionDisabledByAdminDialog.java b/src/com/android/settings/enterprise/ActionDisabledByAdminDialog.java
index e05ae71a05a..b0d0af1eefb 100644
--- a/src/com/android/settings/enterprise/ActionDisabledByAdminDialog.java
+++ b/src/com/android/settings/enterprise/ActionDisabledByAdminDialog.java
@@ -109,12 +109,9 @@ public class ActionDisabledByAdminDialog extends Activity
}
if (enforcingAdmin.getAuthority() instanceof UnknownAuthority authority
&& ADVANCED_PROTECTION_SYSTEM_ENTITY.equals(authority.getName())) {
- AdvancedProtectionManager apm = getSystemService(AdvancedProtectionManager.class);
- if (apm == null) {
- return;
- }
- Intent apmSupportIntent = apm.createSupportIntentForPolicyIdentifierOrRestriction(
- restriction, /* type */ null);
+ Intent apmSupportIntent = AdvancedProtectionManager
+ .createSupportIntentForPolicyIdentifierOrRestriction(restriction,
+ AdvancedProtectionManager.SUPPORT_DIALOG_TYPE_UNKNOWN);
startActivityAsUser(apmSupportIntent, UserHandle.of(userId));
finish();
} else {
diff --git a/src/com/android/settings/fuelgauge/batteryusage/PowerUsageAdvanced.java b/src/com/android/settings/fuelgauge/batteryusage/PowerUsageAdvanced.java
index 9943d0b429b..b8188b8d0ed 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/PowerUsageAdvanced.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/PowerUsageAdvanced.java
@@ -32,6 +32,8 @@ import android.util.Pair;
import androidx.annotation.VisibleForTesting;
import androidx.loader.app.LoaderManager;
import androidx.loader.content.Loader;
+import androidx.preference.PreferenceScreen;
+import androidx.recyclerview.widget.RecyclerView;
import com.android.settings.R;
import com.android.settings.SettingsActivity;
@@ -149,6 +151,13 @@ public class PowerUsageAdvanced extends PowerUsageBase {
}
}
+ @Override
+ protected RecyclerView.Adapter onCreateAdapter(PreferenceScreen preferenceScreen) {
+ final RecyclerView.Adapter adapter = super.onCreateAdapter(preferenceScreen);
+ adapter.setHasStableIds(true);
+ return adapter;
+ }
+
@Override
protected List createPreferenceControllers(Context context) {
final List controllers = new ArrayList<>();
diff --git a/src/com/android/settings/inputmethod/PointerFillStylePreference.java b/src/com/android/settings/inputmethod/PointerFillStylePreference.java
index 74284d64250..9c9d076d4d9 100644
--- a/src/com/android/settings/inputmethod/PointerFillStylePreference.java
+++ b/src/com/android/settings/inputmethod/PointerFillStylePreference.java
@@ -25,6 +25,9 @@ import static android.view.PointerIcon.POINTER_ICON_VECTOR_STYLE_FILL_RED;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Color;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.LayerDrawable;
+import android.graphics.drawable.StateListDrawable;
import android.provider.Settings;
import android.util.AttributeSet;
import android.view.PointerIcon;
@@ -41,6 +44,11 @@ import com.android.settings.R;
public class PointerFillStylePreference extends Preference {
+ private static final int[] STATE_HOVERED_SELECTED =
+ new int[]{android.R.attr.state_hovered, android.R.attr.state_selected};
+ private static final int[] STATE_SELECTED = new int[]{android.R.attr.state_selected};
+ private static final int[] STATE_HOVERED = new int[]{android.R.attr.state_hovered};
+ private static final int[] STATE_DEFAULT = new int[]{};
@Nullable private LinearLayout mButtonHolder;
@@ -82,11 +90,7 @@ public class PointerFillStylePreference extends Preference {
if (button == null) {
return;
}
- int[] attrs = {com.android.internal.R.attr.pointerIconVectorFill};
- try (TypedArray ta = getContext().obtainStyledAttributes(
- PointerIcon.vectorFillStyleToResource(style), attrs)) {
- button.getBackground().setTint(ta.getColor(0, Color.BLACK));
- }
+ tintButtonByStyle(button, style);
button.setOnClickListener(
(v) -> {
getPreferenceDataStore().putInt(Settings.System.POINTER_FILL_STYLE, style);
@@ -96,6 +100,32 @@ public class PointerFillStylePreference extends Preference {
button.setPointerIcon(PointerIcon.getSystemIcon(getContext(), PointerIcon.TYPE_ARROW));
}
+ private void tintButtonByStyle(ImageView button, int style) {
+ int[] attrs = {com.android.internal.R.attr.pointerIconVectorFill};
+ try (TypedArray ta = getContext().obtainStyledAttributes(
+ PointerIcon.vectorFillStyleToResource(style), attrs)) {
+ // Index 0, as there is only one attribute returned here.
+ int color = ta.getColor(/* index= */ 0, Color.BLACK);
+ StateListDrawable stateListDrawable = (StateListDrawable) button.getDrawable();
+ tintDrawableByLayerId(stateListDrawable, STATE_HOVERED_SELECTED,
+ R.id.tintableCircleHoveredSelected, color);
+ tintDrawableByLayerId(stateListDrawable, STATE_SELECTED, R.id.tintableCircleSelected,
+ color);
+ tintDrawableByLayerId(stateListDrawable, STATE_HOVERED, R.id.tintableCircleHovered,
+ color);
+ tintDrawableByLayerId(stateListDrawable, STATE_DEFAULT, R.id.tintableCircleDefault,
+ color);
+ }
+ }
+
+ private void tintDrawableByLayerId(StateListDrawable stateListDrawable, int[] stateSet,
+ int layerId, int color) {
+ int index = stateListDrawable.findStateDrawableIndex(stateSet);
+ LayerDrawable layerDrawable = (LayerDrawable) stateListDrawable.getStateDrawable(index);
+ Drawable drawable = layerDrawable.findDrawableByLayerId(layerId);
+ drawable.setTint(color);
+ }
+
private void setButtonChecked(int id) {
if (mButtonHolder == null) {
return;
diff --git a/src/com/android/settings/network/MobileNetworkRepository.java b/src/com/android/settings/network/MobileNetworkRepository.java
index f5763eb4847..e7642f4b95f 100644
--- a/src/com/android/settings/network/MobileNetworkRepository.java
+++ b/src/com/android/settings/network/MobileNetworkRepository.java
@@ -54,6 +54,7 @@ import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@@ -345,6 +346,7 @@ public class MobileNetworkRepository extends SubscriptionManager.OnSubscriptions
List availableSubInfoEntityList) {
List activeSubInfoEntityList =
availableSubInfoEntityList.stream()
+ .filter(entity -> Objects.nonNull(entity))
.filter(SubscriptionInfoEntity::isActiveSubscription)
.filter(SubscriptionInfoEntity::isSubscriptionVisible)
.collect(Collectors.toList());
diff --git a/src/com/android/settings/security/ActionDisabledByAdvancedProtectionDialog.kt b/src/com/android/settings/security/ActionDisabledByAdvancedProtectionDialog.kt
new file mode 100644
index 00000000000..d56f8958ac3
--- /dev/null
+++ b/src/com/android/settings/security/ActionDisabledByAdvancedProtectionDialog.kt
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.security;
+
+import android.app.Activity
+import android.content.DialogInterface
+import android.os.Bundle
+import android.view.View
+import android.view.ViewGroup
+import android.widget.TextView
+import com.android.settings.R
+
+import androidx.appcompat.app.AlertDialog;
+
+class ActionDisabledByAdvancedProtectionDialog : Activity(), DialogInterface.OnDismissListener {
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ val dialogView = layoutInflater.inflate(R.layout.support_details_dialog, null) as ViewGroup
+ val builder = AlertDialog.Builder(this)
+ .setPositiveButton(R.string.okay, null)
+ .setView(dialogView)
+ .setOnDismissListener(this)
+ initializeDialogView(dialogView)
+ builder.show()
+ }
+
+ override fun onDismiss(dialog: DialogInterface) {
+ finish()
+ }
+
+ private fun initializeDialogView(dialogView: View) {
+ setSupportTitle(dialogView)
+ setSupportDetails(dialogView)
+ }
+
+ private fun setSupportTitle(root: View) {
+ val titleView: TextView = root.findViewById(R.id.admin_support_dialog_title) ?: return
+ titleView.setText(R.string.disabled_by_advanced_protection_title)
+ }
+
+ private fun setSupportDetails(root: View) {
+ val textView: TextView = root.findViewById(R.id.admin_support_msg)
+ textView.setText(R.string.disabled_by_advanced_protection_message)
+ }
+}
diff --git a/src/com/android/settings/service/PreferenceServiceRequestTransformer.kt b/src/com/android/settings/service/PreferenceServiceRequestTransformer.kt
index ce7624a956c..2fe27542667 100644
--- a/src/com/android/settings/service/PreferenceServiceRequestTransformer.kt
+++ b/src/com/android/settings/service/PreferenceServiceRequestTransformer.kt
@@ -204,5 +204,7 @@ private fun PreferenceProto.toMetadata(
.setWritable(persistent)
.setLaunchIntent(launchIntent.toIntent())
.setWriteSensitivity(sensitivity)
+ .setReadPermissions(readPermissionsList)
+ .setWritePermissions(writePermissionsList)
.build()
}
diff --git a/src/com/android/settings/widget/SeekBarPreference.java b/src/com/android/settings/widget/SeekBarPreference.java
index 3dd72f908fe..78f2fa5fe2a 100644
--- a/src/com/android/settings/widget/SeekBarPreference.java
+++ b/src/com/android/settings/widget/SeekBarPreference.java
@@ -142,9 +142,13 @@ public class SeekBarPreference extends RestrictedPreference
mSeekBar.setContentDescription(mSeekBarContentDescription);
} else if (!TextUtils.isEmpty(title)) {
mSeekBar.setContentDescription(title);
+ } else {
+ mSeekBar.setContentDescription(null);
}
if (!TextUtils.isEmpty(mSeekBarStateDescription)) {
mSeekBar.setStateDescription(mSeekBarStateDescription);
+ } else {
+ mSeekBar.setStateDescription(null);
}
if (mSeekBar instanceof DefaultIndicatorSeekBar) {
((DefaultIndicatorSeekBar) mSeekBar).setDefaultProgress(mDefaultProgress);
diff --git a/src/com/android/settings/wifi/WepNetworksPreferenceController.kt b/src/com/android/settings/wifi/WepNetworksPreferenceController.kt
index 92716bec4ff..59c67eef9ff 100644
--- a/src/com/android/settings/wifi/WepNetworksPreferenceController.kt
+++ b/src/com/android/settings/wifi/WepNetworksPreferenceController.kt
@@ -162,10 +162,10 @@ class WepNetworksPreferenceController(context: Context, preferenceKey: String) :
emit(aapmManager?.isAdvancedProtectionEnabled ?: false) }.flowOn(Dispatchers.Default)
private fun startSupportIntent() {
- aapmManager?.createSupportIntent(
+ AdvancedProtectionManager.createSupportIntent(
AdvancedProtectionManager.FEATURE_ID_DISALLOW_WEP,
AdvancedProtectionManager.SUPPORT_DIALOG_TYPE_DISABLED_SETTING
- )?.let { mContext.startActivity(it) }
+ ).let { mContext.startActivity(it) }
}
val wepAllowedFlow =
diff --git a/tests/robotests/src/com/android/settings/accessibility/HighContrastTextMigrationReceiverTest.java b/tests/robotests/src/com/android/settings/accessibility/HighContrastTextMigrationReceiverTest.java
index 0fedddc7416..1b663936fcb 100644
--- a/tests/robotests/src/com/android/settings/accessibility/HighContrastTextMigrationReceiverTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/HighContrastTextMigrationReceiverTest.java
@@ -203,7 +203,7 @@ public class HighContrastTextMigrationReceiverTest {
ShadowNotification shadowNotification = Shadows.shadowOf(notification);
assertThat(shadowNotification.getContentTitle()).isEqualTo(mContext.getString(
- R.string.accessibility_toggle_high_text_contrast_preference_title));
+ R.string.accessibility_notification_high_contrast_text_title));
assertThat(shadowNotification.getContentText()).isEqualTo(
mContext.getString(R.string.accessibility_notification_high_contrast_text_content));
diff --git a/tests/robotests/src/com/android/settings/bluetooth/AmbientVolumePreferenceTest.java b/tests/robotests/src/com/android/settings/bluetooth/AmbientVolumePreferenceTest.java
index ec406c45503..115f642d19b 100644
--- a/tests/robotests/src/com/android/settings/bluetooth/AmbientVolumePreferenceTest.java
+++ b/tests/robotests/src/com/android/settings/bluetooth/AmbientVolumePreferenceTest.java
@@ -26,8 +26,10 @@ import static com.android.settingslib.bluetooth.HearingAidInfo.DeviceSide.SIDE_R
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
+import android.bluetooth.BluetoothDevice;
import android.content.Context;
import android.util.ArrayMap;
import android.view.View;
@@ -40,6 +42,7 @@ import androidx.test.core.app.ApplicationProvider;
import com.android.settings.R;
import com.android.settings.widget.SeekBarPreference;
+import com.android.settingslib.bluetooth.AmbientVolumeUi;
import org.junit.Before;
import org.junit.Rule;
@@ -69,14 +72,14 @@ public class AmbientVolumePreferenceTest {
@Spy
private Context mContext = ApplicationProvider.getApplicationContext();
@Mock
- private AmbientVolumePreference.OnIconClickListener mListener;
+ private AmbientVolumeUi.AmbientVolumeUiListener mListener;
@Mock
private View mItemView;
private AmbientVolumePreference mPreference;
private ImageView mExpandIcon;
private ImageView mVolumeIcon;
- private final Map mSideToSlidersMap = new ArrayMap<>();
+ private final Map mSideToDeviceMap = new ArrayMap<>();
@Before
public void setUp() {
@@ -84,13 +87,27 @@ public class AmbientVolumePreferenceTest {
PreferenceScreen preferenceScreen = preferenceManager.createPreferenceScreen(mContext);
mPreference = new AmbientVolumePreference(mContext);
mPreference.setKey(KEY_AMBIENT_VOLUME);
- mPreference.setOnIconClickListener(mListener);
+ mPreference.setListener(mListener);
mPreference.setExpandable(true);
mPreference.setMutable(true);
preferenceScreen.addPreference(mPreference);
- prepareSliders();
- mPreference.setSliders(mSideToSlidersMap);
+ prepareDevices();
+ mPreference.setupSliders(mSideToDeviceMap);
+ mPreference.getSliders().forEach((side, slider) -> {
+ slider.setMin(0);
+ slider.setMax(4);
+ if (side == SIDE_LEFT) {
+ slider.setKey(KEY_LEFT_SLIDER);
+ slider.setProgress(TEST_LEFT_VOLUME_LEVEL);
+ } else if (side == SIDE_RIGHT) {
+ slider.setKey(KEY_RIGHT_SLIDER);
+ slider.setProgress(TEST_RIGHT_VOLUME_LEVEL);
+ } else {
+ slider.setKey(KEY_UNIFIED_SLIDER);
+ slider.setProgress(TEST_UNIFIED_VOLUME_LEVEL);
+ }
+ });
mExpandIcon = new ImageView(mContext);
mVolumeIcon = new ImageView(mContext);
@@ -206,33 +223,16 @@ public class AmbientVolumePreferenceTest {
private void assertControlUiCorrect() {
final boolean expanded = mPreference.isExpanded();
- assertThat(mSideToSlidersMap.get(SIDE_UNIFIED).isVisible()).isEqualTo(!expanded);
- assertThat(mSideToSlidersMap.get(SIDE_LEFT).isVisible()).isEqualTo(expanded);
- assertThat(mSideToSlidersMap.get(SIDE_RIGHT).isVisible()).isEqualTo(expanded);
+ Map sliders = mPreference.getSliders();
+ assertThat(sliders.get(SIDE_UNIFIED).isVisible()).isEqualTo(!expanded);
+ assertThat(sliders.get(SIDE_LEFT).isVisible()).isEqualTo(expanded);
+ assertThat(sliders.get(SIDE_RIGHT).isVisible()).isEqualTo(expanded);
final float rotation = expanded ? ROTATION_EXPANDED : ROTATION_COLLAPSED;
assertThat(mExpandIcon.getRotation()).isEqualTo(rotation);
}
- private void prepareSliders() {
- prepareSlider(SIDE_UNIFIED);
- prepareSlider(SIDE_LEFT);
- prepareSlider(SIDE_RIGHT);
- }
-
- private void prepareSlider(int side) {
- SeekBarPreference slider = new SeekBarPreference(mContext);
- slider.setMin(0);
- slider.setMax(4);
- if (side == SIDE_LEFT) {
- slider.setKey(KEY_LEFT_SLIDER);
- slider.setProgress(TEST_LEFT_VOLUME_LEVEL);
- } else if (side == SIDE_RIGHT) {
- slider.setKey(KEY_RIGHT_SLIDER);
- slider.setProgress(TEST_RIGHT_VOLUME_LEVEL);
- } else {
- slider.setKey(KEY_UNIFIED_SLIDER);
- slider.setProgress(TEST_UNIFIED_VOLUME_LEVEL);
- }
- mSideToSlidersMap.put(side, slider);
+ private void prepareDevices() {
+ mSideToDeviceMap.put(SIDE_LEFT, mock(BluetoothDevice.class));
+ mSideToDeviceMap.put(SIDE_RIGHT, mock(BluetoothDevice.class));
}
}
diff --git a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsAmbientVolumePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsAmbientVolumePreferenceControllerTest.java
index 975d3b491aa..fb10d09f350 100644
--- a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsAmbientVolumePreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsAmbientVolumePreferenceControllerTest.java
@@ -16,46 +16,25 @@
package com.android.settings.bluetooth;
-import static android.bluetooth.AudioInputControl.MUTE_DISABLED;
-import static android.bluetooth.AudioInputControl.MUTE_NOT_MUTED;
-import static android.bluetooth.AudioInputControl.MUTE_MUTED;
-import static android.bluetooth.BluetoothDevice.BOND_BONDED;
-
import static com.android.settings.bluetooth.BluetoothDetailsAmbientVolumePreferenceController.KEY_AMBIENT_VOLUME;
-import static com.android.settings.bluetooth.BluetoothDetailsAmbientVolumePreferenceController.KEY_AMBIENT_VOLUME_SLIDER;
import static com.android.settings.bluetooth.BluetoothDetailsHearingDeviceController.KEY_HEARING_DEVICE_GROUP;
-import static com.android.settingslib.bluetooth.HearingAidInfo.DeviceSide.SIDE_LEFT;
-import static com.android.settingslib.bluetooth.HearingAidInfo.DeviceSide.SIDE_RIGHT;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyBoolean;
-import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import static org.robolectric.Shadows.shadowOf;
-import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothProfile;
-import android.content.ContentResolver;
import android.os.Handler;
-import android.os.Looper;
-import android.provider.Settings;
import androidx.preference.PreferenceCategory;
import com.android.settings.testutils.shadow.ShadowThreadUtils;
-import com.android.settings.widget.SeekBarPreference;
-import com.android.settingslib.bluetooth.AmbientVolumeController;
+import com.android.settingslib.bluetooth.AmbientVolumeUiController;
import com.android.settingslib.bluetooth.BluetoothEventManager;
-import com.android.settingslib.bluetooth.CachedBluetoothDevice;
-import com.android.settingslib.bluetooth.HearingDeviceLocalDataManager;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
import com.android.settingslib.bluetooth.VolumeControlProfile;
@@ -69,41 +48,19 @@ import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
-import org.robolectric.annotation.Implementation;
-import org.robolectric.annotation.Implements;
-import org.robolectric.shadows.ShadowSettings;
-import java.util.HashMap;
import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.Executor;
/** Tests for {@link BluetoothDetailsAmbientVolumePreferenceController}. */
@RunWith(RobolectricTestRunner.class)
@Config(shadows = {
- BluetoothDetailsAmbientVolumePreferenceControllerTest.ShadowGlobal.class,
ShadowThreadUtils.class
})
public class BluetoothDetailsAmbientVolumePreferenceControllerTest extends
BluetoothDetailsControllerTestBase {
-
@Rule
public final MockitoRule mMockitoRule = MockitoJUnit.rule();
- private static final String LEFT_CONTROL_KEY = KEY_AMBIENT_VOLUME_SLIDER + "_" + SIDE_LEFT;
- private static final String RIGHT_CONTROL_KEY = KEY_AMBIENT_VOLUME_SLIDER + "_" + SIDE_RIGHT;
- private static final String TEST_ADDRESS = "00:00:00:00:11";
- private static final String TEST_MEMBER_ADDRESS = "00:00:00:00:22";
-
- @Mock
- private CachedBluetoothDevice mCachedMemberDevice;
- @Mock
- private BluetoothDevice mDevice;
- @Mock
- private BluetoothDevice mMemberDevice;
- @Mock
- private HearingDeviceLocalDataManager mLocalDataManager;
@Mock
private LocalBluetoothManager mBluetoothManager;
@Mock
@@ -113,9 +70,9 @@ public class BluetoothDetailsAmbientVolumePreferenceControllerTest extends
@Mock
private VolumeControlProfile mVolumeControlProfile;
@Mock
- private AmbientVolumeController mVolumeController;
- @Mock
private Handler mTestHandler;
+ @Mock
+ private AmbientVolumeUiController mUiController;
private BluetoothDetailsAmbientVolumePreferenceController mController;
@@ -124,24 +81,16 @@ public class BluetoothDetailsAmbientVolumePreferenceControllerTest extends
super.setUp();
mContext = spy(mContext);
+
+ when(mBluetoothManager.getProfileManager()).thenReturn(mProfileManager);
+ when(mBluetoothManager.getEventManager()).thenReturn(mEventManager);
+ mController = spy(
+ new BluetoothDetailsAmbientVolumePreferenceController(mContext, mBluetoothManager,
+ mFragment, mCachedDevice, mLifecycle, mUiController));
+
PreferenceCategory deviceControls = new PreferenceCategory(mContext);
deviceControls.setKey(KEY_HEARING_DEVICE_GROUP);
mScreen.addPreference(deviceControls);
- mController = spy(
- new BluetoothDetailsAmbientVolumePreferenceController(mContext, mBluetoothManager,
- mFragment, mCachedDevice, mLifecycle, mLocalDataManager,
- mVolumeController));
-
- when(mBluetoothManager.getEventManager()).thenReturn(mEventManager);
- when(mBluetoothManager.getProfileManager()).thenReturn(mProfileManager);
- when(mProfileManager.getVolumeControlProfile()).thenReturn(mVolumeControlProfile);
- when(mVolumeControlProfile.getConnectionStatus(mDevice)).thenReturn(
- BluetoothProfile.STATE_CONNECTED);
- when(mVolumeControlProfile.getConnectionStatus(mMemberDevice)).thenReturn(
- BluetoothProfile.STATE_CONNECTED);
- when(mCachedDevice.getProfiles()).thenReturn(List.of(mVolumeControlProfile));
- when(mLocalDataManager.get(any(BluetoothDevice.class))).thenReturn(
- new HearingDeviceLocalDataManager.Data.Builder().build());
when(mContext.getMainThreadHandler()).thenReturn(mTestHandler);
when(mTestHandler.postDelayed(any(Runnable.class), anyLong())).thenAnswer(
@@ -152,283 +101,42 @@ public class BluetoothDetailsAmbientVolumePreferenceControllerTest extends
}
@Test
- public void init_deviceWithoutMember_controlNotExpandable() {
- prepareDevice(/* hasMember= */ false);
-
+ public void init_preferenceAdded() {
mController.init(mScreen);
AmbientVolumePreference preference = mScreen.findPreference(KEY_AMBIENT_VOLUME);
assertThat(preference).isNotNull();
- assertThat(preference.isExpandable()).isFalse();
}
@Test
- public void init_deviceWithMember_controlExpandable() {
- prepareDevice(/* hasMember= */ true);
+ public void refresh_deviceNotSupportVcp_verifyUiControllerNoRefresh() {
+ when(mCachedDevice.getProfiles()).thenReturn(List.of());
- mController.init(mScreen);
+ mController.refresh();
- AmbientVolumePreference preference = mScreen.findPreference(KEY_AMBIENT_VOLUME);
- assertThat(preference).isNotNull();
- assertThat(preference.isExpandable()).isTrue();
+ verify(mUiController, never()).refresh();
}
@Test
- public void onDeviceLocalDataChange_noMemberAndExpanded_uiCorrectAndDataUpdated() {
- prepareDevice(/* hasMember= */ false);
- mController.init(mScreen);
- HearingDeviceLocalDataManager.Data data = new HearingDeviceLocalDataManager.Data.Builder()
- .ambient(0).groupAmbient(0).ambientControlExpanded(true).build();
- when(mLocalDataManager.get(mDevice)).thenReturn(data);
+ public void refresh_deviceSupportVcp_verifyUiControllerRefresh() {
+ when(mCachedDevice.getProfiles()).thenReturn(List.of(mVolumeControlProfile));
- mController.onDeviceLocalDataChange(TEST_ADDRESS, data);
- shadowOf(Looper.getMainLooper()).idle();
+ mController.refresh();
- AmbientVolumePreference preference = mScreen.findPreference(KEY_AMBIENT_VOLUME);
- assertThat(preference).isNotNull();
- assertThat(preference.isExpanded()).isFalse();
- verifyDeviceDataUpdated(mDevice);
+ verify(mUiController).refresh();
}
@Test
- public void onDeviceLocalDataChange_noMemberAndCollapsed_uiCorrectAndDataUpdated() {
- prepareDevice(/* hasMember= */ false);
- mController.init(mScreen);
- HearingDeviceLocalDataManager.Data data = new HearingDeviceLocalDataManager.Data.Builder()
- .ambient(0).groupAmbient(0).ambientControlExpanded(false).build();
- when(mLocalDataManager.get(mDevice)).thenReturn(data);
-
- mController.onDeviceLocalDataChange(TEST_ADDRESS, data);
- shadowOf(Looper.getMainLooper()).idle();
-
- AmbientVolumePreference preference = mScreen.findPreference(KEY_AMBIENT_VOLUME);
- assertThat(preference).isNotNull();
- assertThat(preference.isExpanded()).isFalse();
- verifyDeviceDataUpdated(mDevice);
- }
-
- @Test
- public void onDeviceLocalDataChange_hasMemberAndExpanded_uiCorrectAndDataUpdated() {
- prepareDevice(/* hasMember= */ true);
- mController.init(mScreen);
- HearingDeviceLocalDataManager.Data data = new HearingDeviceLocalDataManager.Data.Builder()
- .ambient(0).groupAmbient(0).ambientControlExpanded(true).build();
- when(mLocalDataManager.get(mDevice)).thenReturn(data);
-
- mController.onDeviceLocalDataChange(TEST_ADDRESS, data);
- shadowOf(Looper.getMainLooper()).idle();
-
- AmbientVolumePreference preference = mScreen.findPreference(KEY_AMBIENT_VOLUME);
- assertThat(preference).isNotNull();
- assertThat(preference.isExpanded()).isTrue();
- verifyDeviceDataUpdated(mDevice);
- }
-
- @Test
- public void onDeviceLocalDataChange_hasMemberAndCollapsed_uiCorrectAndDataUpdated() {
- prepareDevice(/* hasMember= */ true);
- mController.init(mScreen);
- HearingDeviceLocalDataManager.Data data = new HearingDeviceLocalDataManager.Data.Builder()
- .ambient(0).groupAmbient(0).ambientControlExpanded(false).build();
- when(mLocalDataManager.get(mDevice)).thenReturn(data);
-
- mController.onDeviceLocalDataChange(TEST_ADDRESS, data);
- shadowOf(Looper.getMainLooper()).idle();
-
- AmbientVolumePreference preference = mScreen.findPreference(KEY_AMBIENT_VOLUME);
- assertThat(preference).isNotNull();
- assertThat(preference.isExpanded()).isFalse();
- verifyDeviceDataUpdated(mDevice);
- }
-
- @Test
- public void onStart_localDataManagerStartAndCallbackRegistered() {
- prepareDevice(/* hasMember= */ true);
- mController.init(mScreen);
-
+ public void onStart_verifyUiControllerStart() {
mController.onStart();
- verify(mLocalDataManager, atLeastOnce()).start();
- verify(mVolumeController).registerCallback(any(Executor.class), eq(mDevice));
- verify(mVolumeController).registerCallback(any(Executor.class), eq(mMemberDevice));
- verify(mCachedDevice).registerCallback(any(Executor.class),
- any(CachedBluetoothDevice.Callback.class));
- verify(mCachedMemberDevice).registerCallback(any(Executor.class),
- any(CachedBluetoothDevice.Callback.class));
+ verify(mUiController).start();
}
@Test
- public void onStop_localDataManagerStopAndCallbackUnregistered() {
- prepareDevice(/* hasMember= */ true);
- mController.init(mScreen);
-
+ public void onStop_verifyUiControllerStop() {
mController.onStop();
- verify(mLocalDataManager).stop();
- verify(mVolumeController).unregisterCallback(mDevice);
- verify(mVolumeController).unregisterCallback(mMemberDevice);
- verify(mCachedDevice).unregisterCallback(any(CachedBluetoothDevice.Callback.class));
- verify(mCachedMemberDevice).unregisterCallback(any(CachedBluetoothDevice.Callback.class));
- }
-
- @Test
- public void onDeviceAttributesChanged_newDevice_newPreference() {
- prepareDevice(/* hasMember= */ false);
- mController.init(mScreen);
-
- // check the right control is null before onDeviceAttributesChanged()
- SeekBarPreference leftControl = mScreen.findPreference(LEFT_CONTROL_KEY);
- SeekBarPreference rightControl = mScreen.findPreference(RIGHT_CONTROL_KEY);
- assertThat(leftControl).isNotNull();
- assertThat(rightControl).isNull();
-
- prepareDevice(/* hasMember= */ true);
- mController.onDeviceAttributesChanged();
- shadowOf(Looper.getMainLooper()).idle();
-
- // check the right control is created after onDeviceAttributesChanged()
- SeekBarPreference updatedLeftControl = mScreen.findPreference(LEFT_CONTROL_KEY);
- SeekBarPreference updatedRightControl = mScreen.findPreference(RIGHT_CONTROL_KEY);
- assertThat(updatedLeftControl).isEqualTo(leftControl);
- assertThat(updatedRightControl).isNotNull();
- }
-
- @Test
- public void onAmbientChanged_refreshWhenNotInitiateFromUi() {
- prepareDevice(/* hasMember= */ false);
- mController.init(mScreen);
- final int testAmbient = 10;
- HearingDeviceLocalDataManager.Data data = new HearingDeviceLocalDataManager.Data.Builder()
- .ambient(testAmbient)
- .groupAmbient(testAmbient)
- .ambientControlExpanded(false)
- .build();
- when(mLocalDataManager.get(mDevice)).thenReturn(data);
- getPreference().setExpanded(true);
-
- mController.onAmbientChanged(mDevice, testAmbient);
- verify(mController, never()).refresh();
-
- final int updatedTestAmbient = 20;
- mController.onAmbientChanged(mDevice, updatedTestAmbient);
- verify(mController).refresh();
- }
-
- @Test
- public void onMuteChanged_refreshWhenNotInitiateFromUi() {
- prepareDevice(/* hasMember= */ false);
- mController.init(mScreen);
- final int testMute = MUTE_NOT_MUTED;
- AmbientVolumeController.RemoteAmbientState state =
- new AmbientVolumeController.RemoteAmbientState(testMute, 0);
- when(mVolumeController.refreshAmbientState(mDevice)).thenReturn(state);
- getPreference().setMuted(false);
-
- mController.onMuteChanged(mDevice, testMute);
- verify(mController, never()).refresh();
-
- final int updatedTestMute = MUTE_MUTED;
- mController.onMuteChanged(mDevice, updatedTestMute);
- verify(mController).refresh();
- }
-
- @Test
- public void refresh_leftAndRightDifferentGainSetting_expandControl() {
- prepareDevice(/* hasMember= */ true);
- mController.init(mScreen);
- prepareRemoteData(mDevice, 10, MUTE_NOT_MUTED);
- prepareRemoteData(mMemberDevice, 20, MUTE_NOT_MUTED);
- getPreference().setExpanded(false);
-
- mController.refresh();
-
- assertThat(getPreference().isExpanded()).isTrue();
- }
-
- @Test
- public void refresh_oneSideNotMutable_controlNotMutableAndNotMuted() {
- prepareDevice(/* hasMember= */ true);
- mController.init(mScreen);
- prepareRemoteData(mDevice, 10, MUTE_DISABLED);
- prepareRemoteData(mMemberDevice, 20, MUTE_NOT_MUTED);
- getPreference().setMutable(true);
- getPreference().setMuted(true);
-
- mController.refresh();
-
- assertThat(getPreference().isMutable()).isFalse();
- assertThat(getPreference().isMuted()).isFalse();
- }
-
- @Test
- public void refresh_oneSideNotMuted_controlNotMutedAndSyncToRemote() {
- prepareDevice(/* hasMember= */ true);
- mController.init(mScreen);
- prepareRemoteData(mDevice, 10, MUTE_MUTED);
- prepareRemoteData(mMemberDevice, 20, MUTE_NOT_MUTED);
- getPreference().setMutable(true);
- getPreference().setMuted(true);
-
- mController.refresh();
-
- assertThat(getPreference().isMutable()).isTrue();
- assertThat(getPreference().isMuted()).isFalse();
- verify(mVolumeController).setMuted(mDevice, false);
- }
-
- private void prepareDevice(boolean hasMember) {
- when(mCachedDevice.getDeviceSide()).thenReturn(SIDE_LEFT);
- when(mCachedDevice.getDevice()).thenReturn(mDevice);
- when(mCachedDevice.getBondState()).thenReturn(BOND_BONDED);
- when(mDevice.getAddress()).thenReturn(TEST_ADDRESS);
- when(mDevice.getAnonymizedAddress()).thenReturn(TEST_ADDRESS);
- when(mDevice.isConnected()).thenReturn(true);
- if (hasMember) {
- when(mCachedDevice.getMemberDevice()).thenReturn(Set.of(mCachedMemberDevice));
- when(mCachedMemberDevice.getDeviceSide()).thenReturn(SIDE_RIGHT);
- when(mCachedMemberDevice.getDevice()).thenReturn(mMemberDevice);
- when(mCachedMemberDevice.getBondState()).thenReturn(BOND_BONDED);
- when(mMemberDevice.getAddress()).thenReturn(TEST_MEMBER_ADDRESS);
- when(mMemberDevice.getAnonymizedAddress()).thenReturn(TEST_MEMBER_ADDRESS);
- when(mMemberDevice.isConnected()).thenReturn(true);
- }
- }
-
- private void prepareRemoteData(BluetoothDevice device, int gainSetting, int mute) {
- when(mVolumeController.isAmbientControlAvailable(device)).thenReturn(true);
- when(mVolumeController.refreshAmbientState(device)).thenReturn(
- new AmbientVolumeController.RemoteAmbientState(gainSetting, mute));
- }
-
- private void verifyDeviceDataUpdated(BluetoothDevice device) {
- verify(mLocalDataManager, atLeastOnce()).updateAmbient(eq(device), anyInt());
- verify(mLocalDataManager, atLeastOnce()).updateGroupAmbient(eq(device), anyInt());
- verify(mLocalDataManager, atLeastOnce()).updateAmbientControlExpanded(eq(device),
- anyBoolean());
- }
-
- private AmbientVolumePreference getPreference() {
- return mScreen.findPreference(KEY_AMBIENT_VOLUME);
- }
-
- @Implements(value = Settings.Global.class)
- public static class ShadowGlobal extends ShadowSettings.ShadowGlobal {
- private static final Map> sDataMap = new HashMap<>();
-
- @Implementation
- protected static boolean putStringForUser(
- ContentResolver cr, String name, String value, int userHandle) {
- get(cr).put(name, value);
- return true;
- }
-
- @Implementation
- protected static String getStringForUser(ContentResolver cr, String name, int userHandle) {
- return get(cr).get(name);
- }
-
- private static Map get(ContentResolver cr) {
- return sDataMap.computeIfAbsent(cr, k -> new HashMap<>());
- }
+ verify(mUiController).stop();
}
}
diff --git a/tests/robotests/src/com/android/settings/enterprise/ActionDisabledByAdminDialogTest.java b/tests/robotests/src/com/android/settings/enterprise/ActionDisabledByAdminDialogTest.java
index 4b7abec906a..37e04247f89 100644
--- a/tests/robotests/src/com/android/settings/enterprise/ActionDisabledByAdminDialogTest.java
+++ b/tests/robotests/src/com/android/settings/enterprise/ActionDisabledByAdminDialogTest.java
@@ -20,9 +20,14 @@ import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static android.security.advancedprotection.AdvancedProtectionManager.ACTION_SHOW_ADVANCED_PROTECTION_SUPPORT_DIALOG;
import static android.security.advancedprotection.AdvancedProtectionManager.ADVANCED_PROTECTION_SYSTEM_ENTITY;
import static android.security.advancedprotection.AdvancedProtectionManager.EXTRA_SUPPORT_DIALOG_FEATURE;
+import static android.security.advancedprotection.AdvancedProtectionManager.EXTRA_SUPPORT_DIALOG_TYPE;
+import static android.security.advancedprotection.AdvancedProtectionManager.FEATURE_ID_DISALLOW_INSTALL_UNKNOWN_SOURCES;
+import static android.security.advancedprotection.AdvancedProtectionManager.SUPPORT_DIALOG_TYPE_UNKNOWN;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
@@ -40,7 +45,6 @@ import android.os.UserManager;
import android.platform.test.annotations.RequiresFlagsEnabled;
import android.platform.test.flag.junit.CheckFlagsRule;
import android.platform.test.flag.junit.DeviceFlagsValueProvider;
-import android.security.advancedprotection.AdvancedProtectionManager;
import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
@@ -48,6 +52,7 @@ import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
@@ -59,8 +64,6 @@ public class ActionDisabledByAdminDialogTest {
@Mock
private DevicePolicyManager mDevicePolicyManager;
- @Mock
- private AdvancedProtectionManager mAdvancedProtectionManager;
private ActionDisabledByAdminDialog mDialog;
private final ComponentName mAdminComponent = new ComponentName("admin", "adminclass");
@@ -70,8 +73,6 @@ public class ActionDisabledByAdminDialogTest {
MockitoAnnotations.initMocks(this);
mDialog = spy(new ActionDisabledByAdminDialog());
doReturn(mDevicePolicyManager).when(mDialog).getSystemService(DevicePolicyManager.class);
- doReturn(mAdvancedProtectionManager).when(mDialog).getSystemService(
- AdvancedProtectionManager.class);
}
@Test
@@ -118,24 +119,28 @@ public class ActionDisabledByAdminDialogTest {
advancedProtectionAuthority, UserHandle.of(userId), mAdminComponent);
final String userRestriction = UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY;
- final Intent apmIntent = new Intent(ACTION_SHOW_ADVANCED_PROTECTION_SUPPORT_DIALOG);
- apmIntent.setFlags(FLAG_ACTIVITY_NEW_TASK);
- apmIntent.putExtra(EXTRA_SUPPORT_DIALOG_FEATURE, "featureId");
-
final Intent dialogIntent = new Intent();
dialogIntent.putExtra(Intent.EXTRA_USER_ID, userId);
dialogIntent.putExtra(DevicePolicyManager.EXTRA_RESTRICTION, userRestriction);
when(mDevicePolicyManager.getEnforcingAdmin(userId, userRestriction))
.thenReturn(advancedProtectionEnforcingAdmin);
- when(mAdvancedProtectionManager.createSupportIntentForPolicyIdentifierOrRestriction(
- userRestriction, /* type */ null)).thenReturn(apmIntent);
- doNothing().when(mDialog).startActivityAsUser(apmIntent, UserHandle.of(userId));
+ doNothing().when(mDialog).startActivityAsUser(any(), eq(UserHandle.of(userId)));
mDialog.getAdminDetailsFromIntent(dialogIntent);
- verify(mDialog).startActivityAsUser(apmIntent, UserHandle.of(userId));
+ ArgumentCaptor intentCaptor = ArgumentCaptor.forClass(Intent.class);
+ verify(mDialog).startActivityAsUser(intentCaptor.capture(), eq(UserHandle.of(userId)));
assertTrue(mDialog.isFinishing());
+
+ Intent launchedIntent = intentCaptor.getValue();
+ assertEquals("Intent action is incorrect", ACTION_SHOW_ADVANCED_PROTECTION_SUPPORT_DIALOG,
+ launchedIntent.getAction());
+ assertEquals("Feature ID extra is incorrect", FEATURE_ID_DISALLOW_INSTALL_UNKNOWN_SOURCES,
+ launchedIntent.getIntExtra(EXTRA_SUPPORT_DIALOG_FEATURE, -1));
+ assertEquals("Type is incorrect", SUPPORT_DIALOG_TYPE_UNKNOWN,
+ launchedIntent.getIntExtra(EXTRA_SUPPORT_DIALOG_TYPE, -1));
+ assertEquals(FLAG_ACTIVITY_NEW_TASK, launchedIntent.getFlags());
}
@RequiresFlagsEnabled(android.security.Flags.FLAG_AAPM_API)
diff --git a/tests/robotests/src/com/android/settings/service/PreferenceServiceRequestTransformerTest.kt b/tests/robotests/src/com/android/settings/service/PreferenceServiceRequestTransformerTest.kt
index 7631a00e9d1..da7ba5b5237 100644
--- a/tests/robotests/src/com/android/settings/service/PreferenceServiceRequestTransformerTest.kt
+++ b/tests/robotests/src/com/android/settings/service/PreferenceServiceRequestTransformerTest.kt
@@ -41,10 +41,8 @@ import com.android.settingslib.graph.preferenceGroupProto
import com.android.settingslib.graph.preferenceOrGroupProto
import com.android.settingslib.graph.preferenceProto
import com.android.settingslib.graph.preferenceScreenProto
+import com.android.settingslib.graph.preferenceValueProto
import com.android.settingslib.graph.proto.PreferenceGraphProto
-import com.android.settingslib.graph.proto.PreferenceProto
-import com.android.settingslib.graph.proto.PreferenceValueProto
-import com.android.settingslib.graph.proto.TextProto
import com.android.settingslib.graph.textProto
import com.android.settingslib.graph.toProto
import com.android.settingslib.metadata.SensitivityLevel
@@ -57,8 +55,7 @@ import org.junit.runner.RunWith
@RequiresFlagsEnabled(FLAG_SETTINGS_CATALYST)
class PreferenceServiceRequestTransformerTest {
- @get:Rule
- val checkFlagsRule: CheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule()
+ @get:Rule val checkFlagsRule: CheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule()
@Test
fun transformCatalystGetMetadataResponse_emptyGraph_returnsFrameworkResponseWithError() {
@@ -97,7 +94,7 @@ class PreferenceServiceRequestTransformerTest {
title = textProto { string = "title2" }
enabled = false
}
- }
+ },
)
)
}
@@ -110,21 +107,23 @@ class PreferenceServiceRequestTransformerTest {
assertThat(metadataList.size).isEqualTo(2)
}
assertThat(
- fResult.metadataList.any {
- it.key == "key1" &&
- it.screenKey == "screen" &&
- it.title == "title1" &&
- it.isEnabled == true
- }
- ).isTrue()
+ fResult.metadataList.any {
+ it.key == "key1" &&
+ it.screenKey == "screen" &&
+ it.title == "title1" &&
+ it.isEnabled
+ }
+ )
+ .isTrue()
assertThat(
- fResult.metadataList.any {
- it.key == "key2" &&
- it.screenKey == "screen" &&
- it.title == "title2" &&
- it.isEnabled == false
- }
- ).isTrue()
+ fResult.metadataList.any {
+ it.key == "key2" &&
+ it.screenKey == "screen" &&
+ it.title == "title2" &&
+ !it.isEnabled
+ }
+ )
+ .isTrue()
}
@Test
@@ -143,26 +142,28 @@ class PreferenceServiceRequestTransformerTest {
fun transformCatalystGetValueResponse_success_returnsValidFrameworkResponse() {
val context: Context = ApplicationProvider.getApplicationContext()
val fRequest = GetValueRequest.Builder("screen", "key").build()
- val cResult = PreferenceGetterResponse(
- emptyMap(),
- mapOf(
- PreferenceCoordinate(fRequest.screenKey, fRequest.preferenceKey) to
- PreferenceProto.newBuilder()
- .setKey("key")
- .setTitle(TextProto.newBuilder().setString("title"))
- .setSummary(TextProto.newBuilder().setString("summary"))
- .setEnabled(true)
- .setAvailable(true)
- .setRestricted(true)
- .setPersistent(true)
- .setSensitivityLevel(SensitivityLevel.LOW_SENSITIVITY)
- .setLaunchIntent(
+ val cResult =
+ PreferenceGetterResponse(
+ emptyMap(),
+ mapOf(
+ PreferenceCoordinate(fRequest.screenKey, fRequest.preferenceKey) to
+ preferenceProto {
+ key = "key"
+ title = textProto { string = "title" }
+ summary = textProto { string = "summary" }
+ enabled = true
+ available = true
+ restricted = true
+ persistent = true
+ sensitivityLevel = SensitivityLevel.LOW_SENSITIVITY
+ addReadPermissions("read_permission")
+ addWritePermissions("write_permission")
+ launchIntent =
Intent(context, SettingsHomepageActivity::class.java).toProto()
- )
- .setValue(PreferenceValueProto.newBuilder().setBooleanValue(true))
- .build()
+ value = preferenceValueProto { booleanValue = true }
+ }
+ ),
)
- )
val fResult = transformCatalystGetValueResponse(context, fRequest, cResult)
assertThat(fResult!!.resultCode).isEqualTo(GetValueResult.RESULT_OK)
with(fResult.metadata!!) {
@@ -174,6 +175,8 @@ class PreferenceServiceRequestTransformerTest {
assertThat(isWritable).isTrue()
assertThat(writeSensitivity)
.isEqualTo(SettingsPreferenceMetadata.EXPECT_POST_CONFIRMATION)
+ assertThat(readPermissions).containsExactly("read_permission")
+ assertThat(writePermissions).containsExactly("write_permission")
assertThat(launchIntent).isNotNull()
assertThat(launchIntent!!.component!!.className)
.isEqualTo(SettingsHomepageActivity::class.java.name)
@@ -188,13 +191,14 @@ class PreferenceServiceRequestTransformerTest {
fun transformCatalystGetValueResponse_failure_returnsValidFrameworkResponse() {
val context: Context = ApplicationProvider.getApplicationContext()
val fRequest = GetValueRequest.Builder("screen", "key").build()
- val cResult = PreferenceGetterResponse(
- mapOf(
- PreferenceCoordinate(fRequest.screenKey, fRequest.preferenceKey) to
+ val cResult =
+ PreferenceGetterResponse(
+ mapOf(
+ PreferenceCoordinate(fRequest.screenKey, fRequest.preferenceKey) to
PreferenceGetterErrorCode.NOT_FOUND
- ),
- emptyMap()
- )
+ ),
+ emptyMap(),
+ )
val fResult = transformCatalystGetValueResponse(context, fRequest, cResult)
with(fResult!!) {
assertThat(resultCode).isEqualTo(GetValueResult.RESULT_UNSUPPORTED)
@@ -214,13 +218,15 @@ class PreferenceServiceRequestTransformerTest {
@Test
fun transformFrameworkSetValueRequest_typeBoolean_returnsValidCatalystRequest() {
- val fRequest = SetValueRequest.Builder(
- "screen",
- "pref",
- SettingsPreferenceValue.Builder(SettingsPreferenceValue.TYPE_BOOLEAN)
- .setBooleanValue(true)
+ val fRequest =
+ SetValueRequest.Builder(
+ "screen",
+ "pref",
+ SettingsPreferenceValue.Builder(SettingsPreferenceValue.TYPE_BOOLEAN)
+ .setBooleanValue(true)
+ .build(),
+ )
.build()
- ).build()
val cRequest = transformFrameworkSetValueRequest(fRequest)
with(cRequest!!) {
assertThat(screenKey).isEqualTo(fRequest.screenKey)
@@ -232,13 +238,15 @@ class PreferenceServiceRequestTransformerTest {
@Test
fun transformFrameworkSetValueRequest_typeInt_returnsValidCatalystRequest() {
- val fRequest = SetValueRequest.Builder(
- "screen",
- "pref",
- SettingsPreferenceValue.Builder(SettingsPreferenceValue.TYPE_INT)
- .setIntValue(5)
+ val fRequest =
+ SetValueRequest.Builder(
+ "screen",
+ "pref",
+ SettingsPreferenceValue.Builder(SettingsPreferenceValue.TYPE_INT)
+ .setIntValue(5)
+ .build(),
+ )
.build()
- ).build()
val cRequest = transformFrameworkSetValueRequest(fRequest)
with(cRequest!!) {
assertThat(screenKey).isEqualTo(fRequest.screenKey)
@@ -250,59 +258,59 @@ class PreferenceServiceRequestTransformerTest {
@Test
fun transformFrameworkSetValueRequest_typeString_returnsNull() {
- val fRequest = SetValueRequest.Builder(
- "screen",
- "pref",
- SettingsPreferenceValue.Builder(SettingsPreferenceValue.TYPE_STRING)
- .setStringValue("value")
+ val fRequest =
+ SetValueRequest.Builder(
+ "screen",
+ "pref",
+ SettingsPreferenceValue.Builder(SettingsPreferenceValue.TYPE_STRING)
+ .setStringValue("value")
+ .build(),
+ )
.build()
- ).build()
val cRequest = transformFrameworkSetValueRequest(fRequest)
assertThat(cRequest).isNull()
}
@Test
fun transformCatalystSetValueResponse_returnsValidFrameworkResponse() {
- assertThat(
- transformCatalystSetValueResponse(PreferenceSetterResult.OK).resultCode
- ).isEqualTo(SetValueResult.RESULT_OK)
+ assertThat(transformCatalystSetValueResponse(PreferenceSetterResult.OK).resultCode)
+ .isEqualTo(SetValueResult.RESULT_OK)
+
+ assertThat(transformCatalystSetValueResponse(PreferenceSetterResult.UNAVAILABLE).resultCode)
+ .isEqualTo(SetValueResult.RESULT_UNAVAILABLE)
+
+ assertThat(transformCatalystSetValueResponse(PreferenceSetterResult.DISABLED).resultCode)
+ .isEqualTo(SetValueResult.RESULT_DISABLED)
+
+ assertThat(transformCatalystSetValueResponse(PreferenceSetterResult.UNSUPPORTED).resultCode)
+ .isEqualTo(SetValueResult.RESULT_UNSUPPORTED)
+
+ assertThat(transformCatalystSetValueResponse(PreferenceSetterResult.DISALLOW).resultCode)
+ .isEqualTo(SetValueResult.RESULT_DISALLOW)
assertThat(
- transformCatalystSetValueResponse(PreferenceSetterResult.UNAVAILABLE).resultCode
- ).isEqualTo(SetValueResult.RESULT_UNAVAILABLE)
+ transformCatalystSetValueResponse(PreferenceSetterResult.REQUIRE_APP_PERMISSION)
+ .resultCode
+ )
+ .isEqualTo(SetValueResult.RESULT_REQUIRE_APP_PERMISSION)
assertThat(
- transformCatalystSetValueResponse(PreferenceSetterResult.DISABLED).resultCode
- ).isEqualTo(SetValueResult.RESULT_DISABLED)
+ transformCatalystSetValueResponse(PreferenceSetterResult.REQUIRE_USER_AGREEMENT)
+ .resultCode
+ )
+ .isEqualTo(SetValueResult.RESULT_REQUIRE_USER_CONSENT)
+
+ assertThat(transformCatalystSetValueResponse(PreferenceSetterResult.RESTRICTED).resultCode)
+ .isEqualTo(SetValueResult.RESULT_RESTRICTED)
assertThat(
- transformCatalystSetValueResponse(PreferenceSetterResult.UNSUPPORTED).resultCode
- ).isEqualTo(SetValueResult.RESULT_UNSUPPORTED)
+ transformCatalystSetValueResponse(PreferenceSetterResult.INVALID_REQUEST).resultCode
+ )
+ .isEqualTo(SetValueResult.RESULT_INVALID_REQUEST)
assertThat(
- transformCatalystSetValueResponse(PreferenceSetterResult.DISALLOW).resultCode
- ).isEqualTo(SetValueResult.RESULT_DISALLOW)
-
- assertThat(
- transformCatalystSetValueResponse(PreferenceSetterResult.REQUIRE_APP_PERMISSION)
- .resultCode
- ).isEqualTo(SetValueResult.RESULT_REQUIRE_APP_PERMISSION)
-
- assertThat(
- transformCatalystSetValueResponse(PreferenceSetterResult.REQUIRE_USER_AGREEMENT)
- .resultCode
- ).isEqualTo(SetValueResult.RESULT_REQUIRE_USER_CONSENT)
-
- assertThat(
- transformCatalystSetValueResponse(PreferenceSetterResult.RESTRICTED).resultCode
- ).isEqualTo(SetValueResult.RESULT_RESTRICTED)
-
- assertThat(
- transformCatalystSetValueResponse(PreferenceSetterResult.INVALID_REQUEST).resultCode
- ).isEqualTo(SetValueResult.RESULT_INVALID_REQUEST)
-
- assertThat(
- transformCatalystSetValueResponse(PreferenceSetterResult.INTERNAL_ERROR).resultCode
- ).isEqualTo(SetValueResult.RESULT_INTERNAL_ERROR)
+ transformCatalystSetValueResponse(PreferenceSetterResult.INTERNAL_ERROR).resultCode
+ )
+ .isEqualTo(SetValueResult.RESULT_INTERNAL_ERROR)
}
-}
\ No newline at end of file
+}
diff --git a/tests/spa_unit/src/com/android/settings/wifi/WepNetworksPreferenceControllerTest.kt b/tests/spa_unit/src/com/android/settings/wifi/WepNetworksPreferenceControllerTest.kt
index 1f0a4916310..74107571b0d 100644
--- a/tests/spa_unit/src/com/android/settings/wifi/WepNetworksPreferenceControllerTest.kt
+++ b/tests/spa_unit/src/com/android/settings/wifi/WepNetworksPreferenceControllerTest.kt
@@ -200,7 +200,6 @@ class WepNetworksPreferenceControllerTest {
fun whenClick_aapmEnabled_openDialog() {
mockAapmManager.stub {
on { isAdvancedProtectionEnabled } doReturn true
- on { createSupportIntent(any(), any()) } doReturn Intent()
}
doNothing().whenever(context).startActivity(any())
composeTestRule.setContent { controller.Content() }