Refactor Bluetooth scan mode APIs
Removed setScanMode(int, long), setScanMode(int mode) is now a SystemApi. Made getDiscoverableTimeout a public API. setDiscoverableTimeout is now SystemApi and takes java.time.Duration as parameter. Tag: #feature Bug: 195150096 Test: Manual Change-Id: I824b24464987e1db87efc193d30452a6d9d0411e
This commit is contained in:
@@ -8718,6 +8718,7 @@ package android.bluetooth {
|
||||
method public android.bluetooth.le.BluetoothLeScanner getBluetoothLeScanner();
|
||||
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public java.util.Set<android.bluetooth.BluetoothDevice> getBondedDevices();
|
||||
method @Deprecated public static android.bluetooth.BluetoothAdapter getDefaultAdapter();
|
||||
method @Nullable @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) public java.time.Duration getDiscoverableTimeout();
|
||||
method public int getLeMaximumAdvertisingDataLength();
|
||||
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public String getName();
|
||||
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public int getProfileConnectionState(int);
|
||||
|
||||
@@ -1999,6 +1999,8 @@ package android.bluetooth {
|
||||
method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED, android.Manifest.permission.MODIFY_PHONE_STATE}) public boolean removeActiveDevice(int);
|
||||
method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public boolean removeOnMetadataChangedListener(@NonNull android.bluetooth.BluetoothDevice, @NonNull android.bluetooth.BluetoothAdapter.OnMetadataChangedListener);
|
||||
method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED, android.Manifest.permission.MODIFY_PHONE_STATE}) public boolean setActiveDevice(@NonNull android.bluetooth.BluetoothDevice, int);
|
||||
method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_SCAN, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public int setDiscoverableTimeout(@NonNull java.time.Duration);
|
||||
method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_SCAN, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public int setScanMode(int);
|
||||
field public static final String ACTION_BLE_STATE_CHANGED = "android.bluetooth.adapter.action.BLE_STATE_CHANGED";
|
||||
field public static final String ACTION_REQUEST_BLE_SCAN_ALWAYS_AVAILABLE = "android.bluetooth.adapter.action.REQUEST_BLE_SCAN_ALWAYS_AVAILABLE";
|
||||
field public static final int ACTIVE_DEVICE_ALL = 2; // 0x2
|
||||
|
||||
@@ -69,6 +69,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;
|
||||
@@ -402,6 +403,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
|
||||
@@ -1618,7 +1629,7 @@ public final class BluetoothAdapter {
|
||||
return mService.getScanMode(mAttributionSource);
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "", e);
|
||||
throw e.rethrowFromSystemServer();
|
||||
} finally {
|
||||
mServiceLock.readLock().unlock();
|
||||
}
|
||||
@@ -1626,143 +1637,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.
|
||||
* {@link #ACTION_REQUEST_DISCOVERABLE} 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
|
||||
* @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
|
||||
* @return the duration of the discoverable timeout or null if an error has occurred
|
||||
*/
|
||||
@RequiresBluetoothScanPermission
|
||||
@RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
|
||||
public @Nullable Duration getDiscoverableTimeout() {
|
||||
if (getState() != STATE_ON) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
mServiceLock.readLock().lock();
|
||||
if (mService != null) {
|
||||
long timeout = mService.getDiscoverableTimeout(mAttributionSource);
|
||||
return (timeout == -1) ? null : Duration.ofSeconds(timeout);
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
} finally {
|
||||
mServiceLock.readLock().unlock();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
@UnsupportedAppUsage
|
||||
@RequiresLegacyBluetoothPermission
|
||||
@SystemApi
|
||||
@RequiresBluetoothScanPermission
|
||||
@RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
|
||||
public boolean setScanMode(@ScanMode int mode) {
|
||||
@RequiresPermission(allOf = {
|
||||
android.Manifest.permission.BLUETOOTH_SCAN,
|
||||
android.Manifest.permission.BLUETOOTH_PRIVILEGED,
|
||||
})
|
||||
@ScanModeStatusCode
|
||||
public int setDiscoverableTimeout(@NonNull Duration timeout) {
|
||||
if (getState() != STATE_ON) {
|
||||
return false;
|
||||
return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED;
|
||||
}
|
||||
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) {
|
||||
return mService.setScanMode(mode, getDiscoverableTimeout(), mAttributionSource);
|
||||
return mService.setDiscoverableTimeout(timeout.toSeconds(), mAttributionSource);
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "", e);
|
||||
} finally {
|
||||
mServiceLock.readLock().unlock();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
@UnsupportedAppUsage
|
||||
@RequiresBluetoothScanPermission
|
||||
@RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
|
||||
public int getDiscoverableTimeout() {
|
||||
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 -1;
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
@UnsupportedAppUsage
|
||||
@RequiresBluetoothScanPermission
|
||||
@RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
|
||||
public void setDiscoverableTimeout(int timeout) {
|
||||
if (getState() != STATE_ON) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
mServiceLock.readLock().lock();
|
||||
if (mService != null) {
|
||||
mService.setDiscoverableTimeout(timeout, mAttributionSource);
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "", e);
|
||||
throw e.rethrowFromSystemServer();
|
||||
} finally {
|
||||
mServiceLock.readLock().unlock();
|
||||
}
|
||||
return BluetoothStatusCodes.ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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,
|
||||
@@ -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,
|
||||
|
||||
@@ -19,11 +19,13 @@ package com.android.settingslib.bluetooth;
|
||||
import android.bluetooth.BluetoothAdapter;
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
import android.bluetooth.BluetoothProfile;
|
||||
import android.bluetooth.BluetoothStatusCodes;
|
||||
import android.bluetooth.le.BluetoothLeScanner;
|
||||
import android.content.Context;
|
||||
import android.os.ParcelUuid;
|
||||
import android.util.Log;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
@@ -140,7 +142,7 @@ public class LocalBluetoothAdapter {
|
||||
}
|
||||
|
||||
public void setDiscoverableTimeout(int timeout) {
|
||||
mAdapter.setDiscoverableTimeout(timeout);
|
||||
mAdapter.setDiscoverableTimeout(Duration.ofSeconds(timeout));
|
||||
}
|
||||
|
||||
public long getDiscoveryEndMillis() {
|
||||
@@ -156,7 +158,9 @@ public class LocalBluetoothAdapter {
|
||||
}
|
||||
|
||||
public boolean setScanMode(int mode, int duration) {
|
||||
return mAdapter.setScanMode(mode, duration);
|
||||
return (mAdapter.setDiscoverableTimeout(Duration.ofSeconds(duration))
|
||||
== BluetoothStatusCodes.SUCCESS
|
||||
&& mAdapter.setScanMode(mode) == BluetoothStatusCodes.SUCCESS);
|
||||
}
|
||||
|
||||
public void startScanning(boolean force) {
|
||||
|
||||
Reference in New Issue
Block a user