From 43611adcf3f4d650148a0aa64463571c8526d003 Mon Sep 17 00:00:00 2001 From: chelseahao Date: Wed, 22 Nov 2023 17:21:37 +0800 Subject: [PATCH] [Audiosharing] Impl "Listen with" row. This row will show the currently connected and active LE buds. There should be no more than one pair. Bug: 308368124 Test: Manual Change-Id: I281d7f7c6debaeb34b8206fe587cb776ea0eb0ec --- res/xml/bluetooth_audio_streams.xml | 5 + .../AudioStreamsActiveDeviceController.java | 67 +++++++++++++ ...udioStreamsActiveDeviceSummaryUpdater.java | 98 +++++++++++++++++++ 3 files changed, 170 insertions(+) create mode 100644 src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsActiveDeviceController.java create mode 100644 src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsActiveDeviceSummaryUpdater.java diff --git a/res/xml/bluetooth_audio_streams.xml b/res/xml/bluetooth_audio_streams.xml index ce7374be079..206fb34e5b6 100644 --- a/res/xml/bluetooth_audio_streams.xml +++ b/res/xml/bluetooth_audio_streams.xml @@ -26,6 +26,11 @@ android:icon="@drawable/ic_add_24dp" android:summary="@string/audio_streams_qr_code_summary" /> + + diff --git a/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsActiveDeviceController.java b/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsActiveDeviceController.java new file mode 100644 index 00000000000..f1119fcf655 --- /dev/null +++ b/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsActiveDeviceController.java @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2023 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.connecteddevice.audiosharing.audiostreams; + +import android.content.Context; + +import androidx.annotation.NonNull; +import androidx.lifecycle.DefaultLifecycleObserver; +import androidx.lifecycle.LifecycleOwner; +import androidx.preference.Preference; +import androidx.preference.PreferenceScreen; + +import com.android.settings.core.BasePreferenceController; +import com.android.settings.widget.SummaryUpdater; + +public class AudioStreamsActiveDeviceController extends BasePreferenceController + implements SummaryUpdater.OnSummaryChangeListener, DefaultLifecycleObserver { + + public static final String KEY = "audio_streams_active_device"; + private final AudioStreamsActiveDeviceSummaryUpdater mSummaryHelper; + private Preference mPreference; + + public AudioStreamsActiveDeviceController(Context context, String preferenceKey) { + super(context, preferenceKey); + mSummaryHelper = new AudioStreamsActiveDeviceSummaryUpdater(mContext, this); + } + + @Override + public void displayPreference(PreferenceScreen screen) { + super.displayPreference(screen); + mPreference = screen.findPreference(KEY); + } + + @Override + public int getAvailabilityStatus() { + return AVAILABLE; + } + + @Override + public void onSummaryChanged(String summary) { + mPreference.setSummary(summary); + } + + @Override + public void onResume(@NonNull LifecycleOwner owner) { + mSummaryHelper.register(true); + } + + @Override + public void onStop(@NonNull LifecycleOwner owner) { + mSummaryHelper.register(false); + } +} diff --git a/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsActiveDeviceSummaryUpdater.java b/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsActiveDeviceSummaryUpdater.java new file mode 100644 index 00000000000..66101f7d1c6 --- /dev/null +++ b/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsActiveDeviceSummaryUpdater.java @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2023 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.connecteddevice.audiosharing.audiostreams; + +import android.annotation.Nullable; +import android.bluetooth.BluetoothProfile; +import android.content.Context; +import android.util.Log; + +import com.android.settings.bluetooth.Utils; +import com.android.settings.connecteddevice.audiosharing.AudioSharingUtils; +import com.android.settings.widget.SummaryUpdater; +import com.android.settingslib.bluetooth.BluetoothCallback; +import com.android.settingslib.bluetooth.BluetoothUtils; +import com.android.settingslib.bluetooth.CachedBluetoothDevice; +import com.android.settingslib.bluetooth.LocalBluetoothManager; + +import java.util.Optional; + +public class AudioStreamsActiveDeviceSummaryUpdater extends SummaryUpdater + implements BluetoothCallback { + private static final String TAG = "AudioStreamsListenWithSummaryUpdater"; + private static final boolean DEBUG = BluetoothUtils.D; + private final LocalBluetoothManager mBluetoothManager; + + public AudioStreamsActiveDeviceSummaryUpdater( + Context context, OnSummaryChangeListener listener) { + super(context, listener); + mBluetoothManager = Utils.getLocalBluetoothManager(context); + } + + @Override + public void onActiveDeviceChanged( + @Nullable CachedBluetoothDevice activeDevice, int bluetoothProfile) { + if (DEBUG) { + Log.d( + TAG, + "onActiveDeviceChanged() with activeDevice : " + + (activeDevice == null ? "null" : activeDevice.getAddress()) + + " on profile : " + + bluetoothProfile); + } + if (bluetoothProfile == BluetoothProfile.LE_AUDIO) { + notifyChangeIfNeeded(); + } + } + + @Override + public void register(boolean register) { + if (register) { + notifyChangeIfNeeded(); + mBluetoothManager.getEventManager().registerCallback(this); + } else { + mBluetoothManager.getEventManager().unregisterCallback(this); + } + } + + @Override + protected String getSummary() { + var activeSink = getActiveSinkOnAssistant(mBluetoothManager); + if (activeSink.isEmpty()) { + return "No active LE Audio device"; + } + return activeSink.get().getName(); + } + + private static Optional getActiveSinkOnAssistant( + LocalBluetoothManager manager) { + if (manager == null) { + Log.w(TAG, "getActiveSinksOnAssistant(): LocalBluetoothManager is null!"); + return Optional.empty(); + } + var groupedDevices = AudioSharingUtils.fetchConnectedDevicesByGroupId(manager); + var leadDevices = + AudioSharingUtils.buildOrderedConnectedLeadDevices(manager, groupedDevices, false); + + if (!leadDevices.isEmpty() && AudioSharingUtils.isActiveLeAudioDevice(leadDevices.get(0))) { + return Optional.of(leadDevices.get(0)); + } else { + Log.w(TAG, "getActiveSinksOnAssistant(): No active lead device!"); + } + return Optional.empty(); + } +}