Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 389ab6a6 authored by Yiyi Shen's avatar Yiyi Shen
Browse files

[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
parent 4e0fc12d
Loading
Loading
Loading
Loading
+76 −59
Original line number Diff line number Diff line
@@ -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 {