[Ambient Volume] Show value with remote data
Sync local data with remote data when UI need to refresh and set the corresponding local value to remote when the control expanded/collapsed. Flag: com.android.settingslib.flags.hearing_devices_ambient_volume_control Bug: 357878944 Test: atest BluetoothDetailsAmbientVolumePreferenceControllerTest Change-Id: If748e696eb62b199d4fd9abafa2300d301a8079c
This commit is contained in:
@@ -174,6 +174,8 @@
|
|||||||
<string name="bluetooth_ambient_volume_control_left">Left</string>
|
<string name="bluetooth_ambient_volume_control_left">Left</string>
|
||||||
<!-- Connected devices settings. The text to show the control is for right side device. [CHAR LIMIT=30] -->
|
<!-- Connected devices settings. The text to show the control is for right side device. [CHAR LIMIT=30] -->
|
||||||
<string name="bluetooth_ambient_volume_control_right">Right</string>
|
<string name="bluetooth_ambient_volume_control_right">Right</string>
|
||||||
|
<!-- Message when changing ambient state failed. [CHAR LIMIT=NONE] -->
|
||||||
|
<string name="bluetooth_ambient_volume_error">Couldn\u2019t update surroundings</string>
|
||||||
<!-- Connected devices settings. Title of the preference to show the entrance of the audio output page. It can change different types of audio are played on phone or other bluetooth devices. [CHAR LIMIT=35] -->
|
<!-- Connected devices settings. Title of the preference to show the entrance of the audio output page. It can change different types of audio are played on phone or other bluetooth devices. [CHAR LIMIT=35] -->
|
||||||
<string name="bluetooth_audio_routing_title">Audio output</string>
|
<string name="bluetooth_audio_routing_title">Audio output</string>
|
||||||
<!-- Title for bluetooth audio routing page footer. [CHAR LIMIT=30] -->
|
<!-- Title for bluetooth audio routing page footer. [CHAR LIMIT=30] -->
|
||||||
|
@@ -28,9 +28,11 @@ import static com.android.settingslib.bluetooth.HearingAidInfo.DeviceSide.SIDE_R
|
|||||||
import static com.android.settingslib.bluetooth.HearingDeviceLocalDataManager.Data.INVALID_VOLUME;
|
import static com.android.settingslib.bluetooth.HearingDeviceLocalDataManager.Data.INVALID_VOLUME;
|
||||||
|
|
||||||
import android.bluetooth.BluetoothDevice;
|
import android.bluetooth.BluetoothDevice;
|
||||||
|
import android.bluetooth.BluetoothProfile;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.util.ArraySet;
|
import android.util.ArraySet;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
@@ -42,9 +44,12 @@ import androidx.preference.PreferenceScreen;
|
|||||||
|
|
||||||
import com.android.settings.R;
|
import com.android.settings.R;
|
||||||
import com.android.settings.widget.SeekBarPreference;
|
import com.android.settings.widget.SeekBarPreference;
|
||||||
|
import com.android.settingslib.bluetooth.AmbientVolumeController;
|
||||||
|
import com.android.settingslib.bluetooth.BluetoothCallback;
|
||||||
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
|
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
|
||||||
import com.android.settingslib.bluetooth.HearingDeviceLocalDataManager;
|
import com.android.settingslib.bluetooth.HearingDeviceLocalDataManager;
|
||||||
import com.android.settingslib.bluetooth.HearingDeviceLocalDataManager.Data;
|
import com.android.settingslib.bluetooth.HearingDeviceLocalDataManager.Data;
|
||||||
|
import com.android.settingslib.bluetooth.LocalBluetoothManager;
|
||||||
import com.android.settingslib.bluetooth.VolumeControlProfile;
|
import com.android.settingslib.bluetooth.VolumeControlProfile;
|
||||||
import com.android.settingslib.core.lifecycle.Lifecycle;
|
import com.android.settingslib.core.lifecycle.Lifecycle;
|
||||||
import com.android.settingslib.core.lifecycle.events.OnStart;
|
import com.android.settingslib.core.lifecycle.events.OnStart;
|
||||||
@@ -54,12 +59,14 @@ import com.android.settingslib.utils.ThreadUtils;
|
|||||||
import com.google.common.collect.BiMap;
|
import com.google.common.collect.BiMap;
|
||||||
import com.google.common.collect.HashBiMap;
|
import com.google.common.collect.HashBiMap;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
/** A {@link BluetoothDetailsController} that manages ambient volume control preferences. */
|
/** A {@link BluetoothDetailsController} that manages ambient volume control preferences. */
|
||||||
public class BluetoothDetailsAmbientVolumePreferenceController extends
|
public class BluetoothDetailsAmbientVolumePreferenceController extends
|
||||||
BluetoothDetailsController implements Preference.OnPreferenceChangeListener,
|
BluetoothDetailsController implements Preference.OnPreferenceChangeListener,
|
||||||
HearingDeviceLocalDataManager.OnDeviceLocalDataChangeListener, OnStart, OnStop {
|
HearingDeviceLocalDataManager.OnDeviceLocalDataChangeListener, OnStart, OnStop,
|
||||||
|
AmbientVolumeController.AmbientVolumeControlCallback, BluetoothCallback {
|
||||||
|
|
||||||
private static final boolean DEBUG = true;
|
private static final boolean DEBUG = true;
|
||||||
private static final String TAG = "AmbientPrefController";
|
private static final String TAG = "AmbientPrefController";
|
||||||
@@ -69,34 +76,45 @@ public class BluetoothDetailsAmbientVolumePreferenceController extends
|
|||||||
private static final int ORDER_AMBIENT_VOLUME_CONTROL_UNIFIED = 0;
|
private static final int ORDER_AMBIENT_VOLUME_CONTROL_UNIFIED = 0;
|
||||||
private static final int ORDER_AMBIENT_VOLUME_CONTROL_SEPARATED = 1;
|
private static final int ORDER_AMBIENT_VOLUME_CONTROL_SEPARATED = 1;
|
||||||
|
|
||||||
|
private final LocalBluetoothManager mBluetoothManager;
|
||||||
private final Set<CachedBluetoothDevice> mCachedDevices = new ArraySet<>();
|
private final Set<CachedBluetoothDevice> mCachedDevices = new ArraySet<>();
|
||||||
private final BiMap<Integer, BluetoothDevice> mSideToDeviceMap = HashBiMap.create();
|
private final BiMap<Integer, BluetoothDevice> mSideToDeviceMap = HashBiMap.create();
|
||||||
private final BiMap<Integer, SeekBarPreference> mSideToSliderMap = HashBiMap.create();
|
private final BiMap<Integer, SeekBarPreference> mSideToSliderMap = HashBiMap.create();
|
||||||
private final HearingDeviceLocalDataManager mLocalDataManager;
|
private final HearingDeviceLocalDataManager mLocalDataManager;
|
||||||
|
private final AmbientVolumeController mVolumeController;
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private PreferenceCategory mDeviceControls;
|
private PreferenceCategory mDeviceControls;
|
||||||
@Nullable
|
@Nullable
|
||||||
private AmbientVolumePreference mPreference;
|
private AmbientVolumePreference mPreference;
|
||||||
|
@Nullable
|
||||||
|
private Toast mToast;
|
||||||
|
|
||||||
public BluetoothDetailsAmbientVolumePreferenceController(@NonNull Context context,
|
public BluetoothDetailsAmbientVolumePreferenceController(@NonNull Context context,
|
||||||
|
@NonNull LocalBluetoothManager manager,
|
||||||
@NonNull PreferenceFragmentCompat fragment,
|
@NonNull PreferenceFragmentCompat fragment,
|
||||||
@NonNull CachedBluetoothDevice device,
|
@NonNull CachedBluetoothDevice device,
|
||||||
@NonNull Lifecycle lifecycle) {
|
@NonNull Lifecycle lifecycle) {
|
||||||
super(context, fragment, device, lifecycle);
|
super(context, fragment, device, lifecycle);
|
||||||
|
mBluetoothManager = manager;
|
||||||
mLocalDataManager = new HearingDeviceLocalDataManager(context);
|
mLocalDataManager = new HearingDeviceLocalDataManager(context);
|
||||||
mLocalDataManager.setOnDeviceLocalDataChangeListener(this,
|
mLocalDataManager.setOnDeviceLocalDataChangeListener(this,
|
||||||
ThreadUtils.getBackgroundExecutor());
|
ThreadUtils.getBackgroundExecutor());
|
||||||
|
mVolumeController = new AmbientVolumeController(manager.getProfileManager(), this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
BluetoothDetailsAmbientVolumePreferenceController(@NonNull Context context,
|
BluetoothDetailsAmbientVolumePreferenceController(@NonNull Context context,
|
||||||
|
@NonNull LocalBluetoothManager manager,
|
||||||
@NonNull PreferenceFragmentCompat fragment,
|
@NonNull PreferenceFragmentCompat fragment,
|
||||||
@NonNull CachedBluetoothDevice device,
|
@NonNull CachedBluetoothDevice device,
|
||||||
@NonNull Lifecycle lifecycle,
|
@NonNull Lifecycle lifecycle,
|
||||||
@NonNull HearingDeviceLocalDataManager localSettings) {
|
@NonNull HearingDeviceLocalDataManager localSettings,
|
||||||
|
@NonNull AmbientVolumeController volumeController) {
|
||||||
super(context, fragment, device, lifecycle);
|
super(context, fragment, device, lifecycle);
|
||||||
|
mBluetoothManager = manager;
|
||||||
mLocalDataManager = localSettings;
|
mLocalDataManager = localSettings;
|
||||||
|
mVolumeController = volumeController;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -111,19 +129,33 @@ public class BluetoothDetailsAmbientVolumePreferenceController extends
|
|||||||
@Override
|
@Override
|
||||||
public void onStart() {
|
public void onStart() {
|
||||||
ThreadUtils.postOnBackgroundThread(() -> {
|
ThreadUtils.postOnBackgroundThread(() -> {
|
||||||
|
mBluetoothManager.getEventManager().registerCallback(this);
|
||||||
mLocalDataManager.start();
|
mLocalDataManager.start();
|
||||||
mCachedDevices.forEach(device -> {
|
mCachedDevices.forEach(device -> {
|
||||||
device.registerCallback(ThreadUtils.getBackgroundExecutor(), this);
|
device.registerCallback(ThreadUtils.getBackgroundExecutor(), this);
|
||||||
|
mVolumeController.registerCallback(ThreadUtils.getBackgroundExecutor(),
|
||||||
|
device.getDevice());
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onResume() {
|
||||||
|
refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPause() {
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onStop() {
|
public void onStop() {
|
||||||
ThreadUtils.postOnBackgroundThread(() -> {
|
ThreadUtils.postOnBackgroundThread(() -> {
|
||||||
|
mBluetoothManager.getEventManager().unregisterCallback(this);
|
||||||
mLocalDataManager.stop();
|
mLocalDataManager.stop();
|
||||||
mCachedDevices.forEach(device -> {
|
mCachedDevices.forEach(device -> {
|
||||||
device.unregisterCallback(this);
|
device.unregisterCallback(this);
|
||||||
|
mVolumeController.unregisterCallback(device.getDevice());
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -133,8 +165,17 @@ public class BluetoothDetailsAmbientVolumePreferenceController extends
|
|||||||
if (!isAvailable()) {
|
if (!isAvailable()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// TODO: load data from remote
|
boolean shouldShowAmbientControl = isAmbientControlAvailable();
|
||||||
loadLocalDataToUi();
|
if (shouldShowAmbientControl) {
|
||||||
|
if (mPreference != null) {
|
||||||
|
mPreference.setVisible(true);
|
||||||
|
}
|
||||||
|
loadRemoteDataToUi();
|
||||||
|
} else {
|
||||||
|
if (mPreference != null) {
|
||||||
|
mPreference.setVisible(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -160,19 +201,33 @@ public class BluetoothDetailsAmbientVolumePreferenceController extends
|
|||||||
setVolumeIfValid(side, value);
|
setVolumeIfValid(side, value);
|
||||||
|
|
||||||
if (side == SIDE_UNIFIED) {
|
if (side == SIDE_UNIFIED) {
|
||||||
// TODO: set the value on the devices
|
mSideToDeviceMap.forEach((s, d) -> mVolumeController.setAmbient(d, value));
|
||||||
} else {
|
} else {
|
||||||
// TODO: set the value on the side device
|
final BluetoothDevice device = mSideToDeviceMap.get(side);
|
||||||
|
mVolumeController.setAmbient(device, value);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
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
|
@Override
|
||||||
public void onDeviceAttributesChanged() {
|
public void onDeviceAttributesChanged() {
|
||||||
mCachedDevices.forEach(device -> {
|
mCachedDevices.forEach(device -> {
|
||||||
device.unregisterCallback(this);
|
device.unregisterCallback(this);
|
||||||
|
mVolumeController.unregisterCallback(device.getDevice());
|
||||||
});
|
});
|
||||||
mContext.getMainExecutor().execute(() -> {
|
mContext.getMainExecutor().execute(() -> {
|
||||||
loadDevices();
|
loadDevices();
|
||||||
@@ -182,6 +237,8 @@ public class BluetoothDetailsAmbientVolumePreferenceController extends
|
|||||||
ThreadUtils.postOnBackgroundThread(() ->
|
ThreadUtils.postOnBackgroundThread(() ->
|
||||||
mCachedDevices.forEach(device -> {
|
mCachedDevices.forEach(device -> {
|
||||||
device.registerCallback(ThreadUtils.getBackgroundExecutor(), this);
|
device.registerCallback(ThreadUtils.getBackgroundExecutor(), this);
|
||||||
|
mVolumeController.registerCallback(ThreadUtils.getBackgroundExecutor(),
|
||||||
|
device.getDevice());
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@@ -201,6 +258,41 @@ public class BluetoothDetailsAmbientVolumePreferenceController extends
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@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 onCommandFailed(@NonNull BluetoothDevice device) {
|
||||||
|
Log.w(TAG, "onCommandFailed, device:" + device);
|
||||||
|
mContext.getMainExecutor().execute(() -> {
|
||||||
|
showErrorToast();
|
||||||
|
refresh();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private void loadDevices() {
|
private void loadDevices() {
|
||||||
mSideToDeviceMap.clear();
|
mSideToDeviceMap.clear();
|
||||||
mCachedDevices.clear();
|
mCachedDevices.clear();
|
||||||
@@ -234,6 +326,11 @@ public class BluetoothDetailsAmbientVolumePreferenceController extends
|
|||||||
mPreference.setOrder(ORDER_AMBIENT_VOLUME);
|
mPreference.setOrder(ORDER_AMBIENT_VOLUME);
|
||||||
mPreference.setOnIconClickListener(() -> {
|
mPreference.setOnIconClickListener(() -> {
|
||||||
mSideToDeviceMap.forEach((s, d) -> {
|
mSideToDeviceMap.forEach((s, d) -> {
|
||||||
|
// 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
|
// Update new value to local data
|
||||||
mLocalDataManager.updateAmbientControlExpanded(d, isControlExpanded());
|
mLocalDataManager.updateAmbientControlExpanded(d, isControlExpanded());
|
||||||
});
|
});
|
||||||
@@ -269,6 +366,16 @@ public class BluetoothDetailsAmbientVolumePreferenceController extends
|
|||||||
/** Refreshes the control UI visibility and enabled state. */
|
/** Refreshes the control UI visibility and enabled state. */
|
||||||
private void refreshControlUi() {
|
private void refreshControlUi() {
|
||||||
if (mPreference != null) {
|
if (mPreference != null) {
|
||||||
|
boolean isAnySliderEnabled = false;
|
||||||
|
for (Map.Entry<Integer, BluetoothDevice> 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();
|
mPreference.updateLayout();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -299,12 +406,74 @@ public class BluetoothDetailsAmbientVolumePreferenceController extends
|
|||||||
Log.d(TAG, "loadLocalDataToUi, data=" + data + ", device=" + device);
|
Log.d(TAG, "loadLocalDataToUi, data=" + data + ", device=" + device);
|
||||||
}
|
}
|
||||||
final int side = mSideToDeviceMap.inverse().getOrDefault(device, SIDE_INVALID);
|
final int side = mSideToDeviceMap.inverse().getOrDefault(device, SIDE_INVALID);
|
||||||
setVolumeIfValid(side, data.ambient());
|
if (isDeviceConnectedToVcp(device)) {
|
||||||
setVolumeIfValid(SIDE_UNIFIED, data.groupAmbient());
|
setVolumeIfValid(side, data.ambient());
|
||||||
|
setVolumeIfValid(SIDE_UNIFIED, data.groupAmbient());
|
||||||
|
}
|
||||||
setControlExpanded(data.ambientControlExpanded());
|
setControlExpanded(data.ambientControlExpanded());
|
||||||
refreshControlUi();
|
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();
|
||||||
|
|
||||||
|
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() {
|
private boolean isControlExpanded() {
|
||||||
return mPreference != null && mPreference.isExpanded();
|
return mPreference != null && mPreference.isExpanded();
|
||||||
}
|
}
|
||||||
@@ -318,4 +487,41 @@ public class BluetoothDetailsAmbientVolumePreferenceController extends
|
|||||||
mLocalDataManager.updateAmbientControlExpanded(d, expanded);
|
mLocalDataManager.updateAmbientControlExpanded(d, expanded);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -110,7 +110,7 @@ public class BluetoothDetailsHearingDeviceController extends BluetoothDetailsCon
|
|||||||
}
|
}
|
||||||
if (com.android.settingslib.flags.Flags.hearingDevicesAmbientVolumeControl()) {
|
if (com.android.settingslib.flags.Flags.hearingDevicesAmbientVolumeControl()) {
|
||||||
mControllers.add(new BluetoothDetailsAmbientVolumePreferenceController(mContext,
|
mControllers.add(new BluetoothDetailsAmbientVolumePreferenceController(mContext,
|
||||||
mFragment, mCachedDevice, mLifecycle));
|
mManager, mFragment, mCachedDevice, mLifecycle));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -29,14 +29,19 @@ 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.anyBoolean;
|
||||||
import static org.mockito.ArgumentMatchers.anyInt;
|
import static org.mockito.ArgumentMatchers.anyInt;
|
||||||
|
import static org.mockito.ArgumentMatchers.anyLong;
|
||||||
import static org.mockito.ArgumentMatchers.eq;
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
import static org.mockito.Mockito.atLeastOnce;
|
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.verify;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
import static org.robolectric.Shadows.shadowOf;
|
import static org.robolectric.Shadows.shadowOf;
|
||||||
|
|
||||||
import android.bluetooth.BluetoothDevice;
|
import android.bluetooth.BluetoothDevice;
|
||||||
|
import android.bluetooth.BluetoothProfile;
|
||||||
import android.content.ContentResolver;
|
import android.content.ContentResolver;
|
||||||
|
import android.os.Handler;
|
||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
|
|
||||||
@@ -44,8 +49,13 @@ import androidx.preference.PreferenceCategory;
|
|||||||
|
|
||||||
import com.android.settings.testutils.shadow.ShadowThreadUtils;
|
import com.android.settings.testutils.shadow.ShadowThreadUtils;
|
||||||
import com.android.settings.widget.SeekBarPreference;
|
import com.android.settings.widget.SeekBarPreference;
|
||||||
|
import com.android.settingslib.bluetooth.AmbientVolumeController;
|
||||||
|
import com.android.settingslib.bluetooth.BluetoothEventManager;
|
||||||
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
|
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
|
||||||
import com.android.settingslib.bluetooth.HearingDeviceLocalDataManager;
|
import com.android.settingslib.bluetooth.HearingDeviceLocalDataManager;
|
||||||
|
import com.android.settingslib.bluetooth.LocalBluetoothManager;
|
||||||
|
import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
|
||||||
|
import com.android.settingslib.bluetooth.VolumeControlProfile;
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Rule;
|
import org.junit.Rule;
|
||||||
@@ -90,6 +100,18 @@ public class BluetoothDetailsAmbientVolumePreferenceControllerTest extends
|
|||||||
private BluetoothDevice mMemberDevice;
|
private BluetoothDevice mMemberDevice;
|
||||||
@Mock
|
@Mock
|
||||||
private HearingDeviceLocalDataManager mLocalDataManager;
|
private HearingDeviceLocalDataManager mLocalDataManager;
|
||||||
|
@Mock
|
||||||
|
private LocalBluetoothManager mBluetoothManager;
|
||||||
|
@Mock
|
||||||
|
private BluetoothEventManager mEventManager;
|
||||||
|
@Mock
|
||||||
|
private LocalBluetoothProfileManager mProfileManager;
|
||||||
|
@Mock
|
||||||
|
private VolumeControlProfile mVolumeControlProfile;
|
||||||
|
@Mock
|
||||||
|
private AmbientVolumeController mVolumeController;
|
||||||
|
@Mock
|
||||||
|
private Handler mTestHandler;
|
||||||
|
|
||||||
private BluetoothDetailsAmbientVolumePreferenceController mController;
|
private BluetoothDetailsAmbientVolumePreferenceController mController;
|
||||||
|
|
||||||
@@ -97,11 +119,29 @@ public class BluetoothDetailsAmbientVolumePreferenceControllerTest extends
|
|||||||
public void setUp() {
|
public void setUp() {
|
||||||
super.setUp();
|
super.setUp();
|
||||||
|
|
||||||
|
mContext = spy(mContext);
|
||||||
PreferenceCategory deviceControls = new PreferenceCategory(mContext);
|
PreferenceCategory deviceControls = new PreferenceCategory(mContext);
|
||||||
deviceControls.setKey(KEY_HEARING_DEVICE_GROUP);
|
deviceControls.setKey(KEY_HEARING_DEVICE_GROUP);
|
||||||
mScreen.addPreference(deviceControls);
|
mScreen.addPreference(deviceControls);
|
||||||
mController = new BluetoothDetailsAmbientVolumePreferenceController(mContext, mFragment,
|
mController = spy(
|
||||||
mCachedDevice, mLifecycle, mLocalDataManager);
|
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(mContext.getMainThreadHandler()).thenReturn(mTestHandler);
|
||||||
|
when(mTestHandler.postDelayed(any(Runnable.class), anyLong())).thenAnswer(
|
||||||
|
invocationOnMock -> {
|
||||||
|
invocationOnMock.getArgument(0, Runnable.class).run();
|
||||||
|
return null;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -128,10 +168,13 @@ public class BluetoothDetailsAmbientVolumePreferenceControllerTest extends
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void onDeviceLocalDataChange_noMemberAndExpanded_uiCorrectAndDataUpdated() {
|
public void onDeviceLocalDataChange_noMemberAndExpanded_uiCorrectAndDataUpdated() {
|
||||||
prepareDevice(/* hasMember= */ false, /* controlExpanded= */ true);
|
prepareDevice(/* hasMember= */ false);
|
||||||
|
|
||||||
mController.init(mScreen);
|
mController.init(mScreen);
|
||||||
mController.onDeviceLocalDataChange(TEST_ADDRESS, prepareEmptyData());
|
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();
|
shadowOf(Looper.getMainLooper()).idle();
|
||||||
|
|
||||||
AmbientVolumePreference preference = mScreen.findPreference(KEY_AMBIENT_VOLUME);
|
AmbientVolumePreference preference = mScreen.findPreference(KEY_AMBIENT_VOLUME);
|
||||||
@@ -142,10 +185,13 @@ public class BluetoothDetailsAmbientVolumePreferenceControllerTest extends
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void onDeviceLocalDataChange_noMemberAndCollapsed_uiCorrectAndDataUpdated() {
|
public void onDeviceLocalDataChange_noMemberAndCollapsed_uiCorrectAndDataUpdated() {
|
||||||
prepareDevice(/* hasMember= */ false, /* controlExpanded= */ false);
|
prepareDevice(/* hasMember= */ false);
|
||||||
|
|
||||||
mController.init(mScreen);
|
mController.init(mScreen);
|
||||||
mController.onDeviceLocalDataChange(TEST_ADDRESS, prepareEmptyData());
|
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();
|
shadowOf(Looper.getMainLooper()).idle();
|
||||||
|
|
||||||
AmbientVolumePreference preference = mScreen.findPreference(KEY_AMBIENT_VOLUME);
|
AmbientVolumePreference preference = mScreen.findPreference(KEY_AMBIENT_VOLUME);
|
||||||
@@ -156,10 +202,13 @@ public class BluetoothDetailsAmbientVolumePreferenceControllerTest extends
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void onDeviceLocalDataChange_hasMemberAndExpanded_uiCorrectAndDataUpdated() {
|
public void onDeviceLocalDataChange_hasMemberAndExpanded_uiCorrectAndDataUpdated() {
|
||||||
prepareDevice(/* hasMember= */ true, /* controlExpanded= */ true);
|
prepareDevice(/* hasMember= */ true);
|
||||||
|
|
||||||
mController.init(mScreen);
|
mController.init(mScreen);
|
||||||
mController.onDeviceLocalDataChange(TEST_ADDRESS, prepareEmptyData());
|
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();
|
shadowOf(Looper.getMainLooper()).idle();
|
||||||
|
|
||||||
AmbientVolumePreference preference = mScreen.findPreference(KEY_AMBIENT_VOLUME);
|
AmbientVolumePreference preference = mScreen.findPreference(KEY_AMBIENT_VOLUME);
|
||||||
@@ -170,10 +219,13 @@ public class BluetoothDetailsAmbientVolumePreferenceControllerTest extends
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void onDeviceLocalDataChange_hasMemberAndCollapsed_uiCorrectAndDataUpdated() {
|
public void onDeviceLocalDataChange_hasMemberAndCollapsed_uiCorrectAndDataUpdated() {
|
||||||
prepareDevice(/* hasMember= */ true, /* controlExpanded= */ false);
|
prepareDevice(/* hasMember= */ true);
|
||||||
|
|
||||||
mController.init(mScreen);
|
mController.init(mScreen);
|
||||||
mController.onDeviceLocalDataChange(TEST_ADDRESS, prepareEmptyData());
|
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();
|
shadowOf(Looper.getMainLooper()).idle();
|
||||||
|
|
||||||
AmbientVolumePreference preference = mScreen.findPreference(KEY_AMBIENT_VOLUME);
|
AmbientVolumePreference preference = mScreen.findPreference(KEY_AMBIENT_VOLUME);
|
||||||
@@ -185,11 +237,13 @@ public class BluetoothDetailsAmbientVolumePreferenceControllerTest extends
|
|||||||
@Test
|
@Test
|
||||||
public void onStart_localDataManagerStartAndCallbackRegistered() {
|
public void onStart_localDataManagerStartAndCallbackRegistered() {
|
||||||
prepareDevice(/* hasMember= */ true);
|
prepareDevice(/* hasMember= */ true);
|
||||||
|
|
||||||
mController.init(mScreen);
|
mController.init(mScreen);
|
||||||
|
|
||||||
mController.onStart();
|
mController.onStart();
|
||||||
|
|
||||||
verify(mLocalDataManager, atLeastOnce()).start();
|
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),
|
verify(mCachedDevice).registerCallback(any(Executor.class),
|
||||||
any(CachedBluetoothDevice.Callback.class));
|
any(CachedBluetoothDevice.Callback.class));
|
||||||
verify(mCachedMemberDevice).registerCallback(any(Executor.class),
|
verify(mCachedMemberDevice).registerCallback(any(Executor.class),
|
||||||
@@ -199,11 +253,13 @@ public class BluetoothDetailsAmbientVolumePreferenceControllerTest extends
|
|||||||
@Test
|
@Test
|
||||||
public void onStop_localDataManagerStopAndCallbackUnregistered() {
|
public void onStop_localDataManagerStopAndCallbackUnregistered() {
|
||||||
prepareDevice(/* hasMember= */ true);
|
prepareDevice(/* hasMember= */ true);
|
||||||
|
|
||||||
mController.init(mScreen);
|
mController.init(mScreen);
|
||||||
|
|
||||||
mController.onStop();
|
mController.onStop();
|
||||||
|
|
||||||
verify(mLocalDataManager).stop();
|
verify(mLocalDataManager).stop();
|
||||||
|
verify(mVolumeController).unregisterCallback(mDevice);
|
||||||
|
verify(mVolumeController).unregisterCallback(mMemberDevice);
|
||||||
verify(mCachedDevice).unregisterCallback(any(CachedBluetoothDevice.Callback.class));
|
verify(mCachedDevice).unregisterCallback(any(CachedBluetoothDevice.Callback.class));
|
||||||
verify(mCachedMemberDevice).unregisterCallback(any(CachedBluetoothDevice.Callback.class));
|
verify(mCachedMemberDevice).unregisterCallback(any(CachedBluetoothDevice.Callback.class));
|
||||||
}
|
}
|
||||||
@@ -211,7 +267,6 @@ public class BluetoothDetailsAmbientVolumePreferenceControllerTest extends
|
|||||||
@Test
|
@Test
|
||||||
public void onDeviceAttributesChanged_newDevice_newPreference() {
|
public void onDeviceAttributesChanged_newDevice_newPreference() {
|
||||||
prepareDevice(/* hasMember= */ false);
|
prepareDevice(/* hasMember= */ false);
|
||||||
|
|
||||||
mController.init(mScreen);
|
mController.init(mScreen);
|
||||||
|
|
||||||
// check the right control is null before onDeviceAttributesChanged()
|
// check the right control is null before onDeviceAttributesChanged()
|
||||||
@@ -231,16 +286,34 @@ public class BluetoothDetailsAmbientVolumePreferenceControllerTest extends
|
|||||||
assertThat(updatedRightControl).isNotNull();
|
assertThat(updatedRightControl).isNotNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void prepareDevice(boolean hasMember) {
|
@Test
|
||||||
prepareDevice(hasMember, false);
|
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();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void prepareDevice(boolean hasMember, boolean controlExpanded) {
|
private void prepareDevice(boolean hasMember) {
|
||||||
when(mCachedDevice.getDeviceSide()).thenReturn(SIDE_LEFT);
|
when(mCachedDevice.getDeviceSide()).thenReturn(SIDE_LEFT);
|
||||||
when(mCachedDevice.getDevice()).thenReturn(mDevice);
|
when(mCachedDevice.getDevice()).thenReturn(mDevice);
|
||||||
when(mCachedDevice.getBondState()).thenReturn(BOND_BONDED);
|
when(mCachedDevice.getBondState()).thenReturn(BOND_BONDED);
|
||||||
when(mDevice.getAddress()).thenReturn(TEST_ADDRESS);
|
when(mDevice.getAddress()).thenReturn(TEST_ADDRESS);
|
||||||
when(mDevice.getAnonymizedAddress()).thenReturn(TEST_ADDRESS);
|
when(mDevice.getAnonymizedAddress()).thenReturn(TEST_ADDRESS);
|
||||||
|
when(mDevice.isConnected()).thenReturn(true);
|
||||||
if (hasMember) {
|
if (hasMember) {
|
||||||
when(mCachedDevice.getMemberDevice()).thenReturn(Set.of(mCachedMemberDevice));
|
when(mCachedDevice.getMemberDevice()).thenReturn(Set.of(mCachedMemberDevice));
|
||||||
when(mCachedMemberDevice.getDeviceSide()).thenReturn(SIDE_RIGHT);
|
when(mCachedMemberDevice.getDeviceSide()).thenReturn(SIDE_RIGHT);
|
||||||
@@ -248,14 +321,8 @@ public class BluetoothDetailsAmbientVolumePreferenceControllerTest extends
|
|||||||
when(mCachedMemberDevice.getBondState()).thenReturn(BOND_BONDED);
|
when(mCachedMemberDevice.getBondState()).thenReturn(BOND_BONDED);
|
||||||
when(mMemberDevice.getAddress()).thenReturn(TEST_MEMBER_ADDRESS);
|
when(mMemberDevice.getAddress()).thenReturn(TEST_MEMBER_ADDRESS);
|
||||||
when(mMemberDevice.getAnonymizedAddress()).thenReturn(TEST_MEMBER_ADDRESS);
|
when(mMemberDevice.getAnonymizedAddress()).thenReturn(TEST_MEMBER_ADDRESS);
|
||||||
|
when(mMemberDevice.isConnected()).thenReturn(true);
|
||||||
}
|
}
|
||||||
HearingDeviceLocalDataManager.Data data = new HearingDeviceLocalDataManager.Data.Builder()
|
|
||||||
.ambient(0).groupAmbient(0).ambientControlExpanded(controlExpanded).build();
|
|
||||||
when(mLocalDataManager.get(any(BluetoothDevice.class))).thenReturn(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
private HearingDeviceLocalDataManager.Data prepareEmptyData() {
|
|
||||||
return new HearingDeviceLocalDataManager.Data.Builder().build();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void verifyDeviceDataUpdated(BluetoothDevice device) {
|
private void verifyDeviceDataUpdated(BluetoothDevice device) {
|
||||||
@@ -265,6 +332,10 @@ public class BluetoothDetailsAmbientVolumePreferenceControllerTest extends
|
|||||||
anyBoolean());
|
anyBoolean());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private AmbientVolumePreference getPreference() {
|
||||||
|
return mScreen.findPreference(KEY_AMBIENT_VOLUME);
|
||||||
|
}
|
||||||
|
|
||||||
@Implements(value = Settings.Global.class)
|
@Implements(value = Settings.Global.class)
|
||||||
public static class ShadowGlobal extends ShadowSettings.ShadowGlobal {
|
public static class ShadowGlobal extends ShadowSettings.ShadowGlobal {
|
||||||
private static final Map<ContentResolver, Map<String, String>> sDataMap = new HashMap<>();
|
private static final Map<ContentResolver, Map<String, String>> sDataMap = new HashMap<>();
|
||||||
|
Reference in New Issue
Block a user