Merge "LocalBluetoothLeBroadcast: Remove sources on broadcast stop" into udc-qpr-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
ae1d766a9a
@@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user