Loading OWNERS_build +0 −1 Original line number Original line Diff line number Diff line licorne@google.com wescande@google.com wescande@google.com OWNERS_hearingaid +0 −1 Original line number Original line Diff line number Diff line charliebout@google.com charliebout@google.com licorne@google.com android/app/src/com/android/bluetooth/bass_client/BassClientService.java +69 −31 Original line number Original line Diff line number Diff line Loading @@ -92,7 +92,6 @@ import java.util.Deque; import java.util.HashMap; import java.util.HashMap; import java.util.HashSet; import java.util.HashSet; import java.util.Iterator; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.List; import java.util.Map; import java.util.Map; import java.util.Objects; import java.util.Objects; Loading Loading @@ -148,7 +147,7 @@ public class BassClientService extends ProfileService { private final Map<BluetoothDevice, List<Integer>> mActiveSourceMap = new ConcurrentHashMap<>(); private final Map<BluetoothDevice, List<Integer>> mActiveSourceMap = new ConcurrentHashMap<>(); private final Map<BluetoothDevice, BluetoothLeBroadcastMetadata> mBroadcastMetadataMap = private final Map<BluetoothDevice, BluetoothLeBroadcastMetadata> mBroadcastMetadataMap = new ConcurrentHashMap<>(); new ConcurrentHashMap<>(); private final LinkedList<BluetoothDevice> mPausedBroadcastSinks = new LinkedList<>(); private final HashSet<BluetoothDevice> mPausedBroadcastSinks = new HashSet<>(); private final Deque<AddSourceData> mPendingAddSources = new ArrayDeque<>(); private final Deque<AddSourceData> mPendingAddSources = new ArrayDeque<>(); private final Map<Integer, HashSet<BluetoothDevice>> mLocalBroadcastReceivers = private final Map<Integer, HashSet<BluetoothDevice>> mLocalBroadcastReceivers = new ConcurrentHashMap<>(); new ConcurrentHashMap<>(); Loading Loading @@ -704,6 +703,7 @@ public class BassClientService extends ProfileService { mLocalBroadcastReceivers.clear(); mLocalBroadcastReceivers.clear(); mPendingGroupOp.clear(); mPendingGroupOp.clear(); mBroadcastMetadataMap.clear(); mBroadcastMetadataMap.clear(); mPausedBroadcastSinks.clear(); } } } } Loading Loading @@ -1394,6 +1394,7 @@ public class BassClientService extends ProfileService { // Check if the device is disconnected - if unbond, remove the state machine // Check if the device is disconnected - if unbond, remove the state machine if (toState == BluetoothProfile.STATE_DISCONNECTED) { if (toState == BluetoothProfile.STATE_DISCONNECTED) { mPendingGroupOp.remove(device); mPendingGroupOp.remove(device); mPausedBroadcastSinks.remove(device); int bondState = mAdapterService.getBondState(device); int bondState = mAdapterService.getBondState(device); if (bondState == BluetoothDevice.BOND_NONE) { if (bondState == BluetoothDevice.BOND_NONE) { Loading Loading @@ -1892,9 +1893,12 @@ public class BassClientService extends ProfileService { int skip, int skip, int timeout, int timeout, int status) { int status) { int broadcastId = getBroadcastIdForSyncHandle(BassConstants.INVALID_SYNC_HANDLE); log( log( "onSyncEstablished syncHandle: " "onSyncEstablished syncHandle: " + syncHandle + syncHandle + ", broadcastId: " + broadcastId + ", device: " + ", device: " + device + device + ", advertisingSid: " + ", advertisingSid: " Loading Loading @@ -1944,9 +1948,7 @@ public class BassClientService extends ProfileService { Iterator<AddSourceData> iterator = mPendingSourcesToAdd.iterator(); Iterator<AddSourceData> iterator = mPendingSourcesToAdd.iterator(); while (iterator.hasNext()) { while (iterator.hasNext()) { AddSourceData pendingSourcesToAdd = iterator.next(); AddSourceData pendingSourcesToAdd = iterator.next(); BluetoothDevice sourceDevice = if (pendingSourcesToAdd.mSourceMetadata.getBroadcastId() == broadcastId) { pendingSourcesToAdd.mSourceMetadata.getSourceDevice(); if (sourceDevice.equals(device)) { addSource( addSource( pendingSourcesToAdd.mSink, pendingSourcesToAdd.mSink, pendingSourcesToAdd.mSourceMetadata, pendingSourcesToAdd.mSourceMetadata, Loading @@ -1957,9 +1959,31 @@ public class BassClientService extends ProfileService { } } } else { } else { // remove failed sync handle // remove failed sync handle int broadcastId = getBroadcastIdForSyncHandle(BassConstants.INVALID_SYNC_HANDLE); log("onSyncEstablished failed for broadcast id: " + broadcastId); log("onSyncEstablished failed for broadcast id: " + broadcastId); boolean notifiedOfLost = false; synchronized (mPendingSourcesToAdd) { Iterator<AddSourceData> iterator = mPendingSourcesToAdd.iterator(); while (iterator.hasNext()) { AddSourceData pendingSourcesToAdd = iterator.next(); if (pendingSourcesToAdd.mSourceMetadata.getBroadcastId() == broadcastId) { if (!notifiedOfLost) { notifiedOfLost = true; mCallbacks.notifySourceLost(broadcastId); } mCallbacks.notifySourceAddFailed( pendingSourcesToAdd.mSink, pendingSourcesToAdd.mSourceMetadata, BluetoothStatusCodes.ERROR_LOCAL_NOT_ENOUGH_RESOURCES); iterator.remove(); } } } synchronized (mSearchScanCallbackLock) { // Clear from cache to make possible sync again (only during active searching) if (mSearchScanCallback != null) { mCachedBroadcasts.remove(broadcastId); mCachedBroadcasts.remove(broadcastId); } } mPeriodicAdvCallbacksMap.remove(BassConstants.INVALID_SYNC_HANDLE); mPeriodicAdvCallbacksMap.remove(BassConstants.INVALID_SYNC_HANDLE); } } handleSelectSourceRequest(); handleSelectSourceRequest(); Loading Loading @@ -2029,9 +2053,13 @@ public class BassClientService extends ProfileService { } } } } clearAllDataForSyncHandle(syncHandle); clearAllDataForSyncHandle(syncHandle); // Clear from cache to make possible sync again // Clear from cache to make possible sync again (only during active searching) synchronized (mSearchScanCallbackLock) { if (mSearchScanCallback != null) { mCachedBroadcasts.remove(broadcastId); mCachedBroadcasts.remove(broadcastId); } } } } @Override @Override public void onBigInfoAdvertisingReport(int syncHandle, boolean encrypted) { public void onBigInfoAdvertisingReport(int syncHandle, boolean encrypted) { Loading Loading @@ -2533,11 +2561,21 @@ public class BassClientService extends ProfileService { if (broadcastId != BassConstants.INVALID_BROADCAST_ID if (broadcastId != BassConstants.INVALID_BROADCAST_ID && getCachedBroadcast(broadcastId) != null) { && getCachedBroadcast(broadcastId) != null) { // If the source has been synced before, try to re-sync // If the source has been synced before, try to re-sync // with the source by previously cached scan result // with the source by previously cached scan result. addSelectSourceRequest(getCachedBroadcast(broadcastId), true); // Check if not added already boolean alreadyAdded = false; synchronized (mPendingSourcesToAdd) { synchronized (mPendingSourcesToAdd) { for (AddSourceData pendingSourcesToAdd : mPendingSourcesToAdd) { if (pendingSourcesToAdd.mSourceMetadata.getBroadcastId() == broadcastId) { alreadyAdded = true; } } mPendingSourcesToAdd.add( mPendingSourcesToAdd.add( new AddSourceData(sink, sourceMetadata, isGroupOp)); new AddSourceData(sink, sourceMetadata, isGroupOp)); if (!alreadyAdded) { addSelectSourceRequest(getCachedBroadcast(broadcastId), true); } } } } else { } else { log("AddSource: broadcast not cached or invalid, broadcastId: " + broadcastId); log("AddSource: broadcast not cached or invalid, broadcastId: " + broadcastId); Loading Loading @@ -2958,15 +2996,14 @@ public class BassClientService extends ProfileService { private void stopSourceReceivers(int broadcastId, boolean store) { private void stopSourceReceivers(int broadcastId, boolean store) { Log.d(TAG, "stopSourceReceivers(), broadcastId: " + broadcastId + ", store: " + store); Log.d(TAG, "stopSourceReceivers(), broadcastId: " + broadcastId + ", store: " + store); if (store && !mPausedBroadcastSinks.isEmpty()) { Log.w(TAG, "stopSourceReceivers(), paused broadcast sinks are replaced"); sEventLogger.logd(TAG, "Clear broadcast sinks paused cache"); mPausedBroadcastSinks.clear(); } Map<BluetoothDevice, Integer> sourcesToRemove = new HashMap<>(); Map<BluetoothDevice, Integer> sourcesToRemove = new HashMap<>(); for (BluetoothDevice device : getConnectedDevices()) { for (BluetoothDevice device : getConnectedDevices()) { if (mPausedBroadcastSinks.contains(device)) { // Skip this device if it has been paused continue; } for (BluetoothLeBroadcastReceiveState receiveState : getAllSources(device)) { for (BluetoothLeBroadcastReceiveState receiveState : getAllSources(device)) { /* Check if local/last broadcast is the synced one. Invalid broadcast ID means /* Check if local/last broadcast is the synced one. Invalid broadcast ID means * that all receivers should be considered. * that all receivers should be considered. Loading @@ -2976,7 +3013,7 @@ public class BassClientService extends ProfileService { continue; continue; } } if (store && !mPausedBroadcastSinks.contains(device)) { if (store) { sEventLogger.logd(TAG, "Add broadcast sink to paused cache: " + device); sEventLogger.logd(TAG, "Add broadcast sink to paused cache: " + device); mPausedBroadcastSinks.add(device); mPausedBroadcastSinks.add(device); } } Loading Loading @@ -3130,18 +3167,12 @@ public class BassClientService extends ProfileService { } } } } /** Cache suspending sources */ /** Cache suspending sources when broadcast paused */ public void cacheSuspendingSources(int broadcastId) { public void cacheSuspendingSources(int broadcastId) { sEventLogger.logd(TAG, "Cache suspending sources: " + broadcastId); sEventLogger.logd(TAG, "Cache suspending sources: " + broadcastId); List<Pair<BluetoothLeBroadcastReceiveState, BluetoothDevice>> sourcesToCache = List<Pair<BluetoothLeBroadcastReceiveState, BluetoothDevice>> sourcesToCache = getReceiveStateDevicePairs(broadcastId); getReceiveStateDevicePairs(broadcastId); if (!mPausedBroadcastSinks.isEmpty()) { Log.w(TAG, "cacheSuspendingSources(), paused broadcast sinks are replaced"); sEventLogger.logd(TAG, "Clear broadcast sinks paused cache"); mPausedBroadcastSinks.clear(); } for (Pair<BluetoothLeBroadcastReceiveState, BluetoothDevice> pair : sourcesToCache) { for (Pair<BluetoothLeBroadcastReceiveState, BluetoothDevice> pair : sourcesToCache) { mPausedBroadcastSinks.add(pair.second); mPausedBroadcastSinks.add(pair.second); } } Loading Loading @@ -3173,8 +3204,9 @@ public class BassClientService extends ProfileService { public void resumeReceiversSourceSynchronization() { public void resumeReceiversSourceSynchronization() { sEventLogger.logd(TAG, "Resume receivers source synchronization"); sEventLogger.logd(TAG, "Resume receivers source synchronization"); while (!mPausedBroadcastSinks.isEmpty()) { Iterator<BluetoothDevice> iterator = mPausedBroadcastSinks.iterator(); BluetoothDevice sink = mPausedBroadcastSinks.remove(); while (iterator.hasNext()) { BluetoothDevice sink = iterator.next(); sEventLogger.logd(TAG, "Remove broadcast sink from paused cache: " + sink); sEventLogger.logd(TAG, "Remove broadcast sink from paused cache: " + sink); BluetoothLeBroadcastMetadata metadata = mBroadcastMetadataMap.get(sink); BluetoothLeBroadcastMetadata metadata = mBroadcastMetadataMap.get(sink); Loading @@ -3182,9 +3214,11 @@ public class BassClientService extends ProfileService { if (metadata == null) { if (metadata == null) { Log.w( Log.w( TAG, TAG, "resumeReceiversSourceSynchronization: failed to get metadata to resume" "resumeReceiversSourceSynchronization: failed to get metadata to" + " sink: " + " resume sink: " + sink); + sink); // remove the device from mPausedBroadcastSinks iterator.remove(); continue; continue; } } Loading @@ -3207,6 +3241,8 @@ public class BassClientService extends ProfileService { if (statusCode != BluetoothStatusCodes.SUCCESS) { if (statusCode != BluetoothStatusCodes.SUCCESS) { mCallbacks.notifySourceModifyFailed(sink, sourceId, statusCode); mCallbacks.notifySourceModifyFailed(sink, sourceId, statusCode); // remove the device from mPausedBroadcastSinks iterator.remove(); continue; continue; } } Loading Loading @@ -3238,11 +3274,13 @@ public class BassClientService extends ProfileService { } else { } else { Log.w( Log.w( TAG, TAG, "resumeReceiversSourceSynchronization: failed to get metadata to resume" "resumeReceiversSourceSynchronization: failed to get metadata to" + " sink: " + " resume sink: " + sink); + sink); } } } } // remove the device from mPausedBroadcastSinks iterator.remove(); } } } } Loading android/app/src/com/android/bluetooth/le_scan/TransitionalScanHelper.java +1 −4 Original line number Original line Diff line number Diff line Loading @@ -78,16 +78,13 @@ import java.util.function.Predicate; /** /** * A helper class which contains all scan related functions extracted from {@link * A helper class which contains all scan related functions extracted from {@link * com.android.bluetooth.gatt.GattService}. The purpose of this class is to preserve scan * com.android.bluetooth.gatt.GattService}. The purpose of this class is to preserve scan * functionality within GattService and provide the same functionality in a new scan dedicated * functionality within GattService and provide the same functionality in {@link ScanController}. * {@link com.android.bluetooth.btservice.ProfileService} when introduced. */ */ public class TransitionalScanHelper { public class TransitionalScanHelper { private static final String TAG = GattServiceConfig.TAG_PREFIX + "ScanHelper"; private static final String TAG = GattServiceConfig.TAG_PREFIX + "ScanHelper"; // Batch scan related constants. // Batch scan related constants. private static final int TRUNCATED_RESULT_SIZE = 11; private static final int TRUNCATED_RESULT_SIZE = 11; static final int SCAN_FILTER_ENABLED = 1; static final int SCAN_FILTER_MODIFIED = 2; /** The default floor value for LE batch scan report delays greater than 0 */ /** The default floor value for LE batch scan report delays greater than 0 */ @VisibleForTesting static final long DEFAULT_REPORT_DELAY_FLOOR = 5000; @VisibleForTesting static final long DEFAULT_REPORT_DELAY_FLOOR = 5000; Loading android/app/src/com/android/bluetooth/notification/NotificationHelperService.java +22 −17 Original line number Original line Diff line number Diff line Loading @@ -160,16 +160,19 @@ public class NotificationHelperService extends Service { } } private boolean shouldDisplayNotification(String countKey) { private boolean shouldDisplayNotification(String countKey) { final LocalDateTime now = LocalDateTime.now(ZoneId.systemDefault()); final String dateKey = countKey + "_date"; final String dateKey = countKey + "_date"; final String date = Settings.Secure.getString(getContentResolver(), dateKey); final int countShown = Settings.Secure.getInt(getContentResolver(), countKey, 0); final int countShown = Settings.Secure.getInt(getContentResolver(), countKey, 0); final LocalDateTime now = LocalDateTime.now(ZoneId.systemDefault()); LocalDateTime savedDate = null; if (countShown != 0) { // Check the saved date only if there is a count of notification. // This will detect manual override of the count setting. final String date = Settings.Secure.getString(getContentResolver(), dateKey); // The notification is always displayed the first time and if it has been at least…: // The notification is always displayed the first time and if it has been at least…: // * … 1 week since the first display (aka recurring only once) // * … 1 week since the first display (aka recurring only once) // * … 6 months since the last display (aka recurring forever) // * … 6 months since the last display (aka recurring forever) LocalDateTime savedDate = null; if (date != null) { if (date != null) { savedDate = LocalDateTime.parse(date); savedDate = LocalDateTime.parse(date); if ((countShown == 1 && now.isBefore(savedDate.plusWeeks(1))) if ((countShown == 1 && now.isBefore(savedDate.plusWeeks(1))) Loading @@ -183,6 +186,8 @@ public class NotificationHelperService extends Service { } } } } } Settings.Secure.putInt(getContentResolver(), countKey, Math.min(3, countShown + 1)); Settings.Secure.putInt(getContentResolver(), countKey, Math.min(3, countShown + 1)); Settings.Secure.putString(getContentResolver(), dateKey, now.toString()); Settings.Secure.putString(getContentResolver(), dateKey, now.toString()); Log.i( Log.i( Loading Loading
OWNERS_build +0 −1 Original line number Original line Diff line number Diff line licorne@google.com wescande@google.com wescande@google.com
OWNERS_hearingaid +0 −1 Original line number Original line Diff line number Diff line charliebout@google.com charliebout@google.com licorne@google.com
android/app/src/com/android/bluetooth/bass_client/BassClientService.java +69 −31 Original line number Original line Diff line number Diff line Loading @@ -92,7 +92,6 @@ import java.util.Deque; import java.util.HashMap; import java.util.HashMap; import java.util.HashSet; import java.util.HashSet; import java.util.Iterator; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.List; import java.util.Map; import java.util.Map; import java.util.Objects; import java.util.Objects; Loading Loading @@ -148,7 +147,7 @@ public class BassClientService extends ProfileService { private final Map<BluetoothDevice, List<Integer>> mActiveSourceMap = new ConcurrentHashMap<>(); private final Map<BluetoothDevice, List<Integer>> mActiveSourceMap = new ConcurrentHashMap<>(); private final Map<BluetoothDevice, BluetoothLeBroadcastMetadata> mBroadcastMetadataMap = private final Map<BluetoothDevice, BluetoothLeBroadcastMetadata> mBroadcastMetadataMap = new ConcurrentHashMap<>(); new ConcurrentHashMap<>(); private final LinkedList<BluetoothDevice> mPausedBroadcastSinks = new LinkedList<>(); private final HashSet<BluetoothDevice> mPausedBroadcastSinks = new HashSet<>(); private final Deque<AddSourceData> mPendingAddSources = new ArrayDeque<>(); private final Deque<AddSourceData> mPendingAddSources = new ArrayDeque<>(); private final Map<Integer, HashSet<BluetoothDevice>> mLocalBroadcastReceivers = private final Map<Integer, HashSet<BluetoothDevice>> mLocalBroadcastReceivers = new ConcurrentHashMap<>(); new ConcurrentHashMap<>(); Loading Loading @@ -704,6 +703,7 @@ public class BassClientService extends ProfileService { mLocalBroadcastReceivers.clear(); mLocalBroadcastReceivers.clear(); mPendingGroupOp.clear(); mPendingGroupOp.clear(); mBroadcastMetadataMap.clear(); mBroadcastMetadataMap.clear(); mPausedBroadcastSinks.clear(); } } } } Loading Loading @@ -1394,6 +1394,7 @@ public class BassClientService extends ProfileService { // Check if the device is disconnected - if unbond, remove the state machine // Check if the device is disconnected - if unbond, remove the state machine if (toState == BluetoothProfile.STATE_DISCONNECTED) { if (toState == BluetoothProfile.STATE_DISCONNECTED) { mPendingGroupOp.remove(device); mPendingGroupOp.remove(device); mPausedBroadcastSinks.remove(device); int bondState = mAdapterService.getBondState(device); int bondState = mAdapterService.getBondState(device); if (bondState == BluetoothDevice.BOND_NONE) { if (bondState == BluetoothDevice.BOND_NONE) { Loading Loading @@ -1892,9 +1893,12 @@ public class BassClientService extends ProfileService { int skip, int skip, int timeout, int timeout, int status) { int status) { int broadcastId = getBroadcastIdForSyncHandle(BassConstants.INVALID_SYNC_HANDLE); log( log( "onSyncEstablished syncHandle: " "onSyncEstablished syncHandle: " + syncHandle + syncHandle + ", broadcastId: " + broadcastId + ", device: " + ", device: " + device + device + ", advertisingSid: " + ", advertisingSid: " Loading Loading @@ -1944,9 +1948,7 @@ public class BassClientService extends ProfileService { Iterator<AddSourceData> iterator = mPendingSourcesToAdd.iterator(); Iterator<AddSourceData> iterator = mPendingSourcesToAdd.iterator(); while (iterator.hasNext()) { while (iterator.hasNext()) { AddSourceData pendingSourcesToAdd = iterator.next(); AddSourceData pendingSourcesToAdd = iterator.next(); BluetoothDevice sourceDevice = if (pendingSourcesToAdd.mSourceMetadata.getBroadcastId() == broadcastId) { pendingSourcesToAdd.mSourceMetadata.getSourceDevice(); if (sourceDevice.equals(device)) { addSource( addSource( pendingSourcesToAdd.mSink, pendingSourcesToAdd.mSink, pendingSourcesToAdd.mSourceMetadata, pendingSourcesToAdd.mSourceMetadata, Loading @@ -1957,9 +1959,31 @@ public class BassClientService extends ProfileService { } } } else { } else { // remove failed sync handle // remove failed sync handle int broadcastId = getBroadcastIdForSyncHandle(BassConstants.INVALID_SYNC_HANDLE); log("onSyncEstablished failed for broadcast id: " + broadcastId); log("onSyncEstablished failed for broadcast id: " + broadcastId); boolean notifiedOfLost = false; synchronized (mPendingSourcesToAdd) { Iterator<AddSourceData> iterator = mPendingSourcesToAdd.iterator(); while (iterator.hasNext()) { AddSourceData pendingSourcesToAdd = iterator.next(); if (pendingSourcesToAdd.mSourceMetadata.getBroadcastId() == broadcastId) { if (!notifiedOfLost) { notifiedOfLost = true; mCallbacks.notifySourceLost(broadcastId); } mCallbacks.notifySourceAddFailed( pendingSourcesToAdd.mSink, pendingSourcesToAdd.mSourceMetadata, BluetoothStatusCodes.ERROR_LOCAL_NOT_ENOUGH_RESOURCES); iterator.remove(); } } } synchronized (mSearchScanCallbackLock) { // Clear from cache to make possible sync again (only during active searching) if (mSearchScanCallback != null) { mCachedBroadcasts.remove(broadcastId); mCachedBroadcasts.remove(broadcastId); } } mPeriodicAdvCallbacksMap.remove(BassConstants.INVALID_SYNC_HANDLE); mPeriodicAdvCallbacksMap.remove(BassConstants.INVALID_SYNC_HANDLE); } } handleSelectSourceRequest(); handleSelectSourceRequest(); Loading Loading @@ -2029,9 +2053,13 @@ public class BassClientService extends ProfileService { } } } } clearAllDataForSyncHandle(syncHandle); clearAllDataForSyncHandle(syncHandle); // Clear from cache to make possible sync again // Clear from cache to make possible sync again (only during active searching) synchronized (mSearchScanCallbackLock) { if (mSearchScanCallback != null) { mCachedBroadcasts.remove(broadcastId); mCachedBroadcasts.remove(broadcastId); } } } } @Override @Override public void onBigInfoAdvertisingReport(int syncHandle, boolean encrypted) { public void onBigInfoAdvertisingReport(int syncHandle, boolean encrypted) { Loading Loading @@ -2533,11 +2561,21 @@ public class BassClientService extends ProfileService { if (broadcastId != BassConstants.INVALID_BROADCAST_ID if (broadcastId != BassConstants.INVALID_BROADCAST_ID && getCachedBroadcast(broadcastId) != null) { && getCachedBroadcast(broadcastId) != null) { // If the source has been synced before, try to re-sync // If the source has been synced before, try to re-sync // with the source by previously cached scan result // with the source by previously cached scan result. addSelectSourceRequest(getCachedBroadcast(broadcastId), true); // Check if not added already boolean alreadyAdded = false; synchronized (mPendingSourcesToAdd) { synchronized (mPendingSourcesToAdd) { for (AddSourceData pendingSourcesToAdd : mPendingSourcesToAdd) { if (pendingSourcesToAdd.mSourceMetadata.getBroadcastId() == broadcastId) { alreadyAdded = true; } } mPendingSourcesToAdd.add( mPendingSourcesToAdd.add( new AddSourceData(sink, sourceMetadata, isGroupOp)); new AddSourceData(sink, sourceMetadata, isGroupOp)); if (!alreadyAdded) { addSelectSourceRequest(getCachedBroadcast(broadcastId), true); } } } } else { } else { log("AddSource: broadcast not cached or invalid, broadcastId: " + broadcastId); log("AddSource: broadcast not cached or invalid, broadcastId: " + broadcastId); Loading Loading @@ -2958,15 +2996,14 @@ public class BassClientService extends ProfileService { private void stopSourceReceivers(int broadcastId, boolean store) { private void stopSourceReceivers(int broadcastId, boolean store) { Log.d(TAG, "stopSourceReceivers(), broadcastId: " + broadcastId + ", store: " + store); Log.d(TAG, "stopSourceReceivers(), broadcastId: " + broadcastId + ", store: " + store); if (store && !mPausedBroadcastSinks.isEmpty()) { Log.w(TAG, "stopSourceReceivers(), paused broadcast sinks are replaced"); sEventLogger.logd(TAG, "Clear broadcast sinks paused cache"); mPausedBroadcastSinks.clear(); } Map<BluetoothDevice, Integer> sourcesToRemove = new HashMap<>(); Map<BluetoothDevice, Integer> sourcesToRemove = new HashMap<>(); for (BluetoothDevice device : getConnectedDevices()) { for (BluetoothDevice device : getConnectedDevices()) { if (mPausedBroadcastSinks.contains(device)) { // Skip this device if it has been paused continue; } for (BluetoothLeBroadcastReceiveState receiveState : getAllSources(device)) { for (BluetoothLeBroadcastReceiveState receiveState : getAllSources(device)) { /* Check if local/last broadcast is the synced one. Invalid broadcast ID means /* Check if local/last broadcast is the synced one. Invalid broadcast ID means * that all receivers should be considered. * that all receivers should be considered. Loading @@ -2976,7 +3013,7 @@ public class BassClientService extends ProfileService { continue; continue; } } if (store && !mPausedBroadcastSinks.contains(device)) { if (store) { sEventLogger.logd(TAG, "Add broadcast sink to paused cache: " + device); sEventLogger.logd(TAG, "Add broadcast sink to paused cache: " + device); mPausedBroadcastSinks.add(device); mPausedBroadcastSinks.add(device); } } Loading Loading @@ -3130,18 +3167,12 @@ public class BassClientService extends ProfileService { } } } } /** Cache suspending sources */ /** Cache suspending sources when broadcast paused */ public void cacheSuspendingSources(int broadcastId) { public void cacheSuspendingSources(int broadcastId) { sEventLogger.logd(TAG, "Cache suspending sources: " + broadcastId); sEventLogger.logd(TAG, "Cache suspending sources: " + broadcastId); List<Pair<BluetoothLeBroadcastReceiveState, BluetoothDevice>> sourcesToCache = List<Pair<BluetoothLeBroadcastReceiveState, BluetoothDevice>> sourcesToCache = getReceiveStateDevicePairs(broadcastId); getReceiveStateDevicePairs(broadcastId); if (!mPausedBroadcastSinks.isEmpty()) { Log.w(TAG, "cacheSuspendingSources(), paused broadcast sinks are replaced"); sEventLogger.logd(TAG, "Clear broadcast sinks paused cache"); mPausedBroadcastSinks.clear(); } for (Pair<BluetoothLeBroadcastReceiveState, BluetoothDevice> pair : sourcesToCache) { for (Pair<BluetoothLeBroadcastReceiveState, BluetoothDevice> pair : sourcesToCache) { mPausedBroadcastSinks.add(pair.second); mPausedBroadcastSinks.add(pair.second); } } Loading Loading @@ -3173,8 +3204,9 @@ public class BassClientService extends ProfileService { public void resumeReceiversSourceSynchronization() { public void resumeReceiversSourceSynchronization() { sEventLogger.logd(TAG, "Resume receivers source synchronization"); sEventLogger.logd(TAG, "Resume receivers source synchronization"); while (!mPausedBroadcastSinks.isEmpty()) { Iterator<BluetoothDevice> iterator = mPausedBroadcastSinks.iterator(); BluetoothDevice sink = mPausedBroadcastSinks.remove(); while (iterator.hasNext()) { BluetoothDevice sink = iterator.next(); sEventLogger.logd(TAG, "Remove broadcast sink from paused cache: " + sink); sEventLogger.logd(TAG, "Remove broadcast sink from paused cache: " + sink); BluetoothLeBroadcastMetadata metadata = mBroadcastMetadataMap.get(sink); BluetoothLeBroadcastMetadata metadata = mBroadcastMetadataMap.get(sink); Loading @@ -3182,9 +3214,11 @@ public class BassClientService extends ProfileService { if (metadata == null) { if (metadata == null) { Log.w( Log.w( TAG, TAG, "resumeReceiversSourceSynchronization: failed to get metadata to resume" "resumeReceiversSourceSynchronization: failed to get metadata to" + " sink: " + " resume sink: " + sink); + sink); // remove the device from mPausedBroadcastSinks iterator.remove(); continue; continue; } } Loading @@ -3207,6 +3241,8 @@ public class BassClientService extends ProfileService { if (statusCode != BluetoothStatusCodes.SUCCESS) { if (statusCode != BluetoothStatusCodes.SUCCESS) { mCallbacks.notifySourceModifyFailed(sink, sourceId, statusCode); mCallbacks.notifySourceModifyFailed(sink, sourceId, statusCode); // remove the device from mPausedBroadcastSinks iterator.remove(); continue; continue; } } Loading Loading @@ -3238,11 +3274,13 @@ public class BassClientService extends ProfileService { } else { } else { Log.w( Log.w( TAG, TAG, "resumeReceiversSourceSynchronization: failed to get metadata to resume" "resumeReceiversSourceSynchronization: failed to get metadata to" + " sink: " + " resume sink: " + sink); + sink); } } } } // remove the device from mPausedBroadcastSinks iterator.remove(); } } } } Loading
android/app/src/com/android/bluetooth/le_scan/TransitionalScanHelper.java +1 −4 Original line number Original line Diff line number Diff line Loading @@ -78,16 +78,13 @@ import java.util.function.Predicate; /** /** * A helper class which contains all scan related functions extracted from {@link * A helper class which contains all scan related functions extracted from {@link * com.android.bluetooth.gatt.GattService}. The purpose of this class is to preserve scan * com.android.bluetooth.gatt.GattService}. The purpose of this class is to preserve scan * functionality within GattService and provide the same functionality in a new scan dedicated * functionality within GattService and provide the same functionality in {@link ScanController}. * {@link com.android.bluetooth.btservice.ProfileService} when introduced. */ */ public class TransitionalScanHelper { public class TransitionalScanHelper { private static final String TAG = GattServiceConfig.TAG_PREFIX + "ScanHelper"; private static final String TAG = GattServiceConfig.TAG_PREFIX + "ScanHelper"; // Batch scan related constants. // Batch scan related constants. private static final int TRUNCATED_RESULT_SIZE = 11; private static final int TRUNCATED_RESULT_SIZE = 11; static final int SCAN_FILTER_ENABLED = 1; static final int SCAN_FILTER_MODIFIED = 2; /** The default floor value for LE batch scan report delays greater than 0 */ /** The default floor value for LE batch scan report delays greater than 0 */ @VisibleForTesting static final long DEFAULT_REPORT_DELAY_FLOOR = 5000; @VisibleForTesting static final long DEFAULT_REPORT_DELAY_FLOOR = 5000; Loading
android/app/src/com/android/bluetooth/notification/NotificationHelperService.java +22 −17 Original line number Original line Diff line number Diff line Loading @@ -160,16 +160,19 @@ public class NotificationHelperService extends Service { } } private boolean shouldDisplayNotification(String countKey) { private boolean shouldDisplayNotification(String countKey) { final LocalDateTime now = LocalDateTime.now(ZoneId.systemDefault()); final String dateKey = countKey + "_date"; final String dateKey = countKey + "_date"; final String date = Settings.Secure.getString(getContentResolver(), dateKey); final int countShown = Settings.Secure.getInt(getContentResolver(), countKey, 0); final int countShown = Settings.Secure.getInt(getContentResolver(), countKey, 0); final LocalDateTime now = LocalDateTime.now(ZoneId.systemDefault()); LocalDateTime savedDate = null; if (countShown != 0) { // Check the saved date only if there is a count of notification. // This will detect manual override of the count setting. final String date = Settings.Secure.getString(getContentResolver(), dateKey); // The notification is always displayed the first time and if it has been at least…: // The notification is always displayed the first time and if it has been at least…: // * … 1 week since the first display (aka recurring only once) // * … 1 week since the first display (aka recurring only once) // * … 6 months since the last display (aka recurring forever) // * … 6 months since the last display (aka recurring forever) LocalDateTime savedDate = null; if (date != null) { if (date != null) { savedDate = LocalDateTime.parse(date); savedDate = LocalDateTime.parse(date); if ((countShown == 1 && now.isBefore(savedDate.plusWeeks(1))) if ((countShown == 1 && now.isBefore(savedDate.plusWeeks(1))) Loading @@ -183,6 +186,8 @@ public class NotificationHelperService extends Service { } } } } } Settings.Secure.putInt(getContentResolver(), countKey, Math.min(3, countShown + 1)); Settings.Secure.putInt(getContentResolver(), countKey, Math.min(3, countShown + 1)); Settings.Secure.putString(getContentResolver(), dateKey, now.toString()); Settings.Secure.putString(getContentResolver(), dateKey, now.toString()); Log.i( Log.i( Loading