Loading services/companion/java/com/android/server/companion/presence/BleCompanionDeviceScanner.java +2 −2 Original line number Diff line number Diff line Loading @@ -168,7 +168,7 @@ class BleCompanionDeviceScanner implements AssociationStore.OnChangeListener { void startScan() { enforceInitialized(); if (DEBUG) Log.i(TAG, "startScan()"); Slog.i(TAG, "startBleScan()"); // This method should not be called if scan is already in progress. if (mScanning) { Slog.w(TAG, "Scan is already in progress."); Loading Loading @@ -228,7 +228,7 @@ class BleCompanionDeviceScanner implements AssociationStore.OnChangeListener { void stopScanIfNeeded() { enforceInitialized(); if (DEBUG) Log.i(TAG, "stopScan()"); Slog.i(TAG, "stopBleScan()"); if (!mScanning) { if (DEBUG) Log.d(TAG, " > not scanning."); return; Loading services/companion/java/com/android/server/companion/presence/CompanionDevicePresenceMonitor.java +117 −12 Original line number Diff line number Diff line Loading @@ -41,7 +41,9 @@ import android.os.UserManager; import android.util.Log; import android.util.Slog; import android.util.SparseArray; import android.util.SparseBooleanArray; import com.android.internal.annotations.GuardedBy; import com.android.server.companion.AssociationStore; import java.io.PrintWriter; Loading Loading @@ -100,12 +102,24 @@ public class CompanionDevicePresenceMonitor implements AssociationStore.OnChange private final @NonNull Set<Integer> mNearbyBleDevices = new HashSet<>(); private final @NonNull Set<Integer> mReportedSelfManagedDevices = new HashSet<>(); private final @NonNull Set<ParcelUuid> mConnectedUuidDevices = new HashSet<>(); @GuardedBy("mBtDisconnectedDevices") private final @NonNull Set<Integer> mBtDisconnectedDevices = new HashSet<>(); // A map to track device presence within 10 seconds of Bluetooth disconnection. // The key is the association ID, and the boolean value indicates if the device // was detected again within that time frame. @GuardedBy("mBtDisconnectedDevices") private final @NonNull SparseBooleanArray mBtDisconnectedDevicesBlePresence = new SparseBooleanArray(); // Tracking "simulated" presence. Used for debugging and testing only. private final @NonNull Set<Integer> mSimulated = new HashSet<>(); private final SimulatedDevicePresenceSchedulerHelper mSchedulerHelper = new SimulatedDevicePresenceSchedulerHelper(); private final BleDeviceDisappearedScheduler mBleDeviceDisappearedScheduler = new BleDeviceDisappearedScheduler(); public CompanionDevicePresenceMonitor(UserManager userManager, @NonNull AssociationStore associationStore, @NonNull ObservableUuidStore observableUuidStore, @NonNull Callback callback) { Loading Loading @@ -227,14 +241,25 @@ public class CompanionDevicePresenceMonitor implements AssociationStore.OnChange @Override public void onBluetoothCompanionDeviceConnected(int associationId) { synchronized (mBtDisconnectedDevices) { // A device is considered reconnected within 10 seconds if a pending BLE lost report is // followed by a detected Bluetooth connection. boolean isReconnected = mBtDisconnectedDevices.contains(associationId); if (isReconnected) { Slog.i(TAG, "Device ( " + associationId + " ) is reconnected within 10s."); mBleDeviceDisappearedScheduler.unScheduleDeviceDisappeared(associationId); } Slog.i(TAG, "onBluetoothCompanionDeviceConnected: " + "associationId( " + associationId + " )"); onDevicePresenceEvent(mConnectedBtDevices, associationId, EVENT_BT_CONNECTED); // Stop scanning for BLE devices when this device is connected // and there are no other devices to connect to. // Stop the BLE scan if all devices report BT connected status and BLE was present. if (canStopBleScan()) { mBleScanner.stopScanIfNeeded(); } } } @Override Loading @@ -245,6 +270,14 @@ public class CompanionDevicePresenceMonitor implements AssociationStore.OnChange mBleScanner.startScan(); onDevicePresenceEvent(mConnectedBtDevices, associationId, EVENT_BT_DISCONNECTED); // If current device is BLE present but BT is disconnected , means it will be // potentially out of range later. Schedule BLE disappeared callback. if (isBlePresent(associationId)) { synchronized (mBtDisconnectedDevices) { mBtDisconnectedDevices.add(associationId); } mBleDeviceDisappearedScheduler.scheduleBleDeviceDisappeared(associationId); } } @Override Loading Loading @@ -281,6 +314,12 @@ public class CompanionDevicePresenceMonitor implements AssociationStore.OnChange @Override public void onBleCompanionDeviceFound(int associationId) { onDevicePresenceEvent(mNearbyBleDevices, associationId, EVENT_BLE_APPEARED); synchronized (mBtDisconnectedDevices) { final boolean isCurrentPresent = mBtDisconnectedDevicesBlePresence.get(associationId); if (mBtDisconnectedDevices.contains(associationId) && isCurrentPresent) { mBleDeviceDisappearedScheduler.unScheduleDeviceDisappeared(associationId); } } } @Override Loading Loading @@ -351,6 +390,16 @@ public class CompanionDevicePresenceMonitor implements AssociationStore.OnChange switch (event) { case EVENT_BLE_APPEARED: synchronized (mBtDisconnectedDevices) { // If a BLE device is detected within 10 seconds after BT is disconnected, // flag it as BLE is present. if (mBtDisconnectedDevices.contains(associationId)) { Slog.i(TAG, "Device ( " + associationId + " ) is present," + " do not need to send the callback with event ( " + EVENT_BLE_APPEARED + " )."); mBtDisconnectedDevicesBlePresence.append(associationId, true); } } case EVENT_BT_CONNECTED: case EVENT_SELF_MANAGED_APPEARED: final boolean added = presentDevicesForSource.add(associationId); Loading Loading @@ -403,6 +452,8 @@ public class CompanionDevicePresenceMonitor implements AssociationStore.OnChange mNearbyBleDevices.remove(id); mReportedSelfManagedDevices.remove(id); mSimulated.remove(id); mBtDisconnectedDevices.remove(id); mBtDisconnectedDevicesBlePresence.delete(id); // Do NOT call mCallback.onDeviceDisappeared()! // CompanionDeviceManagerService will know that the association is removed, and will do Loading @@ -425,16 +476,23 @@ public class CompanionDevicePresenceMonitor implements AssociationStore.OnChange throw new SecurityException("Caller is neither Shell nor Root"); } /** * The BLE scan can be only stopped if all the devices have been reported * BT connected and BLE presence and are not pending to report BLE lost. */ private boolean canStopBleScan() { for (AssociationInfo ai : mAssociationStore.getAssociations()) { int id = ai.getId(); // The BLE scan cannot be stopped if there's a device is not yet connected. if (ai.isNotifyOnDeviceNearby() && !isBtConnected(id)) { synchronized (mBtDisconnectedDevices) { if (ai.isNotifyOnDeviceNearby() && !(isBtConnected(id) && isBlePresent(id) && mBtDisconnectedDevices.isEmpty())) { Slog.i(TAG, "The BLE scan cannot be stopped, " + "device( " + id + " ) is not yet connected"); + "device( " + id + " ) is not yet connected " + "OR the BLE is not current present Or is pending to report BLE lost"); return false; } } } return true; } Loading Loading @@ -512,4 +570,51 @@ public class CompanionDevicePresenceMonitor implements AssociationStore.OnChange } } } private class BleDeviceDisappearedScheduler extends Handler { BleDeviceDisappearedScheduler() { super(Looper.getMainLooper()); } void scheduleBleDeviceDisappeared(int associationId) { if (hasMessages(associationId)) { removeMessages(associationId); } Slog.i(TAG, "scheduleBleDeviceDisappeared for Device: ( " + associationId + " )."); sendEmptyMessageDelayed(associationId, 10 * 1000 /* 10 seconds */); } void unScheduleDeviceDisappeared(int associationId) { if (hasMessages(associationId)) { Slog.i(TAG, "unScheduleDeviceDisappeared for Device( " + associationId + " )"); synchronized (mBtDisconnectedDevices) { mBtDisconnectedDevices.remove(associationId); mBtDisconnectedDevicesBlePresence.delete(associationId); } removeMessages(associationId); } } @Override public void handleMessage(@NonNull Message msg) { final int associationId = msg.what; synchronized (mBtDisconnectedDevices) { final boolean isCurrentPresent = mBtDisconnectedDevicesBlePresence.get( associationId); // If a device hasn't reported after 10 seconds and is not currently present, // assume BLE is lost and trigger the onDeviceEvent callback with the // EVENT_BLE_DISAPPEARED event. if (mBtDisconnectedDevices.contains(associationId) && !isCurrentPresent) { Slog.i(TAG, "Device ( " + associationId + " ) is likely BLE out of range, " + "sending callback with event ( " + EVENT_BLE_DISAPPEARED + " )"); onDevicePresenceEvent(mNearbyBleDevices, associationId, EVENT_BLE_DISAPPEARED); } mBtDisconnectedDevices.remove(associationId); mBtDisconnectedDevicesBlePresence.delete(associationId); } } } } Loading
services/companion/java/com/android/server/companion/presence/BleCompanionDeviceScanner.java +2 −2 Original line number Diff line number Diff line Loading @@ -168,7 +168,7 @@ class BleCompanionDeviceScanner implements AssociationStore.OnChangeListener { void startScan() { enforceInitialized(); if (DEBUG) Log.i(TAG, "startScan()"); Slog.i(TAG, "startBleScan()"); // This method should not be called if scan is already in progress. if (mScanning) { Slog.w(TAG, "Scan is already in progress."); Loading Loading @@ -228,7 +228,7 @@ class BleCompanionDeviceScanner implements AssociationStore.OnChangeListener { void stopScanIfNeeded() { enforceInitialized(); if (DEBUG) Log.i(TAG, "stopScan()"); Slog.i(TAG, "stopBleScan()"); if (!mScanning) { if (DEBUG) Log.d(TAG, " > not scanning."); return; Loading
services/companion/java/com/android/server/companion/presence/CompanionDevicePresenceMonitor.java +117 −12 Original line number Diff line number Diff line Loading @@ -41,7 +41,9 @@ import android.os.UserManager; import android.util.Log; import android.util.Slog; import android.util.SparseArray; import android.util.SparseBooleanArray; import com.android.internal.annotations.GuardedBy; import com.android.server.companion.AssociationStore; import java.io.PrintWriter; Loading Loading @@ -100,12 +102,24 @@ public class CompanionDevicePresenceMonitor implements AssociationStore.OnChange private final @NonNull Set<Integer> mNearbyBleDevices = new HashSet<>(); private final @NonNull Set<Integer> mReportedSelfManagedDevices = new HashSet<>(); private final @NonNull Set<ParcelUuid> mConnectedUuidDevices = new HashSet<>(); @GuardedBy("mBtDisconnectedDevices") private final @NonNull Set<Integer> mBtDisconnectedDevices = new HashSet<>(); // A map to track device presence within 10 seconds of Bluetooth disconnection. // The key is the association ID, and the boolean value indicates if the device // was detected again within that time frame. @GuardedBy("mBtDisconnectedDevices") private final @NonNull SparseBooleanArray mBtDisconnectedDevicesBlePresence = new SparseBooleanArray(); // Tracking "simulated" presence. Used for debugging and testing only. private final @NonNull Set<Integer> mSimulated = new HashSet<>(); private final SimulatedDevicePresenceSchedulerHelper mSchedulerHelper = new SimulatedDevicePresenceSchedulerHelper(); private final BleDeviceDisappearedScheduler mBleDeviceDisappearedScheduler = new BleDeviceDisappearedScheduler(); public CompanionDevicePresenceMonitor(UserManager userManager, @NonNull AssociationStore associationStore, @NonNull ObservableUuidStore observableUuidStore, @NonNull Callback callback) { Loading Loading @@ -227,14 +241,25 @@ public class CompanionDevicePresenceMonitor implements AssociationStore.OnChange @Override public void onBluetoothCompanionDeviceConnected(int associationId) { synchronized (mBtDisconnectedDevices) { // A device is considered reconnected within 10 seconds if a pending BLE lost report is // followed by a detected Bluetooth connection. boolean isReconnected = mBtDisconnectedDevices.contains(associationId); if (isReconnected) { Slog.i(TAG, "Device ( " + associationId + " ) is reconnected within 10s."); mBleDeviceDisappearedScheduler.unScheduleDeviceDisappeared(associationId); } Slog.i(TAG, "onBluetoothCompanionDeviceConnected: " + "associationId( " + associationId + " )"); onDevicePresenceEvent(mConnectedBtDevices, associationId, EVENT_BT_CONNECTED); // Stop scanning for BLE devices when this device is connected // and there are no other devices to connect to. // Stop the BLE scan if all devices report BT connected status and BLE was present. if (canStopBleScan()) { mBleScanner.stopScanIfNeeded(); } } } @Override Loading @@ -245,6 +270,14 @@ public class CompanionDevicePresenceMonitor implements AssociationStore.OnChange mBleScanner.startScan(); onDevicePresenceEvent(mConnectedBtDevices, associationId, EVENT_BT_DISCONNECTED); // If current device is BLE present but BT is disconnected , means it will be // potentially out of range later. Schedule BLE disappeared callback. if (isBlePresent(associationId)) { synchronized (mBtDisconnectedDevices) { mBtDisconnectedDevices.add(associationId); } mBleDeviceDisappearedScheduler.scheduleBleDeviceDisappeared(associationId); } } @Override Loading Loading @@ -281,6 +314,12 @@ public class CompanionDevicePresenceMonitor implements AssociationStore.OnChange @Override public void onBleCompanionDeviceFound(int associationId) { onDevicePresenceEvent(mNearbyBleDevices, associationId, EVENT_BLE_APPEARED); synchronized (mBtDisconnectedDevices) { final boolean isCurrentPresent = mBtDisconnectedDevicesBlePresence.get(associationId); if (mBtDisconnectedDevices.contains(associationId) && isCurrentPresent) { mBleDeviceDisappearedScheduler.unScheduleDeviceDisappeared(associationId); } } } @Override Loading Loading @@ -351,6 +390,16 @@ public class CompanionDevicePresenceMonitor implements AssociationStore.OnChange switch (event) { case EVENT_BLE_APPEARED: synchronized (mBtDisconnectedDevices) { // If a BLE device is detected within 10 seconds after BT is disconnected, // flag it as BLE is present. if (mBtDisconnectedDevices.contains(associationId)) { Slog.i(TAG, "Device ( " + associationId + " ) is present," + " do not need to send the callback with event ( " + EVENT_BLE_APPEARED + " )."); mBtDisconnectedDevicesBlePresence.append(associationId, true); } } case EVENT_BT_CONNECTED: case EVENT_SELF_MANAGED_APPEARED: final boolean added = presentDevicesForSource.add(associationId); Loading Loading @@ -403,6 +452,8 @@ public class CompanionDevicePresenceMonitor implements AssociationStore.OnChange mNearbyBleDevices.remove(id); mReportedSelfManagedDevices.remove(id); mSimulated.remove(id); mBtDisconnectedDevices.remove(id); mBtDisconnectedDevicesBlePresence.delete(id); // Do NOT call mCallback.onDeviceDisappeared()! // CompanionDeviceManagerService will know that the association is removed, and will do Loading @@ -425,16 +476,23 @@ public class CompanionDevicePresenceMonitor implements AssociationStore.OnChange throw new SecurityException("Caller is neither Shell nor Root"); } /** * The BLE scan can be only stopped if all the devices have been reported * BT connected and BLE presence and are not pending to report BLE lost. */ private boolean canStopBleScan() { for (AssociationInfo ai : mAssociationStore.getAssociations()) { int id = ai.getId(); // The BLE scan cannot be stopped if there's a device is not yet connected. if (ai.isNotifyOnDeviceNearby() && !isBtConnected(id)) { synchronized (mBtDisconnectedDevices) { if (ai.isNotifyOnDeviceNearby() && !(isBtConnected(id) && isBlePresent(id) && mBtDisconnectedDevices.isEmpty())) { Slog.i(TAG, "The BLE scan cannot be stopped, " + "device( " + id + " ) is not yet connected"); + "device( " + id + " ) is not yet connected " + "OR the BLE is not current present Or is pending to report BLE lost"); return false; } } } return true; } Loading Loading @@ -512,4 +570,51 @@ public class CompanionDevicePresenceMonitor implements AssociationStore.OnChange } } } private class BleDeviceDisappearedScheduler extends Handler { BleDeviceDisappearedScheduler() { super(Looper.getMainLooper()); } void scheduleBleDeviceDisappeared(int associationId) { if (hasMessages(associationId)) { removeMessages(associationId); } Slog.i(TAG, "scheduleBleDeviceDisappeared for Device: ( " + associationId + " )."); sendEmptyMessageDelayed(associationId, 10 * 1000 /* 10 seconds */); } void unScheduleDeviceDisappeared(int associationId) { if (hasMessages(associationId)) { Slog.i(TAG, "unScheduleDeviceDisappeared for Device( " + associationId + " )"); synchronized (mBtDisconnectedDevices) { mBtDisconnectedDevices.remove(associationId); mBtDisconnectedDevicesBlePresence.delete(associationId); } removeMessages(associationId); } } @Override public void handleMessage(@NonNull Message msg) { final int associationId = msg.what; synchronized (mBtDisconnectedDevices) { final boolean isCurrentPresent = mBtDisconnectedDevicesBlePresence.get( associationId); // If a device hasn't reported after 10 seconds and is not currently present, // assume BLE is lost and trigger the onDeviceEvent callback with the // EVENT_BLE_DISAPPEARED event. if (mBtDisconnectedDevices.contains(associationId) && !isCurrentPresent) { Slog.i(TAG, "Device ( " + associationId + " ) is likely BLE out of range, " + "sending callback with event ( " + EVENT_BLE_DISAPPEARED + " )"); onDevicePresenceEvent(mNearbyBleDevices, associationId, EVENT_BLE_DISAPPEARED); } mBtDisconnectedDevices.remove(associationId); mBtDisconnectedDevicesBlePresence.delete(associationId); } } } }