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

Commit 228bfe17 authored by Jakub Pawłowski's avatar Jakub Pawłowski Committed by Android (Google) Code Review
Browse files

Merge changes I00f79365,Ic7f063e7,I8ec37403 into main

* changes:
  MediaOutputController: Distinguish broadcast check context in logs
  LocalBluetoothLeBroadcast: Remove sources on broadcast stop
  MediaOutputController: Broadcast to connected capable devices
parents ad677c37 009c379c
Loading
Loading
Loading
Loading
+159 −32
Original line number Diff line number Diff line
@@ -25,10 +25,13 @@ import android.bluetooth.BluetoothClass;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothLeAudioContentMetadata;
import android.bluetooth.BluetoothLeBroadcast;
import android.bluetooth.BluetoothLeBroadcastAssistant;
import android.bluetooth.BluetoothLeBroadcastMetadata;
import android.bluetooth.BluetoothLeBroadcastReceiveState;
import android.bluetooth.BluetoothLeBroadcastSubgroup;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.BluetoothProfile.ServiceListener;
import android.bluetooth.BluetoothStatusCodes;
import android.content.ContentResolver;
import android.content.Context;
import android.database.ContentObserver;
@@ -39,6 +42,7 @@ import android.os.Looper;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.Log;
import android.util.Pair;

import androidx.annotation.RequiresApi;

@@ -76,14 +80,16 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile {
            Settings.Secure.getUriFor(Settings.Secure.BLUETOOTH_LE_BROADCAST_APP_SOURCE_NAME),
    };

    private BluetoothLeBroadcast mService;
    private BluetoothLeBroadcast mServiceBroadcast;
    private BluetoothLeBroadcastAssistant mServiceBroadcastAssistant;
    private BluetoothLeAudioContentMetadata mBluetoothLeAudioContentMetadata;
    private BluetoothLeBroadcastMetadata mBluetoothLeBroadcastMetadata;
    private BluetoothLeAudioContentMetadata.Builder mBuilder;
    private int mBroadcastId = UNKNOWN_VALUE_PLACEHOLDER;
    private String mAppSourceName = "";
    private String mNewAppSourceName = "";
    private boolean mIsProfileReady;
    private boolean mIsBroadcastProfileReady = false;
    private boolean mIsBroadcastAssistantProfileReady = false;
    private String mProgramInfo;
    private byte[] mBroadcastCode;
    private Executor mExecutor;
@@ -94,17 +100,22 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile {
        @Override
        public void onServiceConnected(int profile, BluetoothProfile proxy) {
            if (DEBUG) {
                Log.d(TAG, "Bluetooth service connected");
                Log.d(TAG, "Bluetooth service connected: " + profile);
            }
            if(!mIsProfileReady) {
                mService = (BluetoothLeBroadcast) proxy;
                mIsProfileReady = true;
            if ((profile == BluetoothProfile.LE_AUDIO_BROADCAST) && !mIsBroadcastProfileReady) {
                mServiceBroadcast = (BluetoothLeBroadcast) proxy;
                mIsBroadcastProfileReady = true;
                registerServiceCallBack(mExecutor, mBroadcastCallback);
                List<BluetoothLeBroadcastMetadata> metadata = getAllBroadcastMetadata();
                if (!metadata.isEmpty()) {
                    updateBroadcastInfoFromBroadcastMetadata(metadata.get(0));
                }
                registerContentObserver();
            } else if ((profile == BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT)
                    && !mIsBroadcastAssistantProfileReady) {
                mIsBroadcastAssistantProfileReady = true;
                mServiceBroadcastAssistant = (BluetoothLeBroadcastAssistant) proxy;
                registerBroadcastAssistantCallback(mExecutor, mBroadcastAssistantCallback);
            }
        }

@@ -113,9 +124,17 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile {
            if (DEBUG) {
                Log.d(TAG, "Bluetooth service disconnected");
            }
            if(mIsProfileReady) {
                mIsProfileReady = false;
            if ((profile == BluetoothProfile.LE_AUDIO_BROADCAST) && mIsBroadcastProfileReady) {
                mIsBroadcastProfileReady = false;
                unregisterServiceCallBack(mBroadcastCallback);
            }
            if ((profile == BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT)
                    && mIsBroadcastAssistantProfileReady) {
                mIsBroadcastAssistantProfileReady = false;
                unregisterBroadcastAssistantCallback(mBroadcastAssistantCallback);
            }

            if (!mIsBroadcastAssistantProfileReady && !mIsBroadcastProfileReady) {
                unregisterContentObserver();
            }
        }
@@ -157,6 +176,8 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile {
                                "onBroadcastStopped(), reason = " + reason + ", broadcastId = "
                                        + broadcastId);
                    }

                    stopLocalSourceReceivers();
                    resetCacheInfo();
                }

@@ -196,6 +217,61 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile {
                }
            };

    private final BluetoothLeBroadcastAssistant.Callback mBroadcastAssistantCallback =
            new BluetoothLeBroadcastAssistant.Callback() {
                @Override
                public void onSourceAdded(@NonNull BluetoothDevice sink, int sourceId,
                        int reason) {}
                @Override
                public void onSearchStarted(int reason) {}

                @Override
                public void onSearchStartFailed(int reason) {}

                @Override
                public void onSearchStopped(int reason) {}

                @Override
                public void onSearchStopFailed(int reason) {}

                @Override
                public void onSourceFound(@NonNull BluetoothLeBroadcastMetadata source) {}

                @Override
                public void onSourceAddFailed(@NonNull BluetoothDevice sink,
                        @NonNull BluetoothLeBroadcastMetadata source, int reason) {}

                @Override
                public void onSourceModified(@NonNull BluetoothDevice sink, int sourceId,
                        int reason) {}

                @Override
                public void onSourceModifyFailed(@NonNull BluetoothDevice sink, int sourceId,
                        int reason) {}

                @Override
                public void onSourceRemoved(@NonNull BluetoothDevice sink, int sourceId,
                        int reason) {
                    if (DEBUG) {
                        Log.d(TAG, "onSourceRemoved(), sink = " + sink + ", reason = "
                                + reason + ", sourceId = " + sourceId);
                    }
                }

                @Override
                public void onSourceRemoveFailed(@NonNull BluetoothDevice sink, int sourceId,
                        int reason) {
                    if (DEBUG) {
                        Log.d(TAG, "onSourceRemoveFailed(), sink = " + sink + ", reason = "
                                + reason + ", sourceId = " + sourceId);
                    }
                }

                @Override
                public void onReceiveStateChanged(@NonNull BluetoothDevice sink, int sourceId,
                        @NonNull BluetoothLeBroadcastReceiveState state) {}
            };

    private class BroadcastSettingsObserver extends ContentObserver {
        BroadcastSettingsObserver(Handler h) {
            super(h);
@@ -219,6 +295,9 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile {
        // Before registering callback, the constructor should finish creating the all of variables.
        BluetoothAdapter.getDefaultAdapter()
                .getProfileProxy(context, mServiceListener, BluetoothProfile.LE_AUDIO_BROADCAST);
        BluetoothAdapter.getDefaultAdapter()
                .getProfileProxy(context, mServiceListener,
                BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT);
    }

    /**
@@ -227,7 +306,7 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile {
     */
    public void startBroadcast(String appSourceName, String language) {
        mNewAppSourceName = appSourceName;
        if (mService == null) {
        if (mServiceBroadcast == null) {
            Log.d(TAG, "The BluetoothLeBroadcast is null when starting the broadcast.");
            return;
        }
@@ -237,7 +316,7 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile {
                    "startBroadcast: language = " + language + " ,programInfo = " + programInfo);
        }
        buildContentMetadata(language, programInfo);
        mService.startBroadcast(mBluetoothLeAudioContentMetadata,
        mServiceBroadcast.startBroadcast(mBluetoothLeAudioContentMetadata,
                (mBroadcastCode != null && mBroadcastCode.length > 0) ? mBroadcastCode : null);
    }

@@ -341,13 +420,13 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile {
    }

    public BluetoothLeBroadcastMetadata getLatestBluetoothLeBroadcastMetadata() {
        if (mService == null) {
        if (mServiceBroadcast == null) {
            Log.d(TAG, "The BluetoothLeBroadcast is null");
            return null;
        }
        if (mBluetoothLeBroadcastMetadata == null) {
            final List<BluetoothLeBroadcastMetadata> metadataList =
                    mService.getAllBroadcastMetadata();
                    mServiceBroadcast.getAllBroadcastMetadata();
            mBluetoothLeBroadcastMetadata = metadataList.stream()
                    .filter(i -> i.getBroadcastId() == mBroadcastId)
                    .findFirst()
@@ -411,14 +490,14 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile {
     * corresponding callback {@link BluetoothLeBroadcast.Callback}.
     */
    public void stopBroadcast(int broadcastId) {
        if (mService == null) {
        if (mServiceBroadcast == null) {
            Log.d(TAG, "The BluetoothLeBroadcast is null when stopping the broadcast.");
            return;
        }
        if (DEBUG) {
            Log.d(TAG, "stopBroadcast()");
        }
        mService.stopBroadcast(broadcastId);
        mServiceBroadcast.stopBroadcast(broadcastId);
    }

    /**
@@ -426,7 +505,7 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile {
     * corresponding callback {@link BluetoothLeBroadcast.Callback}.
     */
    public void updateBroadcast(String appSourceName, String language) {
        if (mService == null) {
        if (mServiceBroadcast == null) {
            Log.d(TAG, "The BluetoothLeBroadcast is null when updating the broadcast.");
            return;
        }
@@ -437,26 +516,57 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile {
        }
        mNewAppSourceName = appSourceName;
        mBluetoothLeAudioContentMetadata = mBuilder.setProgramInfo(programInfo).build();
        mService.updateBroadcast(mBroadcastId, mBluetoothLeAudioContentMetadata);
        mServiceBroadcast.updateBroadcast(mBroadcastId, mBluetoothLeAudioContentMetadata);
    }

    public void registerServiceCallBack(@NonNull @CallbackExecutor Executor executor,
            @NonNull BluetoothLeBroadcast.Callback callback) {
        if (mService == null) {
        if (mServiceBroadcast == null) {
            Log.d(TAG, "The BluetoothLeBroadcast is null.");
            return;
        }

        mService.registerCallback(executor, callback);
        mServiceBroadcast.registerCallback(executor, callback);
    }

    /**
     * Register Broadcast Assistant Callbacks to track it's state and receivers
     *
     * @param executor Executor object for callback
     * @param callback Callback object to be registered
     */
    public void registerBroadcastAssistantCallback(@NonNull @CallbackExecutor Executor executor,
            @NonNull BluetoothLeBroadcastAssistant.Callback callback) {
        if (mServiceBroadcastAssistant == null) {
            Log.d(TAG, "The BluetoothLeBroadcastAssisntant is null.");
            return;
        }

        mServiceBroadcastAssistant.registerCallback(executor, callback);
    }

    public void unregisterServiceCallBack(@NonNull BluetoothLeBroadcast.Callback callback) {
        if (mService == null) {
        if (mServiceBroadcast == null) {
            Log.d(TAG, "The BluetoothLeBroadcast is null.");
            return;
        }

        mService.unregisterCallback(callback);
        mServiceBroadcast.unregisterCallback(callback);
    }

    /**
     * Unregister previousely registered Broadcast Assistant Callbacks
     *
     * @param callback Callback object to be unregistered
     */
    public void unregisterBroadcastAssistantCallback(
            @NonNull BluetoothLeBroadcastAssistant.Callback callback) {
        if (mServiceBroadcastAssistant == null) {
            Log.d(TAG, "The BluetoothLeBroadcastAssisntant is null.");
            return;
        }

        mServiceBroadcastAssistant.unregisterCallback(callback);
    }

    private void buildContentMetadata(String language, String programInfo) {
@@ -474,7 +584,7 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile {
    }

    public boolean isProfileReady() {
        return mIsProfileReady;
        return mIsBroadcastProfileReady;
    }

    @Override
@@ -494,40 +604,40 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile {
     * Not supported since LE Audio Broadcasts do not establish a connection.
     */
    public int getConnectionStatus(BluetoothDevice device) {
        if (mService == null) {
        if (mServiceBroadcast == null) {
            return BluetoothProfile.STATE_DISCONNECTED;
        }
        // LE Audio Broadcasts are not connection-oriented.
        return mService.getConnectionState(device);
        return mServiceBroadcast.getConnectionState(device);
    }

    /**
     * Not supported since LE Audio Broadcasts do not establish a connection.
     */
    public List<BluetoothDevice> getConnectedDevices() {
        if (mService == null) {
        if (mServiceBroadcast == null) {
            return new ArrayList<BluetoothDevice>(0);
        }
        // LE Audio Broadcasts are not connection-oriented.
        return mService.getConnectedDevices();
        return mServiceBroadcast.getConnectedDevices();
    }

    public @NonNull
    List<BluetoothLeBroadcastMetadata> getAllBroadcastMetadata() {
        if (mService == null) {
        if (mServiceBroadcast == null) {
            Log.d(TAG, "The BluetoothLeBroadcast is null.");
            return Collections.emptyList();
        }

        return mService.getAllBroadcastMetadata();
        return mServiceBroadcast.getAllBroadcastMetadata();
    }

    public boolean isEnabled(BluetoothDevice device) {
        if (mService == null) {
        if (mServiceBroadcast == null) {
            return false;
        }

        return !mService.getAllBroadcastMetadata().isEmpty();
        return !mServiceBroadcast.getAllBroadcastMetadata().isEmpty();
    }

    /**
@@ -571,12 +681,12 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile {
        if (DEBUG) {
            Log.d(TAG, "finalize()");
        }
        if (mService != null) {
        if (mServiceBroadcast != null) {
            try {
                BluetoothAdapter.getDefaultAdapter().closeProfileProxy(
                        BluetoothProfile.LE_AUDIO_BROADCAST,
                        mService);
                mService = null;
                        mServiceBroadcast);
                mServiceBroadcast = null;
            } catch (Throwable t) {
                Log.w(TAG, "Error cleaning up LeAudio proxy", t);
            }
@@ -626,4 +736,21 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile {
        }
        mContentResolver.unregisterContentObserver(mSettingsObserver);
    }

    private void stopLocalSourceReceivers() {
        if (DEBUG) {
            Log.d(TAG, "stopLocalSourceReceivers()");
        }
        for (BluetoothDevice device : mServiceBroadcastAssistant.getConnectedDevices()) {
            for (BluetoothLeBroadcastReceiveState receiveState :
                    mServiceBroadcastAssistant.getAllSources(device)) {
                /* Check if local/last broadcast is the synced one */
                int localBroadcastId = getLatestBroadcastId();
                if (receiveState.getBroadcastId() != localBroadcastId) continue;

                mServiceBroadcastAssistant.removeSource(device, receiveState.getSourceId());
            }
        }
    }

}
+17 −18
Original line number Diff line number Diff line
@@ -261,7 +261,10 @@ public class MediaOutputBroadcastDialog extends MediaOutputBaseDialog {
            mMediaOutputController.registerLeBroadcastAssistantServiceCallback(mExecutor,
                    mBroadcastAssistantCallback);
        }
        connectBroadcastWithActiveDevice();
        /* Add local source broadcast to connected capable devices that may be possible receivers
         * of stream.
         */
        startBroadcastWithConnectedDevices();
    }

    @Override
@@ -394,20 +397,15 @@ public class MediaOutputBroadcastDialog extends MediaOutputBaseDialog {
        }
    }

    void connectBroadcastWithActiveDevice() {
    void startBroadcastWithConnectedDevices() {
        //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();

        for (BluetoothDevice sink : mMediaOutputController.getConnectedBroadcastSinkDevices()) {
            Log.d(TAG, "The broadcastMetadata broadcastId: " + broadcastMetadata.getBroadcastId()
                    + ", the device: " + sink.getAnonymizedAddress());

@@ -416,10 +414,11 @@ public class MediaOutputBroadcastDialog extends MediaOutputBaseDialog {
                return;
            }
            if (!mMediaOutputController.addSourceIntoSinkDeviceWithBluetoothLeAssistant(sink,
                broadcastMetadata, /*isGroupOp=*/ true)) {
                    broadcastMetadata, /*isGroupOp=*/ false)) {
                Log.e(TAG, "Error: Source add failed");
            }
        }
    }

    private void updateBroadcastCodeVisibility() {
        mBroadcastCode.setTransformationMethod(
+20 −5
Original line number Diff line number Diff line
@@ -983,7 +983,7 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback,
        LocalBluetoothLeBroadcast broadcast =
                mLocalBluetoothManager.getProfileManager().getLeAudioBroadcastProfile();
        if (broadcast == null) {
            Log.d(TAG, "getBroadcastMetadata: LE Audio Broadcast is null");
            Log.d(TAG, "getLocalBroadcastMetadataQrCodeString: LE Audio Broadcast is null");
            return "";
        }
        final LocalBluetoothLeBroadcastMetadata metadata =
@@ -1087,11 +1087,23 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback,
        broadcast.unregisterServiceCallBack(callback);
    }

    List<BluetoothDevice> getConnectedBroadcastSinkDevices() {
        LocalBluetoothLeBroadcastAssistant assistant =
                mLocalBluetoothManager.getProfileManager().getLeAudioBroadcastAssistantProfile();
        if (assistant == null) {
            Log.d(TAG, "getConnectedBroadcastSinkDevices: The broadcast assistant profile is null");
            return null;
        }

        return assistant.getConnectedDevices();
    }

    boolean isThereAnyBroadcastSourceIntoSinkDevice(BluetoothDevice sink) {
        LocalBluetoothLeBroadcastAssistant assistant =
                mLocalBluetoothManager.getProfileManager().getLeAudioBroadcastAssistantProfile();
        if (assistant == null) {
            Log.d(TAG, "The broadcast assistant profile is null");
            Log.d(TAG, "isThereAnyBroadcastSourceIntoSinkDevice: The broadcast assistant profile "
                    + "is null");
            return false;
        }
        List<BluetoothLeBroadcastReceiveState> sourceList = assistant.getAllSources(sink);
@@ -1104,7 +1116,8 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback,
        LocalBluetoothLeBroadcastAssistant assistant =
                mLocalBluetoothManager.getProfileManager().getLeAudioBroadcastAssistantProfile();
        if (assistant == null) {
            Log.d(TAG, "The broadcast assistant profile is null");
            Log.d(TAG, "addSourceIntoSinkDeviceWithBluetoothLeAssistant: The broadcast assistant "
                    + "profile is null");
            return false;
        }
        assistant.addSource(sink, metadata, isGroupOp);
@@ -1117,7 +1130,8 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback,
        LocalBluetoothLeBroadcastAssistant assistant =
                mLocalBluetoothManager.getProfileManager().getLeAudioBroadcastAssistantProfile();
        if (assistant == null) {
            Log.d(TAG, "The broadcast assistant profile is null");
            Log.d(TAG, "registerLeBroadcastAssistantServiceCallback: The broadcast assistant "
                    + "profile is null");
            return;
        }
        Log.d(TAG, "Register LE broadcast assistant callback");
@@ -1129,7 +1143,8 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback,
        LocalBluetoothLeBroadcastAssistant assistant =
                mLocalBluetoothManager.getProfileManager().getLeAudioBroadcastAssistantProfile();
        if (assistant == null) {
            Log.d(TAG, "The broadcast assistant profile is null");
            Log.d(TAG, "unregisterLeBroadcastAssistantServiceCallback: The broadcast assistant "
                    + "profile is null");
            return;
        }
        Log.d(TAG, "Unregister LE broadcast assistant callback");
+46 −13

File changed.

Preview size limit exceeded, changes collapsed.