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

Commit 78a667e7 authored by chelseahao's avatar chelseahao Committed by Chelsea Hao
Browse files

[Audiosharing] Hide / show audio streams category.

Only show when there is an active LE buds connecting, and the source is
not currently broadcasting.

Bug: 308368124
Test: Manual
Change-Id: I2cc172a66648901ac8a7e49c5aac734b6bbc7e33
parent 40cc58f5
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -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);
    }
}
+4 −0
Original line number Diff line number Diff line
@@ -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);
    }
}
+26 −0
Original line number Diff line number Diff line
@@ -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<CachedBluetoothDevice> 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(
+1 −21
Original line number Diff line number Diff line
@@ -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<CachedBluetoothDevice> 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 {
        /**
+70 −2
Original line number Diff line number Diff line
@@ -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;

import java.util.concurrent.Executor;
import java.util.concurrent.Executors;

public class AudioStreamsCategoryController extends PreferenceCategoryController {
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));
                });
    }
}