Loading android/app/src/com/android/bluetooth/bass_client/BassClientService.java +178 −59 Original line number Diff line number Diff line Loading @@ -124,6 +124,7 @@ public class BassClientService extends ProfileService { @VisibleForTesting static final int MESSAGE_SYNC_TIMEOUT = 1; @VisibleForTesting static final int MESSAGE_BIG_MONITOR_TIMEOUT = 2; @VisibleForTesting static final int MESSAGE_BROADCAST_MONITOR_TIMEOUT = 3; @VisibleForTesting static final int MESSAGE_SYNC_LOST_TIMEOUT = 4; /* 1 minute timeout for primary device reconnection in Private Broadcast case */ private static final int DIALING_OUT_TIMEOUT_MS = 60000; Loading @@ -137,6 +138,9 @@ public class BassClientService extends ProfileService { // 5 minutes timeout for monitoring broadcaster private static final Duration sBroadcasterMonitorTimeout = Duration.ofMinutes(5); // 5 seconds timeout for sync Lost notification private static final Duration sSyncLostTimeout = Duration.ofSeconds(5); private enum PauseType { HOST_INTENTIONAL, SINK_UNINTENTIONAL Loading Loading @@ -216,27 +220,65 @@ public class BassClientService extends ProfileService { clearAllSyncData(); break; } default: break; } } }; @VisibleForTesting public final TimeoutHandler mTimeoutHandler = new TimeoutHandler(); @VisibleForTesting public final class TimeoutHandler { private final Map<Integer, Handler> mHandlers = new HashMap<>(); @VisibleForTesting public Handler getOrCreateHandler(int broadcastId) { return mHandlers.computeIfAbsent( broadcastId, key -> new Handler(Looper.getMainLooper()) { @Override public void handleMessage(Message msg) { switch (msg.what) { case MESSAGE_SYNC_LOST_TIMEOUT: { log("MESSAGE_SYNC_LOST_TIMEOUT"); // fall through } case MESSAGE_BROADCAST_MONITOR_TIMEOUT: { log("MESSAGE_BROADCAST_MONITOR_TIMEOUT"); int broadcastId = msg.arg1; List<Integer> activeSyncedSrc = new ArrayList<>(getActiveSyncedSources()); if (activeSyncedSrc.contains( getSyncHandleForBroadcastId(broadcastId))) { break; } log("Notify broadcast source lost, broadcast id: " + broadcastId); // Clear from cache to make possible sync again // (only during active searching) synchronized (mSearchScanCallbackLock) { if (mSearchScanCallback != null) { mCachedBroadcasts.remove(broadcastId); } } log( "Notify broadcast source lost, broadcast" + " id: " + broadcastId); mCallbacks.notifySourceLost(broadcastId); if (!isSinkUnintentionalPauseType(broadcastId)) { break; } // fall through } case MESSAGE_BIG_MONITOR_TIMEOUT: { log("MESSAGE_BIG_MONITOR_TIMEOUT"); int broadcastId = msg.arg1; stopSourceReceivers(broadcastId); synchronized (mSearchScanCallbackLock) { // when searching is stopped then clear all sync data // when searching is stopped then clear all sync // data if (mSearchScanCallback == null) { clearAllSyncData(); } Loading @@ -246,8 +288,62 @@ public class BassClientService extends ProfileService { default: break; } Handler handler = getOrCreateHandler(broadcastId); if (!handler.hasMessagesOrCallbacks()) { mHandlers.remove(broadcastId); } } }); } void start(int broadcastId, int msg, Duration duration) { Handler handler = getOrCreateHandler(broadcastId); log( "Started timeout: " + ("broadcastId: " + broadcastId) + (", msg: " + msg) + (", duration: " + duration)); handler.sendEmptyMessageDelayed(msg, duration.toMillis()); } void stop(int broadcastId, int msg) { if (!mHandlers.containsKey(broadcastId)) { return; } Handler handler = getOrCreateHandler(broadcastId); handler.removeMessages(msg); if (!handler.hasMessagesOrCallbacks()) { mHandlers.remove(broadcastId); } } void stopAll() { for (Handler handler : mHandlers.values()) { handler.removeCallbacksAndMessages(null); } mHandlers.clear(); } void stopAll(int msg) { Iterator<Map.Entry<Integer, Handler>> iterator = mHandlers.entrySet().iterator(); while (iterator.hasNext()) { Map.Entry<Integer, Handler> entry = iterator.next(); Handler handler = entry.getValue(); handler.removeMessages(msg); if (!handler.hasMessagesOrCallbacks()) { iterator.remove(); } } } boolean isStarted(int broadcastId, int msg) { if (!mHandlers.containsKey(broadcastId)) { return false; } Handler handler = getOrCreateHandler(broadcastId); return handler.hasMessages(msg); } } }; public BassClientService(Context ctx) { super(ctx); Loading Loading @@ -710,6 +806,7 @@ public class BassClientService extends ProfileService { } mHandler.removeCallbacksAndMessages(null); mTimeoutHandler.stopAll(); setBassClientService(null); if (!leaudioBroadcastExtractPeriodicScannerFromStateMachine()) { Loading Loading @@ -1041,11 +1138,9 @@ public class BassClientService extends ProfileService { mPausedBroadcastIds.put(broadcastId, PauseType.SINK_UNINTENTIONAL); cacheSuspendingSources(broadcastId); mHandler.removeMessages(MESSAGE_BIG_MONITOR_TIMEOUT); Message newMsg = mHandler.obtainMessage(MESSAGE_BIG_MONITOR_TIMEOUT); newMsg.arg1 = broadcastId; log("Started MESSAGE_BIG_MONITOR_TIMEOUT"); mHandler.sendMessageDelayed(newMsg, sBigMonitorTimeout.toMillis()); mTimeoutHandler.stop(broadcastId, MESSAGE_BIG_MONITOR_TIMEOUT); mTimeoutHandler.start( broadcastId, MESSAGE_BIG_MONITOR_TIMEOUT, sBigMonitorTimeout); } } } else if (isEmptyBluetoothDevice(receiveState.getSourceDevice())) { Loading Loading @@ -1832,8 +1927,10 @@ public class BassClientService extends ProfileService { TAG, "Broadcast Source Found: Broadcast ID: " + broadcastId); if (broadcastId != BassConstants.INVALID_BROADCAST_ID && !mCachedBroadcasts.containsKey(broadcastId)) { if (broadcastId == BassConstants.INVALID_BROADCAST_ID) { return; } if (!mCachedBroadcasts.containsKey(broadcastId)) { log("selectBroadcastSource: broadcastId " + broadcastId); mCachedBroadcasts.put(broadcastId, result); if (leaudioBroadcastExtractPeriodicScannerFromStateMachine()) { Loading @@ -1848,6 +1945,14 @@ public class BassClientService extends ProfileService { } } } } else if (leaudioBroadcastResyncHelper() && mTimeoutHandler.isStarted( broadcastId, MESSAGE_SYNC_LOST_TIMEOUT)) { mTimeoutHandler.stop(broadcastId, MESSAGE_SYNC_LOST_TIMEOUT); mTimeoutHandler.start( broadcastId, MESSAGE_SYNC_LOST_TIMEOUT, sSyncLostTimeout); } } } Loading Loading @@ -1970,6 +2075,7 @@ public class BassClientService extends ProfileService { private void clearAllSyncData() { log("clearAllSyncData"); mTimeoutHandler.stopAll(MESSAGE_SYNC_LOST_TIMEOUT); mSourceSyncRequestsQueue.clear(); mSyncFailureCounter.clear(); mPendingSourcesToAdd.clear(); Loading Loading @@ -2047,7 +2153,7 @@ public class BassClientService extends ProfileService { } } } else { mHandler.removeMessages(MESSAGE_BROADCAST_MONITOR_TIMEOUT); mTimeoutHandler.stop(broadcastId, MESSAGE_BROADCAST_MONITOR_TIMEOUT); } // update valid sync handle in mPeriodicAdvCallbacksMap Loading Loading @@ -2100,11 +2206,12 @@ public class BassClientService extends ProfileService { mSyncFailureCounter.put(broadcastId, failsCounter); } if (isSinkUnintentionalPauseType(broadcastId)) { if (!mHandler.hasMessages(MESSAGE_BROADCAST_MONITOR_TIMEOUT)) { Message newMsg = mHandler.obtainMessage(MESSAGE_BROADCAST_MONITOR_TIMEOUT); newMsg.arg1 = broadcastId; log("Started MESSAGE_BROADCAST_MONITOR_TIMEOUT"); mHandler.sendMessageDelayed(newMsg, sBroadcasterMonitorTimeout.toMillis()); if (!mTimeoutHandler.isStarted( broadcastId, MESSAGE_BROADCAST_MONITOR_TIMEOUT)) { mTimeoutHandler.start( broadcastId, MESSAGE_BROADCAST_MONITOR_TIMEOUT, sBroadcasterMonitorTimeout); } addSelectSourceRequest(broadcastId, true); } else { Loading Loading @@ -2183,16 +2290,23 @@ public class BassClientService extends ProfileService { int failsCounter = mSyncFailureCounter.getOrDefault(broadcastId, 0) + 1; mSyncFailureCounter.put(broadcastId, failsCounter); } mTimeoutHandler.stop(broadcastId, MESSAGE_SYNC_LOST_TIMEOUT); if (isSinkUnintentionalPauseType(broadcastId)) { if (!mHandler.hasMessages(MESSAGE_BROADCAST_MONITOR_TIMEOUT)) { Message newMsg = mHandler.obtainMessage(MESSAGE_BROADCAST_MONITOR_TIMEOUT); newMsg.arg1 = broadcastId; log("Started MESSAGE_BROADCAST_MONITOR_TIMEOUT"); mHandler.sendMessageDelayed(newMsg, sBroadcasterMonitorTimeout.toMillis()); if (!mTimeoutHandler.isStarted( broadcastId, MESSAGE_BROADCAST_MONITOR_TIMEOUT)) { mTimeoutHandler.start( broadcastId, MESSAGE_BROADCAST_MONITOR_TIMEOUT, sBroadcasterMonitorTimeout); } addSelectSourceRequest(broadcastId, true); } else { // Clear from cache to make possible sync again (only during active searching) if (leaudioBroadcastResyncHelper()) { mTimeoutHandler.start( broadcastId, MESSAGE_SYNC_LOST_TIMEOUT, sSyncLostTimeout); } else { // Clear from cache to make possible sync again (only during active // searching) synchronized (mSearchScanCallbackLock) { if (mSearchScanCallback != null) { mCachedBroadcasts.remove(broadcastId); Loading @@ -2203,6 +2317,7 @@ public class BassClientService extends ProfileService { } } } } @Override public void onBigInfoAdvertisingReport(int syncHandle, boolean encrypted) { Loading Loading @@ -2480,7 +2595,7 @@ public class BassClientService extends ProfileService { + broadcastId + ", hasPriority: " + hasPriority); mTimeoutHandler.stop(broadcastId, MESSAGE_SYNC_LOST_TIMEOUT); ScanResult scanRes = getCachedBroadcast(broadcastId); if (scanRes != null) { ScanRecord scanRecord = scanRes.getScanRecord(); Loading Loading @@ -2572,9 +2687,11 @@ public class BassClientService extends ProfileService { cancelActiveSync(syncHandle); } else { Boolean canceledActiveSync = false; int broadcstIdToLostMonitoring = BassConstants.INVALID_BROADCAST_ID; for (int syncHandle : activeSyncedSrc) { if (!isAnyReceiverSyncedToBroadcast(getBroadcastIdForSyncHandle(syncHandle))) { canceledActiveSync = true; broadcstIdToLostMonitoring = getBroadcastIdForSyncHandle(syncHandle); cancelActiveSync(syncHandle); break; } Loading @@ -2582,8 +2699,11 @@ public class BassClientService extends ProfileService { if (!canceledActiveSync) { int syncHandle = activeSyncedSrc.get(0); // removing the 1st synced source before proceeding to add new broadcstIdToLostMonitoring = getBroadcastIdForSyncHandle(syncHandle); cancelActiveSync(syncHandle); } mTimeoutHandler.start( broadcstIdToLostMonitoring, MESSAGE_SYNC_LOST_TIMEOUT, sSyncLostTimeout); } } Loading Loading @@ -3447,14 +3567,13 @@ public class BassClientService extends ProfileService { return; } log("stopBigMonitoring"); mHandler.removeMessages(MESSAGE_BIG_MONITOR_TIMEOUT); mHandler.removeMessages(MESSAGE_BROADCAST_MONITOR_TIMEOUT); mPausedBroadcastSinks.clear(); Iterator<Integer> iterator = mPausedBroadcastIds.keySet().iterator(); while (iterator.hasNext()) { int pausedBroadcastId = iterator.next(); mTimeoutHandler.stop(pausedBroadcastId, MESSAGE_BIG_MONITOR_TIMEOUT); mTimeoutHandler.stop(pausedBroadcastId, MESSAGE_BROADCAST_MONITOR_TIMEOUT); iterator.remove(); synchronized (mSearchScanCallbackLock) { // when searching is stopped then stop active sync Loading @@ -3475,8 +3594,8 @@ public class BassClientService extends ProfileService { while (iterator.hasNext()) { int pausedBroadcastId = iterator.next(); if (!isAnyReceiverSyncedToBroadcast(pausedBroadcastId)) { mHandler.removeMessages(MESSAGE_BIG_MONITOR_TIMEOUT); mHandler.removeMessages(MESSAGE_BROADCAST_MONITOR_TIMEOUT); mTimeoutHandler.stop(pausedBroadcastId, MESSAGE_BIG_MONITOR_TIMEOUT); mTimeoutHandler.stop(pausedBroadcastId, MESSAGE_BROADCAST_MONITOR_TIMEOUT); iterator.remove(); synchronized (mSearchScanCallbackLock) { // when searching is stopped then stop active sync Loading @@ -3494,8 +3613,8 @@ public class BassClientService extends ProfileService { return; } log("stopBigMonitoring broadcastId: " + broadcastId + ", hostInitiated: " + hostInitiated); mHandler.removeMessages(MESSAGE_BIG_MONITOR_TIMEOUT); mHandler.removeMessages(MESSAGE_BROADCAST_MONITOR_TIMEOUT); mTimeoutHandler.stop(broadcastId, MESSAGE_BIG_MONITOR_TIMEOUT); mTimeoutHandler.stop(broadcastId, MESSAGE_BROADCAST_MONITOR_TIMEOUT); if (hostInitiated) { mPausedBroadcastIds.put(broadcastId, PauseType.HOST_INTENTIONAL); } else { Loading android/app/tests/unit/src/com/android/bluetooth/bass_client/BassClientServiceTest.java +270 −50 File changed.Preview size limit exceeded, changes collapsed. Show changes framework/java/android/bluetooth/BluetoothLeBroadcastAssistant.java +3 −2 Original line number Diff line number Diff line Loading @@ -316,6 +316,8 @@ public final class BluetoothLeBroadcastAssistant implements BluetoothProfile, Au * Callback invoked when a new Broadcast Source is found together with the {@link * BluetoothLeBroadcastMetadata}. * * <p>Broadcast is found when it is available for user to synchronize with it. * * @param source {@link BluetoothLeBroadcastMetadata} representing a Broadcast Source * @hide */ Loading Loading @@ -443,8 +445,7 @@ public final class BluetoothLeBroadcastAssistant implements BluetoothProfile, Au /** * Callback invoked when the Broadcast Source is lost together with source broadcast id. * * <p>This callback is to notify source lost due to periodic advertising sync lost. Callback * client can know that the source notified by {@link * <p>Callback client can know that the source notified by {@link * Callback#onSourceFound(BluetoothLeBroadcastMetadata)} before is not available any more * after this callback. * Loading Loading
android/app/src/com/android/bluetooth/bass_client/BassClientService.java +178 −59 Original line number Diff line number Diff line Loading @@ -124,6 +124,7 @@ public class BassClientService extends ProfileService { @VisibleForTesting static final int MESSAGE_SYNC_TIMEOUT = 1; @VisibleForTesting static final int MESSAGE_BIG_MONITOR_TIMEOUT = 2; @VisibleForTesting static final int MESSAGE_BROADCAST_MONITOR_TIMEOUT = 3; @VisibleForTesting static final int MESSAGE_SYNC_LOST_TIMEOUT = 4; /* 1 minute timeout for primary device reconnection in Private Broadcast case */ private static final int DIALING_OUT_TIMEOUT_MS = 60000; Loading @@ -137,6 +138,9 @@ public class BassClientService extends ProfileService { // 5 minutes timeout for monitoring broadcaster private static final Duration sBroadcasterMonitorTimeout = Duration.ofMinutes(5); // 5 seconds timeout for sync Lost notification private static final Duration sSyncLostTimeout = Duration.ofSeconds(5); private enum PauseType { HOST_INTENTIONAL, SINK_UNINTENTIONAL Loading Loading @@ -216,27 +220,65 @@ public class BassClientService extends ProfileService { clearAllSyncData(); break; } default: break; } } }; @VisibleForTesting public final TimeoutHandler mTimeoutHandler = new TimeoutHandler(); @VisibleForTesting public final class TimeoutHandler { private final Map<Integer, Handler> mHandlers = new HashMap<>(); @VisibleForTesting public Handler getOrCreateHandler(int broadcastId) { return mHandlers.computeIfAbsent( broadcastId, key -> new Handler(Looper.getMainLooper()) { @Override public void handleMessage(Message msg) { switch (msg.what) { case MESSAGE_SYNC_LOST_TIMEOUT: { log("MESSAGE_SYNC_LOST_TIMEOUT"); // fall through } case MESSAGE_BROADCAST_MONITOR_TIMEOUT: { log("MESSAGE_BROADCAST_MONITOR_TIMEOUT"); int broadcastId = msg.arg1; List<Integer> activeSyncedSrc = new ArrayList<>(getActiveSyncedSources()); if (activeSyncedSrc.contains( getSyncHandleForBroadcastId(broadcastId))) { break; } log("Notify broadcast source lost, broadcast id: " + broadcastId); // Clear from cache to make possible sync again // (only during active searching) synchronized (mSearchScanCallbackLock) { if (mSearchScanCallback != null) { mCachedBroadcasts.remove(broadcastId); } } log( "Notify broadcast source lost, broadcast" + " id: " + broadcastId); mCallbacks.notifySourceLost(broadcastId); if (!isSinkUnintentionalPauseType(broadcastId)) { break; } // fall through } case MESSAGE_BIG_MONITOR_TIMEOUT: { log("MESSAGE_BIG_MONITOR_TIMEOUT"); int broadcastId = msg.arg1; stopSourceReceivers(broadcastId); synchronized (mSearchScanCallbackLock) { // when searching is stopped then clear all sync data // when searching is stopped then clear all sync // data if (mSearchScanCallback == null) { clearAllSyncData(); } Loading @@ -246,8 +288,62 @@ public class BassClientService extends ProfileService { default: break; } Handler handler = getOrCreateHandler(broadcastId); if (!handler.hasMessagesOrCallbacks()) { mHandlers.remove(broadcastId); } } }); } void start(int broadcastId, int msg, Duration duration) { Handler handler = getOrCreateHandler(broadcastId); log( "Started timeout: " + ("broadcastId: " + broadcastId) + (", msg: " + msg) + (", duration: " + duration)); handler.sendEmptyMessageDelayed(msg, duration.toMillis()); } void stop(int broadcastId, int msg) { if (!mHandlers.containsKey(broadcastId)) { return; } Handler handler = getOrCreateHandler(broadcastId); handler.removeMessages(msg); if (!handler.hasMessagesOrCallbacks()) { mHandlers.remove(broadcastId); } } void stopAll() { for (Handler handler : mHandlers.values()) { handler.removeCallbacksAndMessages(null); } mHandlers.clear(); } void stopAll(int msg) { Iterator<Map.Entry<Integer, Handler>> iterator = mHandlers.entrySet().iterator(); while (iterator.hasNext()) { Map.Entry<Integer, Handler> entry = iterator.next(); Handler handler = entry.getValue(); handler.removeMessages(msg); if (!handler.hasMessagesOrCallbacks()) { iterator.remove(); } } } boolean isStarted(int broadcastId, int msg) { if (!mHandlers.containsKey(broadcastId)) { return false; } Handler handler = getOrCreateHandler(broadcastId); return handler.hasMessages(msg); } } }; public BassClientService(Context ctx) { super(ctx); Loading Loading @@ -710,6 +806,7 @@ public class BassClientService extends ProfileService { } mHandler.removeCallbacksAndMessages(null); mTimeoutHandler.stopAll(); setBassClientService(null); if (!leaudioBroadcastExtractPeriodicScannerFromStateMachine()) { Loading Loading @@ -1041,11 +1138,9 @@ public class BassClientService extends ProfileService { mPausedBroadcastIds.put(broadcastId, PauseType.SINK_UNINTENTIONAL); cacheSuspendingSources(broadcastId); mHandler.removeMessages(MESSAGE_BIG_MONITOR_TIMEOUT); Message newMsg = mHandler.obtainMessage(MESSAGE_BIG_MONITOR_TIMEOUT); newMsg.arg1 = broadcastId; log("Started MESSAGE_BIG_MONITOR_TIMEOUT"); mHandler.sendMessageDelayed(newMsg, sBigMonitorTimeout.toMillis()); mTimeoutHandler.stop(broadcastId, MESSAGE_BIG_MONITOR_TIMEOUT); mTimeoutHandler.start( broadcastId, MESSAGE_BIG_MONITOR_TIMEOUT, sBigMonitorTimeout); } } } else if (isEmptyBluetoothDevice(receiveState.getSourceDevice())) { Loading Loading @@ -1832,8 +1927,10 @@ public class BassClientService extends ProfileService { TAG, "Broadcast Source Found: Broadcast ID: " + broadcastId); if (broadcastId != BassConstants.INVALID_BROADCAST_ID && !mCachedBroadcasts.containsKey(broadcastId)) { if (broadcastId == BassConstants.INVALID_BROADCAST_ID) { return; } if (!mCachedBroadcasts.containsKey(broadcastId)) { log("selectBroadcastSource: broadcastId " + broadcastId); mCachedBroadcasts.put(broadcastId, result); if (leaudioBroadcastExtractPeriodicScannerFromStateMachine()) { Loading @@ -1848,6 +1945,14 @@ public class BassClientService extends ProfileService { } } } } else if (leaudioBroadcastResyncHelper() && mTimeoutHandler.isStarted( broadcastId, MESSAGE_SYNC_LOST_TIMEOUT)) { mTimeoutHandler.stop(broadcastId, MESSAGE_SYNC_LOST_TIMEOUT); mTimeoutHandler.start( broadcastId, MESSAGE_SYNC_LOST_TIMEOUT, sSyncLostTimeout); } } } Loading Loading @@ -1970,6 +2075,7 @@ public class BassClientService extends ProfileService { private void clearAllSyncData() { log("clearAllSyncData"); mTimeoutHandler.stopAll(MESSAGE_SYNC_LOST_TIMEOUT); mSourceSyncRequestsQueue.clear(); mSyncFailureCounter.clear(); mPendingSourcesToAdd.clear(); Loading Loading @@ -2047,7 +2153,7 @@ public class BassClientService extends ProfileService { } } } else { mHandler.removeMessages(MESSAGE_BROADCAST_MONITOR_TIMEOUT); mTimeoutHandler.stop(broadcastId, MESSAGE_BROADCAST_MONITOR_TIMEOUT); } // update valid sync handle in mPeriodicAdvCallbacksMap Loading Loading @@ -2100,11 +2206,12 @@ public class BassClientService extends ProfileService { mSyncFailureCounter.put(broadcastId, failsCounter); } if (isSinkUnintentionalPauseType(broadcastId)) { if (!mHandler.hasMessages(MESSAGE_BROADCAST_MONITOR_TIMEOUT)) { Message newMsg = mHandler.obtainMessage(MESSAGE_BROADCAST_MONITOR_TIMEOUT); newMsg.arg1 = broadcastId; log("Started MESSAGE_BROADCAST_MONITOR_TIMEOUT"); mHandler.sendMessageDelayed(newMsg, sBroadcasterMonitorTimeout.toMillis()); if (!mTimeoutHandler.isStarted( broadcastId, MESSAGE_BROADCAST_MONITOR_TIMEOUT)) { mTimeoutHandler.start( broadcastId, MESSAGE_BROADCAST_MONITOR_TIMEOUT, sBroadcasterMonitorTimeout); } addSelectSourceRequest(broadcastId, true); } else { Loading Loading @@ -2183,16 +2290,23 @@ public class BassClientService extends ProfileService { int failsCounter = mSyncFailureCounter.getOrDefault(broadcastId, 0) + 1; mSyncFailureCounter.put(broadcastId, failsCounter); } mTimeoutHandler.stop(broadcastId, MESSAGE_SYNC_LOST_TIMEOUT); if (isSinkUnintentionalPauseType(broadcastId)) { if (!mHandler.hasMessages(MESSAGE_BROADCAST_MONITOR_TIMEOUT)) { Message newMsg = mHandler.obtainMessage(MESSAGE_BROADCAST_MONITOR_TIMEOUT); newMsg.arg1 = broadcastId; log("Started MESSAGE_BROADCAST_MONITOR_TIMEOUT"); mHandler.sendMessageDelayed(newMsg, sBroadcasterMonitorTimeout.toMillis()); if (!mTimeoutHandler.isStarted( broadcastId, MESSAGE_BROADCAST_MONITOR_TIMEOUT)) { mTimeoutHandler.start( broadcastId, MESSAGE_BROADCAST_MONITOR_TIMEOUT, sBroadcasterMonitorTimeout); } addSelectSourceRequest(broadcastId, true); } else { // Clear from cache to make possible sync again (only during active searching) if (leaudioBroadcastResyncHelper()) { mTimeoutHandler.start( broadcastId, MESSAGE_SYNC_LOST_TIMEOUT, sSyncLostTimeout); } else { // Clear from cache to make possible sync again (only during active // searching) synchronized (mSearchScanCallbackLock) { if (mSearchScanCallback != null) { mCachedBroadcasts.remove(broadcastId); Loading @@ -2203,6 +2317,7 @@ public class BassClientService extends ProfileService { } } } } @Override public void onBigInfoAdvertisingReport(int syncHandle, boolean encrypted) { Loading Loading @@ -2480,7 +2595,7 @@ public class BassClientService extends ProfileService { + broadcastId + ", hasPriority: " + hasPriority); mTimeoutHandler.stop(broadcastId, MESSAGE_SYNC_LOST_TIMEOUT); ScanResult scanRes = getCachedBroadcast(broadcastId); if (scanRes != null) { ScanRecord scanRecord = scanRes.getScanRecord(); Loading Loading @@ -2572,9 +2687,11 @@ public class BassClientService extends ProfileService { cancelActiveSync(syncHandle); } else { Boolean canceledActiveSync = false; int broadcstIdToLostMonitoring = BassConstants.INVALID_BROADCAST_ID; for (int syncHandle : activeSyncedSrc) { if (!isAnyReceiverSyncedToBroadcast(getBroadcastIdForSyncHandle(syncHandle))) { canceledActiveSync = true; broadcstIdToLostMonitoring = getBroadcastIdForSyncHandle(syncHandle); cancelActiveSync(syncHandle); break; } Loading @@ -2582,8 +2699,11 @@ public class BassClientService extends ProfileService { if (!canceledActiveSync) { int syncHandle = activeSyncedSrc.get(0); // removing the 1st synced source before proceeding to add new broadcstIdToLostMonitoring = getBroadcastIdForSyncHandle(syncHandle); cancelActiveSync(syncHandle); } mTimeoutHandler.start( broadcstIdToLostMonitoring, MESSAGE_SYNC_LOST_TIMEOUT, sSyncLostTimeout); } } Loading Loading @@ -3447,14 +3567,13 @@ public class BassClientService extends ProfileService { return; } log("stopBigMonitoring"); mHandler.removeMessages(MESSAGE_BIG_MONITOR_TIMEOUT); mHandler.removeMessages(MESSAGE_BROADCAST_MONITOR_TIMEOUT); mPausedBroadcastSinks.clear(); Iterator<Integer> iterator = mPausedBroadcastIds.keySet().iterator(); while (iterator.hasNext()) { int pausedBroadcastId = iterator.next(); mTimeoutHandler.stop(pausedBroadcastId, MESSAGE_BIG_MONITOR_TIMEOUT); mTimeoutHandler.stop(pausedBroadcastId, MESSAGE_BROADCAST_MONITOR_TIMEOUT); iterator.remove(); synchronized (mSearchScanCallbackLock) { // when searching is stopped then stop active sync Loading @@ -3475,8 +3594,8 @@ public class BassClientService extends ProfileService { while (iterator.hasNext()) { int pausedBroadcastId = iterator.next(); if (!isAnyReceiverSyncedToBroadcast(pausedBroadcastId)) { mHandler.removeMessages(MESSAGE_BIG_MONITOR_TIMEOUT); mHandler.removeMessages(MESSAGE_BROADCAST_MONITOR_TIMEOUT); mTimeoutHandler.stop(pausedBroadcastId, MESSAGE_BIG_MONITOR_TIMEOUT); mTimeoutHandler.stop(pausedBroadcastId, MESSAGE_BROADCAST_MONITOR_TIMEOUT); iterator.remove(); synchronized (mSearchScanCallbackLock) { // when searching is stopped then stop active sync Loading @@ -3494,8 +3613,8 @@ public class BassClientService extends ProfileService { return; } log("stopBigMonitoring broadcastId: " + broadcastId + ", hostInitiated: " + hostInitiated); mHandler.removeMessages(MESSAGE_BIG_MONITOR_TIMEOUT); mHandler.removeMessages(MESSAGE_BROADCAST_MONITOR_TIMEOUT); mTimeoutHandler.stop(broadcastId, MESSAGE_BIG_MONITOR_TIMEOUT); mTimeoutHandler.stop(broadcastId, MESSAGE_BROADCAST_MONITOR_TIMEOUT); if (hostInitiated) { mPausedBroadcastIds.put(broadcastId, PauseType.HOST_INTENTIONAL); } else { Loading
android/app/tests/unit/src/com/android/bluetooth/bass_client/BassClientServiceTest.java +270 −50 File changed.Preview size limit exceeded, changes collapsed. Show changes
framework/java/android/bluetooth/BluetoothLeBroadcastAssistant.java +3 −2 Original line number Diff line number Diff line Loading @@ -316,6 +316,8 @@ public final class BluetoothLeBroadcastAssistant implements BluetoothProfile, Au * Callback invoked when a new Broadcast Source is found together with the {@link * BluetoothLeBroadcastMetadata}. * * <p>Broadcast is found when it is available for user to synchronize with it. * * @param source {@link BluetoothLeBroadcastMetadata} representing a Broadcast Source * @hide */ Loading Loading @@ -443,8 +445,7 @@ public final class BluetoothLeBroadcastAssistant implements BluetoothProfile, Au /** * Callback invoked when the Broadcast Source is lost together with source broadcast id. * * <p>This callback is to notify source lost due to periodic advertising sync lost. Callback * client can know that the source notified by {@link * <p>Callback client can know that the source notified by {@link * Callback#onSourceFound(BluetoothLeBroadcastMetadata)} before is not available any more * after this callback. * Loading