Loading framework/java/android/bluetooth/BluetoothAdapter.java +71 −93 Original line number Diff line number Diff line Loading @@ -67,6 +67,7 @@ import com.android.internal.annotations.GuardedBy; import java.io.IOException; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.time.Duration; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; Loading Loading @@ -399,6 +400,16 @@ public final class BluetoothAdapter { @Retention(RetentionPolicy.SOURCE) public @interface ScanMode {} /** @hide */ @IntDef(value = { BluetoothStatusCodes.SUCCESS, BluetoothStatusCodes.ERROR_UNKNOWN, BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED, BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_SCAN_PERMISSION }) @Retention(RetentionPolicy.SOURCE) public @interface ScanModeStatusCode {} /** * Indicates that both inquiry scan and page scan are disabled on the local * Bluetooth adapter. Therefore this device is neither discoverable Loading Loading @@ -1615,7 +1626,7 @@ public final class BluetoothAdapter { return mService.getScanMode(mAttributionSource); } } catch (RemoteException e) { Log.e(TAG, "", e); throw e.rethrowFromSystemServer(); } finally { mServiceLock.readLock().unlock(); } Loading @@ -1623,143 +1634,110 @@ public final class BluetoothAdapter { } /** * Set the Bluetooth scan mode of the local Bluetooth adapter. * <p>The Bluetooth scan mode determines if the local adapter is * connectable and/or discoverable from remote Bluetooth devices. * <p>For privacy reasons, discoverable mode is automatically turned off * after <code>durationMillis</code> milliseconds. For example, 120000 milliseconds should be * enough for a remote device to initiate and complete its discovery process. * <p>Valid scan mode values are: * {@link #SCAN_MODE_NONE}, * {@link #SCAN_MODE_CONNECTABLE}, * {@link #SCAN_MODE_CONNECTABLE_DISCOVERABLE}. * <p>If Bluetooth state is not {@link #STATE_ON}, this API * will return false. After turning on Bluetooth, * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON} * to get the updated value. * Set the local Bluetooth adapter connectablility and discoverability. * <p>If the scan mode is set to {@link #SCAN_MODE_CONNECTABLE_DISCOVERABLE}, * it will change to {@link #SCAN_MODE_CONNECTABLE} after the discoverable timeout. * The discoverable timeout can be set with {@link #setDiscoverableTimeout} and * checked with {@link #getDiscoverableTimeout}. By default, the timeout is usually * 120 seconds on phones which is enough for a remote device to initiate and complete * its discovery process. * <p>Applications cannot set the scan mode. They should use * <code>startActivityForResult( * BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE}) * </code>instead. * * @param mode valid scan mode * @param durationMillis time in milliseconds to apply scan mode, only used for {@link * #SCAN_MODE_CONNECTABLE_DISCOVERABLE} * @return true if the scan mode was set, false otherwise * {@link #ACTION_REQUEST_DISCOVERABLE} instead. * * @param mode represents the desired state of the local device scan mode * * @return status code indicating whether the scan mode was successfully set * @hide */ @UnsupportedAppUsage(publicAlternatives = "Use {@link #ACTION_REQUEST_DISCOVERABLE}, which " + "shows UI that confirms the user wants to go into discoverable mode.") @RequiresLegacyBluetoothPermission @SystemApi @RequiresBluetoothScanPermission @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) public boolean setScanMode(@ScanMode int mode, long durationMillis) { @RequiresPermission(allOf = { android.Manifest.permission.BLUETOOTH_SCAN, android.Manifest.permission.BLUETOOTH_PRIVILEGED, }) @ScanModeStatusCode public int setScanMode(@ScanMode int mode) { if (getState() != STATE_ON) { return false; return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED; } try { mServiceLock.readLock().lock(); if (mService != null) { int durationSeconds = Math.toIntExact(durationMillis / 1000); return mService.setScanMode(mode, durationSeconds, mAttributionSource); return mService.setScanMode(mode, mAttributionSource); } } catch (RemoteException e) { Log.e(TAG, "", e); } catch (ArithmeticException ex) { Log.e(TAG, "setScanMode: Duration in seconds outside of the bounds of an int"); throw new IllegalArgumentException("Duration not in bounds. In seconds, the " + "durationMillis must be in the range of an int"); throw e.rethrowFromSystemServer(); } finally { mServiceLock.readLock().unlock(); } return false; return BluetoothStatusCodes.ERROR_UNKNOWN; } /** * Set the Bluetooth scan mode of the local Bluetooth adapter. * <p>The Bluetooth scan mode determines if the local adapter is * connectable and/or discoverable from remote Bluetooth devices. * <p>For privacy reasons, discoverable mode is automatically turned off * after <code>duration</code> seconds. For example, 120 seconds should be * enough for a remote device to initiate and complete its discovery * process. * <p>Valid scan mode values are: * {@link #SCAN_MODE_NONE}, * {@link #SCAN_MODE_CONNECTABLE}, * {@link #SCAN_MODE_CONNECTABLE_DISCOVERABLE}. * <p>If Bluetooth state is not {@link #STATE_ON}, this API * will return false. After turning on Bluetooth, * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON} * to get the updated value. * <p>Applications cannot set the scan mode. They should use * <code>startActivityForResult( * BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE}) * </code>instead. * Get the timeout duration of the {@link #SCAN_MODE_CONNECTABLE_DISCOVERABLE}. * * @param mode valid scan mode * @return true if the scan mode was set, false otherwise * @hide * @return the duration of the discoverable timeout or null if an error has occurred */ @UnsupportedAppUsage @RequiresLegacyBluetoothPermission @RequiresBluetoothScanPermission @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) public boolean setScanMode(@ScanMode int mode) { public @Nullable Duration getDiscoverableTimeout() { if (getState() != STATE_ON) { return false; return null; } try { mServiceLock.readLock().lock(); if (mService != null) { return mService.setScanMode(mode, getDiscoverableTimeout(), mAttributionSource); long timeout = mService.getDiscoverableTimeout(mAttributionSource); return (timeout == -1) ? null : Duration.ofSeconds(timeout); } } catch (RemoteException e) { Log.e(TAG, "", e); throw e.rethrowFromSystemServer(); } finally { mServiceLock.readLock().unlock(); } return false; return null; } /** @hide */ @UnsupportedAppUsage /** * Set the total time the Bluetooth local adapter will stay discoverable when * {@link #setScanMode} is called with {@link #SCAN_MODE_CONNECTABLE_DISCOVERABLE} mode. * After this timeout, the scan mode will fallback to {@link #SCAN_MODE_CONNECTABLE}. * <p>If <code>timeout</code> is set to 0, no timeout will occur and the scan mode will * be persisted until a subsequent call to {@link #setScanMode}. * * @param timeout represents the total duration the local Bluetooth adapter will remain * discoverable, or no timeout if set to 0 * @return whether the timeout was successfully set * @throws IllegalArgumentException if <code>timeout</code> duration in seconds is more * than {@link Integer#MAX_VALUE} * @hide */ @SystemApi @RequiresBluetoothScanPermission @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) public int getDiscoverableTimeout() { @RequiresPermission(allOf = { android.Manifest.permission.BLUETOOTH_SCAN, android.Manifest.permission.BLUETOOTH_PRIVILEGED, }) @ScanModeStatusCode public int setDiscoverableTimeout(@NonNull Duration timeout) { if (getState() != STATE_ON) { return -1; } try { mServiceLock.readLock().lock(); if (mService != null) { return mService.getDiscoverableTimeout(mAttributionSource); } } catch (RemoteException e) { Log.e(TAG, "", e); } finally { mServiceLock.readLock().unlock(); return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED; } return -1; } /** @hide */ @UnsupportedAppUsage @RequiresBluetoothScanPermission @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) public void setDiscoverableTimeout(int timeout) { if (getState() != STATE_ON) { return; if (timeout.toSeconds() > Integer.MAX_VALUE) { throw new IllegalArgumentException("Timeout in seconds must be less or equal to " + Integer.MAX_VALUE); } try { mServiceLock.readLock().lock(); if (mService != null) { mService.setDiscoverableTimeout(timeout, mAttributionSource); return mService.setDiscoverableTimeout(timeout.toSeconds(), mAttributionSource); } } catch (RemoteException e) { Log.e(TAG, "", e); throw e.rethrowFromSystemServer(); } finally { mServiceLock.readLock().unlock(); } return BluetoothStatusCodes.ERROR_UNKNOWN; } /** Loading framework/java/android/bluetooth/BluetoothStatusCodes.java +1 −1 Original line number Diff line number Diff line Loading @@ -40,7 +40,7 @@ public final class BluetoothStatusCodes { /** * Error code indicating that the API call was initiated by neither the system nor the active * Zuser * user */ public static final int ERROR_BLUETOOTH_NOT_ALLOWED = 2; Loading framework/tests/src/android/bluetooth/BluetoothTestUtils.java +4 −2 Original line number Diff line number Diff line Loading @@ -587,7 +587,8 @@ public class BluetoothTestUtils extends Assert { final IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED); mContext.registerReceiver(receiver, filter); assertTrue(adapter.setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE)); assertEquals(adapter.setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE), BluetoothStatusCodes.SUCCESS); boolean success = false; try { success = completionSemaphore.tryAcquire(DISCOVERABLE_UNDISCOVERABLE_TIMEOUT, Loading Loading @@ -637,7 +638,8 @@ public class BluetoothTestUtils extends Assert { final IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED); mContext.registerReceiver(receiver, filter); assertTrue(adapter.setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE)); assertEquals(adapter.setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE), BluetoothStatusCodes.SUCCESS); boolean success = false; try { success = completionSemaphore.tryAcquire(DISCOVERABLE_UNDISCOVERABLE_TIMEOUT, Loading Loading
framework/java/android/bluetooth/BluetoothAdapter.java +71 −93 Original line number Diff line number Diff line Loading @@ -67,6 +67,7 @@ import com.android.internal.annotations.GuardedBy; import java.io.IOException; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.time.Duration; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; Loading Loading @@ -399,6 +400,16 @@ public final class BluetoothAdapter { @Retention(RetentionPolicy.SOURCE) public @interface ScanMode {} /** @hide */ @IntDef(value = { BluetoothStatusCodes.SUCCESS, BluetoothStatusCodes.ERROR_UNKNOWN, BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED, BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_SCAN_PERMISSION }) @Retention(RetentionPolicy.SOURCE) public @interface ScanModeStatusCode {} /** * Indicates that both inquiry scan and page scan are disabled on the local * Bluetooth adapter. Therefore this device is neither discoverable Loading Loading @@ -1615,7 +1626,7 @@ public final class BluetoothAdapter { return mService.getScanMode(mAttributionSource); } } catch (RemoteException e) { Log.e(TAG, "", e); throw e.rethrowFromSystemServer(); } finally { mServiceLock.readLock().unlock(); } Loading @@ -1623,143 +1634,110 @@ public final class BluetoothAdapter { } /** * Set the Bluetooth scan mode of the local Bluetooth adapter. * <p>The Bluetooth scan mode determines if the local adapter is * connectable and/or discoverable from remote Bluetooth devices. * <p>For privacy reasons, discoverable mode is automatically turned off * after <code>durationMillis</code> milliseconds. For example, 120000 milliseconds should be * enough for a remote device to initiate and complete its discovery process. * <p>Valid scan mode values are: * {@link #SCAN_MODE_NONE}, * {@link #SCAN_MODE_CONNECTABLE}, * {@link #SCAN_MODE_CONNECTABLE_DISCOVERABLE}. * <p>If Bluetooth state is not {@link #STATE_ON}, this API * will return false. After turning on Bluetooth, * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON} * to get the updated value. * Set the local Bluetooth adapter connectablility and discoverability. * <p>If the scan mode is set to {@link #SCAN_MODE_CONNECTABLE_DISCOVERABLE}, * it will change to {@link #SCAN_MODE_CONNECTABLE} after the discoverable timeout. * The discoverable timeout can be set with {@link #setDiscoverableTimeout} and * checked with {@link #getDiscoverableTimeout}. By default, the timeout is usually * 120 seconds on phones which is enough for a remote device to initiate and complete * its discovery process. * <p>Applications cannot set the scan mode. They should use * <code>startActivityForResult( * BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE}) * </code>instead. * * @param mode valid scan mode * @param durationMillis time in milliseconds to apply scan mode, only used for {@link * #SCAN_MODE_CONNECTABLE_DISCOVERABLE} * @return true if the scan mode was set, false otherwise * {@link #ACTION_REQUEST_DISCOVERABLE} instead. * * @param mode represents the desired state of the local device scan mode * * @return status code indicating whether the scan mode was successfully set * @hide */ @UnsupportedAppUsage(publicAlternatives = "Use {@link #ACTION_REQUEST_DISCOVERABLE}, which " + "shows UI that confirms the user wants to go into discoverable mode.") @RequiresLegacyBluetoothPermission @SystemApi @RequiresBluetoothScanPermission @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) public boolean setScanMode(@ScanMode int mode, long durationMillis) { @RequiresPermission(allOf = { android.Manifest.permission.BLUETOOTH_SCAN, android.Manifest.permission.BLUETOOTH_PRIVILEGED, }) @ScanModeStatusCode public int setScanMode(@ScanMode int mode) { if (getState() != STATE_ON) { return false; return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED; } try { mServiceLock.readLock().lock(); if (mService != null) { int durationSeconds = Math.toIntExact(durationMillis / 1000); return mService.setScanMode(mode, durationSeconds, mAttributionSource); return mService.setScanMode(mode, mAttributionSource); } } catch (RemoteException e) { Log.e(TAG, "", e); } catch (ArithmeticException ex) { Log.e(TAG, "setScanMode: Duration in seconds outside of the bounds of an int"); throw new IllegalArgumentException("Duration not in bounds. In seconds, the " + "durationMillis must be in the range of an int"); throw e.rethrowFromSystemServer(); } finally { mServiceLock.readLock().unlock(); } return false; return BluetoothStatusCodes.ERROR_UNKNOWN; } /** * Set the Bluetooth scan mode of the local Bluetooth adapter. * <p>The Bluetooth scan mode determines if the local adapter is * connectable and/or discoverable from remote Bluetooth devices. * <p>For privacy reasons, discoverable mode is automatically turned off * after <code>duration</code> seconds. For example, 120 seconds should be * enough for a remote device to initiate and complete its discovery * process. * <p>Valid scan mode values are: * {@link #SCAN_MODE_NONE}, * {@link #SCAN_MODE_CONNECTABLE}, * {@link #SCAN_MODE_CONNECTABLE_DISCOVERABLE}. * <p>If Bluetooth state is not {@link #STATE_ON}, this API * will return false. After turning on Bluetooth, * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON} * to get the updated value. * <p>Applications cannot set the scan mode. They should use * <code>startActivityForResult( * BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE}) * </code>instead. * Get the timeout duration of the {@link #SCAN_MODE_CONNECTABLE_DISCOVERABLE}. * * @param mode valid scan mode * @return true if the scan mode was set, false otherwise * @hide * @return the duration of the discoverable timeout or null if an error has occurred */ @UnsupportedAppUsage @RequiresLegacyBluetoothPermission @RequiresBluetoothScanPermission @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) public boolean setScanMode(@ScanMode int mode) { public @Nullable Duration getDiscoverableTimeout() { if (getState() != STATE_ON) { return false; return null; } try { mServiceLock.readLock().lock(); if (mService != null) { return mService.setScanMode(mode, getDiscoverableTimeout(), mAttributionSource); long timeout = mService.getDiscoverableTimeout(mAttributionSource); return (timeout == -1) ? null : Duration.ofSeconds(timeout); } } catch (RemoteException e) { Log.e(TAG, "", e); throw e.rethrowFromSystemServer(); } finally { mServiceLock.readLock().unlock(); } return false; return null; } /** @hide */ @UnsupportedAppUsage /** * Set the total time the Bluetooth local adapter will stay discoverable when * {@link #setScanMode} is called with {@link #SCAN_MODE_CONNECTABLE_DISCOVERABLE} mode. * After this timeout, the scan mode will fallback to {@link #SCAN_MODE_CONNECTABLE}. * <p>If <code>timeout</code> is set to 0, no timeout will occur and the scan mode will * be persisted until a subsequent call to {@link #setScanMode}. * * @param timeout represents the total duration the local Bluetooth adapter will remain * discoverable, or no timeout if set to 0 * @return whether the timeout was successfully set * @throws IllegalArgumentException if <code>timeout</code> duration in seconds is more * than {@link Integer#MAX_VALUE} * @hide */ @SystemApi @RequiresBluetoothScanPermission @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) public int getDiscoverableTimeout() { @RequiresPermission(allOf = { android.Manifest.permission.BLUETOOTH_SCAN, android.Manifest.permission.BLUETOOTH_PRIVILEGED, }) @ScanModeStatusCode public int setDiscoverableTimeout(@NonNull Duration timeout) { if (getState() != STATE_ON) { return -1; } try { mServiceLock.readLock().lock(); if (mService != null) { return mService.getDiscoverableTimeout(mAttributionSource); } } catch (RemoteException e) { Log.e(TAG, "", e); } finally { mServiceLock.readLock().unlock(); return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED; } return -1; } /** @hide */ @UnsupportedAppUsage @RequiresBluetoothScanPermission @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) public void setDiscoverableTimeout(int timeout) { if (getState() != STATE_ON) { return; if (timeout.toSeconds() > Integer.MAX_VALUE) { throw new IllegalArgumentException("Timeout in seconds must be less or equal to " + Integer.MAX_VALUE); } try { mServiceLock.readLock().lock(); if (mService != null) { mService.setDiscoverableTimeout(timeout, mAttributionSource); return mService.setDiscoverableTimeout(timeout.toSeconds(), mAttributionSource); } } catch (RemoteException e) { Log.e(TAG, "", e); throw e.rethrowFromSystemServer(); } finally { mServiceLock.readLock().unlock(); } return BluetoothStatusCodes.ERROR_UNKNOWN; } /** Loading
framework/java/android/bluetooth/BluetoothStatusCodes.java +1 −1 Original line number Diff line number Diff line Loading @@ -40,7 +40,7 @@ public final class BluetoothStatusCodes { /** * Error code indicating that the API call was initiated by neither the system nor the active * Zuser * user */ public static final int ERROR_BLUETOOTH_NOT_ALLOWED = 2; Loading
framework/tests/src/android/bluetooth/BluetoothTestUtils.java +4 −2 Original line number Diff line number Diff line Loading @@ -587,7 +587,8 @@ public class BluetoothTestUtils extends Assert { final IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED); mContext.registerReceiver(receiver, filter); assertTrue(adapter.setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE)); assertEquals(adapter.setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE), BluetoothStatusCodes.SUCCESS); boolean success = false; try { success = completionSemaphore.tryAcquire(DISCOVERABLE_UNDISCOVERABLE_TIMEOUT, Loading Loading @@ -637,7 +638,8 @@ public class BluetoothTestUtils extends Assert { final IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED); mContext.registerReceiver(receiver, filter); assertTrue(adapter.setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE)); assertEquals(adapter.setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE), BluetoothStatusCodes.SUCCESS); boolean success = false; try { success = completionSemaphore.tryAcquire(DISCOVERABLE_UNDISCOVERABLE_TIMEOUT, Loading