[Audiosharing] Update the volume control registration flow.

Based on the framework API redesign, we will start/stop the volume control callback registration when user enter/leave the volume control page.
We will temporarily keep a map of the device to volume map and use the
volume value to set the initial state of the volume progress bar if it is valid.
If the volume value is null or invalid, we will read the music stream
volume from the audio manager to set the initial state.

Test: manual
Bug: 305620450
Change-Id: Iee3fba39af388782ac3498cb1610b248ced22c3c
This commit is contained in:
Yiyi Shen
2024-01-11 13:24:15 +08:00
parent 4e0fc12d05
commit 389ab6a6ef

View File

@@ -37,22 +37,20 @@ import com.android.settings.bluetooth.BluetoothDeviceUpdater;
import com.android.settings.bluetooth.Utils;
import com.android.settings.connecteddevice.DevicePreferenceCallback;
import com.android.settings.dashboard.DashboardFragment;
import com.android.settingslib.bluetooth.BluetoothUtils;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.settingslib.bluetooth.VolumeControlProfile;
import com.android.settingslib.utils.ThreadUtils;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
public class AudioSharingDeviceVolumeGroupController extends AudioSharingBasePreferenceController
implements DevicePreferenceCallback {
private static final boolean DEBUG = BluetoothUtils.D;
private static final String TAG = "AudioSharingDeviceVolumeGroupController";
private static final String KEY = "audio_sharing_device_volume_group";
@@ -63,8 +61,43 @@ public class AudioSharingDeviceVolumeGroupController extends AudioSharingBasePre
private BluetoothDeviceUpdater mBluetoothDeviceUpdater;
private FragmentManager mFragmentManager;
private PreferenceGroup mPreferenceGroup;
private Map<Preference, BluetoothVolumeControl.Callback> mCallbackMap =
new HashMap<Preference, BluetoothVolumeControl.Callback>();
private List<AudioSharingDeviceVolumePreference> mVolumePreferences = new ArrayList<>();
private Map<Integer, Integer> mValueMap = new HashMap<Integer, Integer>();
private BluetoothVolumeControl.Callback mVolumeControlCallback =
new BluetoothVolumeControl.Callback() {
@Override
public void onVolumeOffsetChanged(
@NonNull BluetoothDevice device, int volumeOffset) {}
@Override
public void onDeviceVolumeChanged(
@NonNull BluetoothDevice device,
@IntRange(from = -255, to = 255) int volume) {
CachedBluetoothDevice cachedDevice =
mLocalBtManager.getCachedDeviceManager().findDevice(device);
if (cachedDevice == null) return;
mValueMap.put(cachedDevice.getGroupId(), volume);
for (AudioSharingDeviceVolumePreference preference : mVolumePreferences) {
if (preference.getCachedDevice() != null
&& preference.getCachedDevice().getGroupId()
== cachedDevice.getGroupId()) {
// If the callback return invalid volume, try to
// get the volume from AudioManager.STREAM_MUSIC
int finalVolume = getAudioVolumeIfNeeded(volume);
Log.d(
TAG,
"onDeviceVolumeChanged: set volume to "
+ finalVolume
+ " for "
+ device.getAnonymizedAddress());
mContext.getMainExecutor()
.execute(() -> preference.setProgress(finalVolume));
break;
}
}
}
};
private BluetoothLeBroadcastAssistant.Callback mBroadcastAssistantCallback =
new BluetoothLeBroadcastAssistant.Callback() {
@@ -176,6 +209,10 @@ public class AudioSharingDeviceVolumeGroupController extends AudioSharingBasePre
}
mAssistant.registerServiceCallBack(mExecutor, mBroadcastAssistantCallback);
mBluetoothDeviceUpdater.registerCallback();
if (mVolumeControl != null) {
Log.d(TAG, "onStart() Registered volume control callback");
mVolumeControl.registerCallback(mExecutor, mVolumeControlCallback);
}
}
@Override
@@ -191,17 +228,16 @@ public class AudioSharingDeviceVolumeGroupController extends AudioSharingBasePre
}
mAssistant.unregisterServiceCallBack(mBroadcastAssistantCallback);
mBluetoothDeviceUpdater.unregisterCallback();
if (mVolumeControl != null) {
Log.d(TAG, "onStop() Unregistered volume control callback");
mVolumeControl.unregisterCallback(mVolumeControlCallback);
mValueMap.clear();
}
}
@Override
public void onDestroy(@NonNull LifecycleOwner owner) {
for (var entry : mCallbackMap.entrySet()) {
if (DEBUG) {
Log.d(TAG, "onDestroy: unregister callback for " + entry.getKey());
}
mVolumeControl.unregisterCallback(entry.getValue());
}
mCallbackMap.clear();
mVolumePreferences.clear();
}
@Override
@@ -228,14 +264,22 @@ public class AudioSharingDeviceVolumeGroupController extends AudioSharingBasePre
mPreferenceGroup.setVisible(true);
}
mPreferenceGroup.addPreference(preference);
if (mVolumeControl != null && preference instanceof AudioSharingDeviceVolumePreference) {
BluetoothVolumeControl.Callback callback =
buildVcCallback((AudioSharingDeviceVolumePreference) preference);
mCallbackMap.put(preference, callback);
if (DEBUG) {
Log.d(TAG, "onDeviceAdded: register callback for " + preference);
}
mVolumeControl.registerCallback(mExecutor, callback);
if (preference instanceof AudioSharingDeviceVolumePreference) {
var volumePref = (AudioSharingDeviceVolumePreference) preference;
mVolumePreferences.add(volumePref);
if (volumePref.getProgress() > 0) return;
CachedBluetoothDevice device = volumePref.getCachedDevice();
if (device == null) return;
int volume = mValueMap.getOrDefault(device.getGroupId(), -1);
// If the volume is invalid, try to get the volume from AudioManager.STREAM_MUSIC
int finalVolume = getAudioVolumeIfNeeded(volume);
Log.d(
TAG,
"onDeviceAdded: set volume to "
+ finalVolume
+ " for "
+ device.getDevice().getAnonymizedAddress());
mContext.getMainExecutor().execute(() -> volumePref.setProgress(finalVolume));
}
}
@@ -245,12 +289,18 @@ public class AudioSharingDeviceVolumeGroupController extends AudioSharingBasePre
if (mPreferenceGroup.getPreferenceCount() == 0) {
mPreferenceGroup.setVisible(false);
}
if (mVolumeControl != null && mCallbackMap.containsKey(preference)) {
if (DEBUG) {
Log.d(TAG, "onDeviceRemoved: unregister callback for " + preference);
if (preference instanceof AudioSharingDeviceVolumePreference) {
var volumePref = (AudioSharingDeviceVolumePreference) preference;
if (mVolumePreferences.contains(volumePref)) {
mVolumePreferences.remove(volumePref);
}
mVolumeControl.unregisterCallback(mCallbackMap.get(preference));
mCallbackMap.remove(preference);
CachedBluetoothDevice device = volumePref.getCachedDevice();
Log.d(
TAG,
"onDeviceRemoved: "
+ (device == null
? "null"
: device.getDevice().getAnonymizedAddress()));
}
}
@@ -278,39 +328,6 @@ public class AudioSharingDeviceVolumeGroupController extends AudioSharingBasePre
fragment.getMetricsCategory());
}
private BluetoothVolumeControl.Callback buildVcCallback(
AudioSharingDeviceVolumePreference preference) {
return new BluetoothVolumeControl.Callback() {
@Override
public void onVolumeOffsetChanged(BluetoothDevice device, int volumeOffset) {}
@Override
public void onDeviceVolumeChanged(
@NonNull BluetoothDevice device,
@IntRange(from = -255, to = 255) int volume) {
CachedBluetoothDevice cachedDevice =
mLocalBtManager.getCachedDeviceManager().findDevice(device);
if (cachedDevice == null) return;
if (preference.getCachedDevice() != null
&& preference.getCachedDevice().getGroupId() == cachedDevice.getGroupId()) {
// If the callback return invalid volume, try to get the volume from
// AudioManager.STREAM_MUSIC
int finalVolume = getAudioVolumeIfNeeded(volume);
Log.d(
TAG,
"onDeviceVolumeChanged: set volume to "
+ finalVolume
+ " for "
+ device.getAnonymizedAddress());
ThreadUtils.postOnMainThread(
() -> {
preference.setProgress(finalVolume);
});
}
}
};
}
private int getAudioVolumeIfNeeded(int volume) {
if (volume >= 0) return volume;
try {