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

Commit 169133aa authored by Betty Chang's avatar Betty Chang Committed by Android (Google) Code Review
Browse files

Merge "[LE Broadcast] Add the active LE device into broadcast when broadcasting" into udc-dev

parents 94790d99 ad708d4d
Loading
Loading
Loading
Loading
+10 −6
Original line number Diff line number Diff line
@@ -78,7 +78,7 @@ public abstract class MediaOutputBaseDialog extends SystemUIDialog implements
    private static final boolean DEBUG = true;
    private static final int HANDLE_BROADCAST_FAILED_DELAY = 3000;

    private final Handler mMainThreadHandler = new Handler(Looper.getMainLooper());
    protected final Handler mMainThreadHandler = new Handler(Looper.getMainLooper());
    private final RecyclerView.LayoutManager mLayoutManager;

    final Context mContext;
@@ -102,11 +102,13 @@ public abstract class MediaOutputBaseDialog extends SystemUIDialog implements
    private int mListMaxHeight;
    private int mItemHeight;
    private WallpaperColors mWallpaperColors;
    private Executor mExecutor;
    private boolean mShouldLaunchLeBroadcastDialog;
    private boolean mIsLeBroadcastCallbackRegistered;

    MediaOutputBaseAdapter mAdapter;

    protected Executor mExecutor;

    private final ViewTreeObserver.OnGlobalLayoutListener mDeviceListLayoutListener = () -> {
        ViewGroup.LayoutParams params = mDeviceListLayout.getLayoutParams();
        int totalItemsHeight = mAdapter.getItemCount() * mItemHeight;
@@ -274,17 +276,19 @@ public abstract class MediaOutputBaseDialog extends SystemUIDialog implements
    public void onStart() {
        super.onStart();
        mMediaOutputController.start(this);
        if(isBroadcastSupported()) {
            mMediaOutputController.registerLeBroadcastServiceCallBack(mExecutor,
        if (isBroadcastSupported() && !mIsLeBroadcastCallbackRegistered) {
            mMediaOutputController.registerLeBroadcastServiceCallback(mExecutor,
                    mBroadcastCallback);
            mIsLeBroadcastCallbackRegistered = true;
        }
    }

    @Override
    public void onStop() {
        super.onStop();
        if(isBroadcastSupported()) {
            mMediaOutputController.unregisterLeBroadcastServiceCallBack(mBroadcastCallback);
        if (isBroadcastSupported() && mIsLeBroadcastCallbackRegistered) {
            mMediaOutputController.unregisterLeBroadcastServiceCallback(mBroadcastCallback);
            mIsLeBroadcastCallbackRegistered = false;
        }
        mMediaOutputController.stop();
    }
+149 −3
Original line number Diff line number Diff line
@@ -17,6 +17,10 @@
package com.android.systemui.media.dialog;

import android.app.AlertDialog;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothLeBroadcastAssistant;
import android.bluetooth.BluetoothLeBroadcastMetadata;
import android.bluetooth.BluetoothLeBroadcastReceiveState;
import android.content.Context;
import android.graphics.Bitmap;
import android.os.Bundle;
@@ -34,8 +38,11 @@ import android.widget.EditText;
import android.widget.ImageView;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.core.graphics.drawable.IconCompat;

import com.android.settingslib.media.BluetoothMediaDevice;
import com.android.settingslib.media.MediaDevice;
import com.android.settingslib.qrcode.QrCodeGenerator;
import com.android.systemui.R;
import com.android.systemui.broadcast.BroadcastSender;
@@ -49,7 +56,7 @@ import com.google.zxing.WriterException;
 */
@SysUISingleton
public class MediaOutputBroadcastDialog extends MediaOutputBaseDialog {
    private static final String TAG = "BroadcastDialog";
    private static final String TAG = "MediaOutputBroadcastDialog";

    private ViewStub mBroadcastInfoArea;
    private ImageView mBroadcastQrCodeView;
@@ -66,6 +73,7 @@ public class MediaOutputBroadcastDialog extends MediaOutputBaseDialog {
    private String mCurrentBroadcastName;
    private String mCurrentBroadcastCode;
    private boolean mIsStopbyUpdateBroadcastCode = false;

    private TextWatcher mTextWatcher = new TextWatcher() {
        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) {
@@ -105,6 +113,79 @@ public class MediaOutputBroadcastDialog extends MediaOutputBaseDialog {
        }
    };

    private boolean mIsLeBroadcastAssistantCallbackRegistered;

    private BluetoothLeBroadcastAssistant.Callback mBroadcastAssistantCallback =
            new BluetoothLeBroadcastAssistant.Callback() {
                @Override
                public void onSearchStarted(int reason) {
                    Log.d(TAG, "Assistant-onSearchStarted: " + reason);
                }

                @Override
                public void onSearchStartFailed(int reason) {
                    Log.d(TAG, "Assistant-onSearchStartFailed: " + reason);
                }

                @Override
                public void onSearchStopped(int reason) {
                    Log.d(TAG, "Assistant-onSearchStopped: " + reason);
                }

                @Override
                public void onSearchStopFailed(int reason) {
                    Log.d(TAG, "Assistant-onSearchStopFailed: " + reason);
                }

                @Override
                public void onSourceFound(@NonNull BluetoothLeBroadcastMetadata source) {
                    Log.d(TAG, "Assistant-onSourceFound:");
                }

                @Override
                public void onSourceAdded(@NonNull BluetoothDevice sink, int sourceId, int reason) {
                    Log.d(TAG, "Assistant-onSourceAdded: Device: " + sink
                            + ", sourceId: " + sourceId);
                    mMainThreadHandler.post(() -> refreshUi());
                }

                @Override
                public void onSourceAddFailed(@NonNull BluetoothDevice sink,
                        @NonNull BluetoothLeBroadcastMetadata source, int reason) {
                    Log.d(TAG, "Assistant-onSourceAddFailed: Device: " + sink);
                }

                @Override
                public void onSourceModified(@NonNull BluetoothDevice sink, int sourceId,
                        int reason) {
                    Log.d(TAG, "Assistant-onSourceModified:");
                }

                @Override
                public void onSourceModifyFailed(@NonNull BluetoothDevice sink, int sourceId,
                        int reason) {
                    Log.d(TAG, "Assistant-onSourceModifyFailed:");
                }

                @Override
                public void onSourceRemoved(@NonNull BluetoothDevice sink, int sourceId,
                        int reason) {
                    Log.d(TAG, "Assistant-onSourceRemoved:");
                }

                @Override
                public void onSourceRemoveFailed(@NonNull BluetoothDevice sink, int sourceId,
                        int reason) {
                    Log.d(TAG, "Assistant-onSourceRemoveFailed:");
                }

                @Override
                public void onReceiveStateChanged(@NonNull BluetoothDevice sink, int sourceId,
                        @NonNull BluetoothLeBroadcastReceiveState state) {
                    Log.d(TAG, "Assistant-onReceiveStateChanged:");
                }
            };

    static final int METADATA_BROADCAST_NAME = 0;
    static final int METADATA_BROADCAST_CODE = 1;

@@ -130,6 +211,27 @@ public class MediaOutputBroadcastDialog extends MediaOutputBaseDialog {
        initBtQrCodeUI();
    }

    @Override
    public void onStart() {
        super.onStart();
        if (!mIsLeBroadcastAssistantCallbackRegistered) {
            mIsLeBroadcastAssistantCallbackRegistered = true;
            mMediaOutputController.registerLeBroadcastAssistantServiceCallback(mExecutor,
                    mBroadcastAssistantCallback);
        }
        connectBroadcastWithActiveDevice();
    }

    @Override
    public void onStop() {
        super.onStop();
        if (mIsLeBroadcastAssistantCallbackRegistered) {
            mIsLeBroadcastAssistantCallbackRegistered = false;
            mMediaOutputController.unregisterLeBroadcastAssistantServiceCallback(
                    mBroadcastAssistantCallback);
        }
    }

    @Override
    int getHeaderIconRes() {
        return 0;
@@ -224,6 +326,7 @@ public class MediaOutputBroadcastDialog extends MediaOutputBaseDialog {
        mCurrentBroadcastCode = getBroadcastMetadataInfo(METADATA_BROADCAST_CODE);
        mBroadcastName.setText(mCurrentBroadcastName);
        mBroadcastCode.setText(mCurrentBroadcastCode);
        refresh(false);
    }

    private void inflateBroadcastInfoArea() {
@@ -233,7 +336,7 @@ public class MediaOutputBroadcastDialog extends MediaOutputBaseDialog {

    private void setQrCodeView() {
        //get the Metadata, and convert to BT QR code format.
        String broadcastMetadata = getBroadcastMetadata();
        String broadcastMetadata = getLocalBroadcastMetadataQrCodeString();
        if (broadcastMetadata.isEmpty()) {
            //TDOD(b/226708424) Error handling for unable to generate the QR code bitmap
            return;
@@ -249,6 +352,33 @@ public class MediaOutputBroadcastDialog extends MediaOutputBaseDialog {
        }
    }

    void connectBroadcastWithActiveDevice() {
        //get the Metadata, and convert to BT QR code format.
        BluetoothLeBroadcastMetadata broadcastMetadata = getBroadcastMetadata();
        if (broadcastMetadata == null) {
            Log.e(TAG, "Error: There is no broadcastMetadata.");
            return;
        }
        MediaDevice mediaDevice = mMediaOutputController.getCurrentConnectedMediaDevice();
        if (mediaDevice == null || !(mediaDevice instanceof BluetoothMediaDevice)
                || !mediaDevice.isBLEDevice()) {
            Log.e(TAG, "Error: There is no active BT LE device.");
            return;
        }
        BluetoothDevice sink = ((BluetoothMediaDevice) mediaDevice).getCachedDevice().getDevice();
        Log.d(TAG, "The broadcastMetadata broadcastId: " + broadcastMetadata.getBroadcastId()
                + ", the device: " + sink.getAnonymizedAddress());

        if (mMediaOutputController.isThereAnyBroadcastSourceIntoSinkDevice(sink)) {
            Log.d(TAG, "The sink device has the broadcast source now.");
            return;
        }
        if (!mMediaOutputController.addSourceIntoSinkDeviceWithBluetoothLeAssistant(sink,
                broadcastMetadata, /*isGroupOp=*/ true)) {
            Log.e(TAG, "Error: Source add failed");
        }
    }

    private void updateBroadcastCodeVisibility() {
        mBroadcastCode.setTransformationMethod(
                mIsPasswordHide ? HideReturnsTransformationMethod.getInstance()
@@ -282,7 +412,11 @@ public class MediaOutputBroadcastDialog extends MediaOutputBaseDialog {
        mAlertDialog.show();
    }

    private String getBroadcastMetadata() {
    private String getLocalBroadcastMetadataQrCodeString() {
        return mMediaOutputController.getLocalBroadcastMetadataQrCodeString();
    }

    private BluetoothLeBroadcastMetadata getBroadcastMetadata() {
        return mMediaOutputController.getBroadcastMetadata();
    }

@@ -313,6 +447,17 @@ public class MediaOutputBroadcastDialog extends MediaOutputBaseDialog {
        }
    }

    @Override
    public boolean isBroadcastSupported() {
        boolean isBluetoothLeDevice = false;
        if (mMediaOutputController.getCurrentConnectedMediaDevice() != null) {
            isBluetoothLeDevice = mMediaOutputController.isBluetoothLeDevice(
                    mMediaOutputController.getCurrentConnectedMediaDevice());
        }

        return mMediaOutputController.isBroadcastSupported() && isBluetoothLeDevice;
    }

    @Override
    public void handleLeBroadcastStarted() {
        mRetryCount = 0;
@@ -332,6 +477,7 @@ public class MediaOutputBroadcastDialog extends MediaOutputBaseDialog {

    @Override
    public void handleLeBroadcastMetadataChanged() {
        Log.d(TAG, "handleLeBroadcastMetadataChanged:");
        refreshUi();
    }

+70 −3
Original line number Diff line number Diff line
@@ -25,7 +25,11 @@ import android.app.AlertDialog;
import android.app.KeyguardManager;
import android.app.Notification;
import android.app.WallpaperColors;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothLeBroadcast;
import android.bluetooth.BluetoothLeBroadcastAssistant;
import android.bluetooth.BluetoothLeBroadcastMetadata;
import android.bluetooth.BluetoothLeBroadcastReceiveState;
import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
@@ -66,6 +70,7 @@ import com.android.settingslib.RestrictedLockUtilsInternal;
import com.android.settingslib.Utils;
import com.android.settingslib.bluetooth.BluetoothUtils;
import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast;
import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant;
import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastMetadata;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.settingslib.media.InfoMediaManager;
@@ -1049,7 +1054,7 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback,
                ALLOWLIST_DURATION_MS);
    }

    String getBroadcastMetadata() {
    String getLocalBroadcastMetadataQrCodeString() {
        LocalBluetoothLeBroadcast broadcast =
                mLocalBluetoothManager.getProfileManager().getLeAudioBroadcastProfile();
        if (broadcast == null) {
@@ -1061,6 +1066,17 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback,
        return metadata != null ? metadata.convertToQrCodeString() : "";
    }

    BluetoothLeBroadcastMetadata getBroadcastMetadata() {
        LocalBluetoothLeBroadcast broadcast =
                mLocalBluetoothManager.getProfileManager().getLeAudioBroadcastProfile();
        if (broadcast == null) {
            Log.d(TAG, "getBroadcastMetadata: LE Audio Broadcast is null");
            return null;
        }

        return broadcast.getLatestBluetoothLeBroadcastMetadata();
    }

    boolean isActiveRemoteDevice(@NonNull MediaDevice device) {
        final List<String> features = device.getFeatures();
        return (features.contains(MediaRoute2Info.FEATURE_REMOTE_PLAYBACK)
@@ -1121,7 +1137,7 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback,
        return true;
    }

    void registerLeBroadcastServiceCallBack(
    void registerLeBroadcastServiceCallback(
            @NonNull @CallbackExecutor Executor executor,
            @NonNull BluetoothLeBroadcast.Callback callback) {
        LocalBluetoothLeBroadcast broadcast =
@@ -1130,10 +1146,11 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback,
            Log.d(TAG, "The broadcast profile is null");
            return;
        }
        Log.d(TAG, "Register LE broadcast callback");
        broadcast.registerServiceCallBack(executor, callback);
    }

    void unregisterLeBroadcastServiceCallBack(
    void unregisterLeBroadcastServiceCallback(
            @NonNull BluetoothLeBroadcast.Callback callback) {
        LocalBluetoothLeBroadcast broadcast =
                mLocalBluetoothManager.getProfileManager().getLeAudioBroadcastProfile();
@@ -1141,9 +1158,59 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback,
            Log.d(TAG, "The broadcast profile is null");
            return;
        }
        Log.d(TAG, "Unregister LE broadcast callback");
        broadcast.unregisterServiceCallBack(callback);
    }

    boolean isThereAnyBroadcastSourceIntoSinkDevice(BluetoothDevice sink) {
        LocalBluetoothLeBroadcastAssistant assistant =
                mLocalBluetoothManager.getProfileManager().getLeAudioBroadcastAssistantProfile();
        if (assistant == null) {
            Log.d(TAG, "The broadcast assistant profile is null");
            return false;
        }
        List<BluetoothLeBroadcastReceiveState> sourceList = assistant.getAllSources(sink);
        Log.d(TAG, "isThereAnyBroadcastSourceIntoSinkDevice: List size: " + sourceList.size());
        return !sourceList.isEmpty();
    }

    boolean addSourceIntoSinkDeviceWithBluetoothLeAssistant(BluetoothDevice sink,
            BluetoothLeBroadcastMetadata metadata, boolean isGroupOp) {
        LocalBluetoothLeBroadcastAssistant assistant =
                mLocalBluetoothManager.getProfileManager().getLeAudioBroadcastAssistantProfile();
        if (assistant == null) {
            Log.d(TAG, "The broadcast assistant profile is null");
            return false;
        }
        assistant.addSource(sink, metadata, isGroupOp);
        return true;
    }

    void registerLeBroadcastAssistantServiceCallback(
            @NonNull @CallbackExecutor Executor executor,
            @NonNull BluetoothLeBroadcastAssistant.Callback callback) {
        LocalBluetoothLeBroadcastAssistant assistant =
                mLocalBluetoothManager.getProfileManager().getLeAudioBroadcastAssistantProfile();
        if (assistant == null) {
            Log.d(TAG, "The broadcast assistant profile is null");
            return;
        }
        Log.d(TAG, "Register LE broadcast assistant callback");
        assistant.registerServiceCallBack(executor, callback);
    }

    void unregisterLeBroadcastAssistantServiceCallback(
            @NonNull BluetoothLeBroadcastAssistant.Callback callback) {
        LocalBluetoothLeBroadcastAssistant assistant =
                mLocalBluetoothManager.getProfileManager().getLeAudioBroadcastAssistantProfile();
        if (assistant == null) {
            Log.d(TAG, "The broadcast assistant profile is null");
            return;
        }
        Log.d(TAG, "Unregister LE broadcast assistant callback");
        assistant.unregisterServiceCallBack(callback);
    }

    private boolean isPlayBackInfoLocal() {
        return mMediaController != null
                && mMediaController.getPlaybackInfo() != null
+195 −0

File added.

Preview size limit exceeded, changes collapsed.