diff --git a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingBasePreferenceController.java b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingBasePreferenceController.java index 9ebe26d2c58..21f1c0e4f73 100644 --- a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingBasePreferenceController.java +++ b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingBasePreferenceController.java @@ -64,7 +64,7 @@ public abstract class AudioSharingBasePreferenceController extends BasePreferenc mPreference.setVisible(isVisible); } - private boolean isBroadcasting() { + protected boolean isBroadcasting() { return mBroadcast != null && mBroadcast.isEnabled(null); } } diff --git a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDashboardFragment.java b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDashboardFragment.java index cf5881b3dfe..7f90cebcf46 100644 --- a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDashboardFragment.java +++ b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDashboardFragment.java @@ -22,6 +22,7 @@ import android.os.Bundle; import com.android.settings.R; import com.android.settings.SettingsActivity; +import com.android.settings.connecteddevice.audiosharing.audiostreams.AudioStreamsCategoryController; import com.android.settings.dashboard.DashboardFragment; import com.android.settings.widget.SettingsMainSwitchBar; @@ -34,6 +35,7 @@ public class AudioSharingDashboardFragment extends DashboardFragment private AudioSharingDeviceVolumeGroupController mAudioSharingDeviceVolumeGroupController; private CallsAndAlarmsPreferenceController mCallsAndAlarmsPreferenceController; private AudioSharingNamePreferenceController mAudioSharingNamePreferenceController; + private AudioStreamsCategoryController mAudioStreamsCategoryController; public AudioSharingDashboardFragment() { super(); @@ -73,6 +75,7 @@ public class AudioSharingDashboardFragment extends DashboardFragment mCallsAndAlarmsPreferenceController = use(CallsAndAlarmsPreferenceController.class); mCallsAndAlarmsPreferenceController.init(this); mAudioSharingNamePreferenceController = use(AudioSharingNamePreferenceController.class); + mAudioStreamsCategoryController = use(AudioStreamsCategoryController.class); } @Override @@ -98,5 +101,6 @@ public class AudioSharingDashboardFragment extends DashboardFragment mAudioSharingDeviceVolumeGroupController.updateVisibility(isVisible); mCallsAndAlarmsPreferenceController.updateVisibility(isVisible); mAudioSharingNamePreferenceController.updateVisibility(isVisible); + mAudioStreamsCategoryController.updateVisibility(isVisible); } } diff --git a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingUtils.java b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingUtils.java index 53e095b6f9d..1a5049638a4 100644 --- a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingUtils.java +++ b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingUtils.java @@ -34,6 +34,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.stream.Collectors; public class AudioSharingUtils { @@ -229,6 +230,31 @@ public class AudioSharingUtils { return false; } + /** + * Retrieves the one and only active Bluetooth LE Audio sink device, regardless if the device is + * currently in an audio sharing session. + * + * @param manager The LocalBluetoothManager instance used to fetch connected devices. + * @return An Optional containing the active LE Audio device, or an empty Optional if not found. + */ + public 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(); + } + /** Toast message on main thread. */ public static void toastMessage(Context context, String message) { ThreadUtils.postOnMainThread( diff --git a/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsActiveDeviceSummaryUpdater.java b/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsActiveDeviceSummaryUpdater.java index cf79596df19..0d3b1b12ff3 100644 --- a/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsActiveDeviceSummaryUpdater.java +++ b/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsActiveDeviceSummaryUpdater.java @@ -30,8 +30,6 @@ import com.android.settingslib.bluetooth.CachedBluetoothDevice; import com.android.settingslib.bluetooth.LocalBluetoothManager; import com.android.settingslib.utils.ThreadUtils; -import java.util.Optional; - public class AudioStreamsActiveDeviceSummaryUpdater implements BluetoothCallback { private static final String TAG = "AudioStreamsActiveDeviceSummaryUpdater"; private static final boolean DEBUG = BluetoothUtils.D; @@ -82,31 +80,13 @@ public class AudioStreamsActiveDeviceSummaryUpdater implements BluetoothCallback } private String getSummary() { - var activeSink = getActiveSinkOnAssistant(mBluetoothManager); + var activeSink = AudioSharingUtils.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(); - } - /** Interface definition for a callback to be invoked when the summary has been changed. */ interface OnSummaryChangeListener { /** diff --git a/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsCategoryController.java b/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsCategoryController.java index 84a7be91b03..f80fdab4ffd 100644 --- a/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsCategoryController.java +++ b/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsCategoryController.java @@ -16,15 +16,64 @@ package com.android.settings.connecteddevice.audiosharing.audiostreams; +import android.annotation.Nullable; +import android.bluetooth.BluetoothProfile; import android.content.Context; +import android.util.Log; +import androidx.annotation.NonNull; +import androidx.lifecycle.DefaultLifecycleObserver; +import androidx.lifecycle.LifecycleOwner; + +import com.android.settings.bluetooth.Utils; +import com.android.settings.connecteddevice.audiosharing.AudioSharingBasePreferenceController; +import com.android.settings.connecteddevice.audiosharing.AudioSharingUtils; import com.android.settings.flags.Flags; -import com.android.settings.widget.PreferenceCategoryController; +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 com.android.settingslib.utils.ThreadUtils; -public class AudioStreamsCategoryController extends PreferenceCategoryController { +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; + +public class AudioStreamsCategoryController extends AudioSharingBasePreferenceController + implements DefaultLifecycleObserver { + private static final String TAG = "AudioStreamsCategoryController"; + private static final boolean DEBUG = BluetoothUtils.D; + private final LocalBluetoothManager mLocalBtManager; + private final Executor mExecutor; + private final BluetoothCallback mBluetoothCallback = + new BluetoothCallback() { + @Override + public void onActiveDeviceChanged( + @Nullable CachedBluetoothDevice activeDevice, int bluetoothProfile) { + if (bluetoothProfile == BluetoothProfile.LE_AUDIO) { + updateVisibility(isBroadcasting()); + } + } + }; public AudioStreamsCategoryController(Context context, String key) { super(context, key); + mLocalBtManager = Utils.getLocalBtManager(mContext); + mExecutor = Executors.newSingleThreadExecutor(); + } + + @Override + public void onStart(@NonNull LifecycleOwner owner) { + if (mLocalBtManager != null) { + mLocalBtManager.getEventManager().registerCallback(mBluetoothCallback); + } + updateVisibility(isBroadcasting()); + } + + @Override + public void onStop(@NonNull LifecycleOwner owner) { + if (mLocalBtManager != null) { + mLocalBtManager.getEventManager().unregisterCallback(mBluetoothCallback); + } } @Override @@ -33,4 +82,23 @@ public class AudioStreamsCategoryController extends PreferenceCategoryController ? AVAILABLE : UNSUPPORTED_ON_DEVICE; } + + @Override + public void updateVisibility(boolean isBroadcasting) { + mExecutor.execute( + () -> { + boolean hasActiveLe = + AudioSharingUtils.getActiveSinkOnAssistant(mLocalBtManager).isPresent(); + if (DEBUG) { + Log.d( + TAG, + "updateVisibility() isBroadcasting : " + + isBroadcasting + + " hasActiveLe : " + + hasActiveLe); + } + ThreadUtils.postOnMainThread( + () -> super.updateVisibility(hasActiveLe && !isBroadcasting)); + }); + } }