From 6eed56ddd395e528c420c07c5f2ab0881dcd5f26 Mon Sep 17 00:00:00 2001
From: Jeff Sharkey
Date: Fri, 16 Apr 2021 09:53:23 -0600
Subject: [PATCH] More Bluetooth API annotation updates.
This change adds a "BluetoothPermissionChecker" that ensures that
all Bluetooth permission annotations are consistent. In addition, it
verifies that all Bluetooth public APIs have been audited to be
permission protected where relevant.
We've currently standardized on saying that APIs that return device
or Bluetooth state information (without sharing details about any
particular remote Bluetooth device) do not need to be permission
protected.
This change is only annotations and has no behavior changes.
Bug: 183626724
Test: ./build/soong/soong_ui.bash --make-mode Bluetooth RUN_ERROR_PRONE=true
Change-Id: Ie80b15b058359bf1e9a6ee881b89cb3e5b584ca1
---
Android.bp | 1 +
core/java/Android.bp | 1 +
.../annotation/RequiresNoPermission.java | 36 +++
.../java/android/bluetooth/BluetoothA2dp.java | 6 +
.../android/bluetooth/BluetoothA2dpSink.java | 2 +
.../android/bluetooth/BluetoothAdapter.java | 56 ++++-
.../java/android/bluetooth/BluetoothGatt.java | 23 +-
.../bluetooth/BluetoothGattServer.java | 12 +
.../android/bluetooth/BluetoothHeadset.java | 16 ++
.../bluetooth/BluetoothHeadsetClient.java | 24 +-
.../bluetooth/BluetoothHearingAid.java | 7 +
.../android/bluetooth/BluetoothHidDevice.java | 13 ++
.../android/bluetooth/BluetoothHidHost.java | 3 +
.../bluetooth/BluetoothInputStream.java | 3 +
.../android/bluetooth/BluetoothLeAudio.java | 7 +
.../android/bluetooth/BluetoothManager.java | 7 +
core/java/android/bluetooth/BluetoothMap.java | 14 ++
.../android/bluetooth/BluetoothMapClient.java | 17 ++
.../bluetooth/BluetoothOutputStream.java | 3 +
core/java/android/bluetooth/BluetoothPan.java | 6 +
.../java/android/bluetooth/BluetoothPbap.java | 6 +
.../bluetooth/BluetoothPbapClient.java | 4 +
.../android/bluetooth/BluetoothProfile.java | 3 +
.../bluetooth/BluetoothProfileConnector.java | 2 +-
core/java/android/bluetooth/BluetoothSap.java | 13 ++
.../bluetooth/BluetoothServerSocket.java | 2 +
.../android/bluetooth/BluetoothSocket.java | 13 +-
.../java/android/bluetooth/BluetoothUuid.java | 2 +
.../android/bluetooth/le/AdvertisingSet.java | 3 +
.../bluetooth/le/BluetoothLeAdvertiser.java | 14 +-
.../bluetooth/le/BluetoothLeScanner.java | 12 +-
.../le/PeriodicAdvertisingManager.java | 2 +
.../java/android/bluetooth/le/ScanFilter.java | 1 -
.../java/android/bluetooth/le/ScanRecord.java | 2 +
.../android/bluetooth/le/TruncatedFilter.java | 2 +
.../annotation/RequiresNoPermission.java | 36 +++
.../annotation/RequiresPermission.java | 136 +++++++++++
.../android/BluetoothPermissionChecker.java | 213 ++++++++++++++++++
.../android/RequiresPermissionChecker.java | 15 +-
39 files changed, 711 insertions(+), 27 deletions(-)
create mode 100644 core/java/android/annotation/RequiresNoPermission.java
create mode 100644 errorprone/java/android/annotation/RequiresNoPermission.java
create mode 100644 errorprone/java/android/annotation/RequiresPermission.java
create mode 100644 errorprone/java/com/google/errorprone/bugpatterns/android/BluetoothPermissionChecker.java
diff --git a/Android.bp b/Android.bp
index ca014bc7b11c1..da52c2320048e 100644
--- a/Android.bp
+++ b/Android.bp
@@ -408,6 +408,7 @@ filegroup {
"core/java/android/annotation/MainThread.java",
"core/java/android/annotation/NonNull.java",
"core/java/android/annotation/Nullable.java",
+ "core/java/android/annotation/RequiresNoPermission.java",
"core/java/android/annotation/RequiresPermission.java",
"core/java/android/annotation/SdkConstant.java",
"core/java/android/annotation/StringDef.java",
diff --git a/core/java/Android.bp b/core/java/Android.bp
index 1d290def0bf24..c8a8d36a1b202 100644
--- a/core/java/Android.bp
+++ b/core/java/Android.bp
@@ -70,6 +70,7 @@ filegroup {
"android/annotation/Nullable.java",
"android/annotation/PluralsRes.java",
"android/annotation/RawRes.java",
+ "android/annotation/RequiresNoPermission.java",
"android/annotation/RequiresPermission.java",
"android/annotation/SdkConstant.java",
"android/annotation/Size.java",
diff --git a/core/java/android/annotation/RequiresNoPermission.java b/core/java/android/annotation/RequiresNoPermission.java
new file mode 100644
index 0000000000000..6ff4d6e34957e
--- /dev/null
+++ b/core/java/android/annotation/RequiresNoPermission.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.annotation;
+
+import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
+import static java.lang.annotation.ElementType.CONSTRUCTOR;
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.RetentionPolicy.CLASS;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * Denotes that the annotated element requires no permissions.
+ *
+ * @hide
+ */
+@Retention(CLASS)
+@Target({ANNOTATION_TYPE,METHOD,CONSTRUCTOR,FIELD,PARAMETER})
+public @interface RequiresNoPermission {
+}
diff --git a/core/java/android/bluetooth/BluetoothA2dp.java b/core/java/android/bluetooth/BluetoothA2dp.java
index a268e168ae744..0d21e09293b3c 100644
--- a/core/java/android/bluetooth/BluetoothA2dp.java
+++ b/core/java/android/bluetooth/BluetoothA2dp.java
@@ -20,8 +20,10 @@ import android.Manifest;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.RequiresNoPermission;
import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
+import android.annotation.SuppressLint;
import android.annotation.SdkConstant.SdkConstantType;
import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
import android.bluetooth.annotations.RequiresLegacyBluetoothAdminPermission;
@@ -512,6 +514,7 @@ public final class BluetoothA2dp implements BluetoothProfile {
* @return true if priority is set, false on error
* @hide
*/
+ @RequiresBluetoothConnectPermission
@RequiresPermission(allOf = {
android.Manifest.permission.BLUETOOTH_CONNECT,
android.Manifest.permission.BLUETOOTH_PRIVILEGED,
@@ -534,6 +537,7 @@ public final class BluetoothA2dp implements BluetoothProfile {
* @hide
*/
@SystemApi
+ @RequiresBluetoothConnectPermission
@RequiresPermission(allOf = {
android.Manifest.permission.BLUETOOTH_CONNECT,
android.Manifest.permission.BLUETOOTH_PRIVILEGED,
@@ -624,6 +628,7 @@ public final class BluetoothA2dp implements BluetoothProfile {
* @return true if device supports absolute volume
* @hide
*/
+ @RequiresNoPermission
public boolean isAvrcpAbsoluteVolumeSupported() {
if (DBG) Log.d(TAG, "isAvrcpAbsoluteVolumeSupported");
try {
@@ -690,6 +695,7 @@ public final class BluetoothA2dp implements BluetoothProfile {
*
* @hide
*/
+ @RequiresBluetoothConnectPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean shouldSendVolumeKeys(BluetoothDevice device) {
if (isEnabled() && isValidDevice(device)) {
diff --git a/core/java/android/bluetooth/BluetoothA2dpSink.java b/core/java/android/bluetooth/BluetoothA2dpSink.java
index d81316e357d32..6aba483b15158 100755
--- a/core/java/android/bluetooth/BluetoothA2dpSink.java
+++ b/core/java/android/bluetooth/BluetoothA2dpSink.java
@@ -282,6 +282,7 @@ public final class BluetoothA2dpSink implements BluetoothProfile {
* @return true if priority is set, false on error
* @hide
*/
+ @RequiresBluetoothConnectPermission
@RequiresPermission(allOf = {
android.Manifest.permission.BLUETOOTH_CONNECT,
android.Manifest.permission.BLUETOOTH_PRIVILEGED,
@@ -304,6 +305,7 @@ public final class BluetoothA2dpSink implements BluetoothProfile {
* @hide
*/
@SystemApi
+ @RequiresBluetoothConnectPermission
@RequiresPermission(allOf = {
android.Manifest.permission.BLUETOOTH_CONNECT,
android.Manifest.permission.BLUETOOTH_PRIVILEGED
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index df2c512ebf6e6..052a7733c220c 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -21,6 +21,7 @@ import android.annotation.CallbackExecutor;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.RequiresNoPermission;
import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
@@ -716,6 +717,7 @@ public final class BluetoothAdapter {
* Bluetooth metadata listener. Overrides the default BluetoothMetadataListener
* implementation.
*/
+ @SuppressLint("AndroidFrameworkBluetoothPermission")
private static final IBluetoothMetadataListener sBluetoothMetadataListener =
new IBluetoothMetadataListener.Stub() {
@Override
@@ -747,6 +749,7 @@ public final class BluetoothAdapter {
* @return the default local adapter, or null if Bluetooth is not supported on this hardware
* platform
*/
+ @RequiresNoPermission
public static synchronized BluetoothAdapter getDefaultAdapter() {
if (sAdapter == null) {
IBinder b = ServiceManager.getService(BLUETOOTH_MANAGER_SERVICE);
@@ -792,6 +795,7 @@ public final class BluetoothAdapter {
* @param address valid Bluetooth MAC address
* @throws IllegalArgumentException if address is invalid
*/
+ @RequiresNoPermission
public BluetoothDevice getRemoteDevice(String address) {
return new BluetoothDevice(address);
}
@@ -807,6 +811,7 @@ public final class BluetoothAdapter {
* @param address Bluetooth MAC address (6 bytes)
* @throws IllegalArgumentException if address is invalid
*/
+ @RequiresNoPermission
public BluetoothDevice getRemoteDevice(byte[] address) {
if (address == null || address.length != 6) {
throw new IllegalArgumentException("Bluetooth address must have 6 bytes");
@@ -824,6 +829,7 @@ public final class BluetoothAdapter {
* Use {@link #isMultipleAdvertisementSupported()} to check whether LE Advertising is supported
* on this device before calling this method.
*/
+ @RequiresNoPermission
public BluetoothLeAdvertiser getBluetoothLeAdvertiser() {
if (!getLeAccess()) {
return null;
@@ -846,6 +852,7 @@ public final class BluetoothAdapter {
*
* @hide
*/
+ @RequiresNoPermission
public PeriodicAdvertisingManager getPeriodicAdvertisingManager() {
if (!getLeAccess()) {
return null;
@@ -866,6 +873,7 @@ public final class BluetoothAdapter {
/**
* Returns a {@link BluetoothLeScanner} object for Bluetooth LE scan operations.
*/
+ @RequiresNoPermission
public BluetoothLeScanner getBluetoothLeScanner() {
if (!getLeAccess()) {
return null;
@@ -887,6 +895,7 @@ public final class BluetoothAdapter {
* @return true if the local adapter is turned on
*/
@RequiresLegacyBluetoothPermission
+ @RequiresNoPermission
public boolean isEnabled() {
return getState() == BluetoothAdapter.STATE_ON;
}
@@ -900,6 +909,7 @@ public final class BluetoothAdapter {
* @hide
*/
@SystemApi
+ @RequiresNoPermission
public boolean isLeEnabled() {
final int state = getLeState();
if (DBG) {
@@ -937,6 +947,7 @@ public final class BluetoothAdapter {
* @hide
*/
@SystemApi
+ @RequiresBluetoothConnectPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean disableBLE() {
if (!isBleScanAlwaysAvailable()) {
@@ -983,6 +994,7 @@ public final class BluetoothAdapter {
* @hide
*/
@SystemApi
+ @RequiresBluetoothConnectPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean enableBLE() {
if (!isBleScanAlwaysAvailable()) {
@@ -1015,6 +1027,7 @@ public final class BluetoothAdapter {
};
/** @hide */
+ @RequiresNoPermission
public void disableBluetoothGetStateCache() {
mBluetoothGetStateCache.disableLocal();
}
@@ -1059,6 +1072,7 @@ public final class BluetoothAdapter {
* @return current state of Bluetooth adapter
*/
@RequiresLegacyBluetoothPermission
+ @RequiresNoPermission
@AdapterState
public int getState() {
int state = getStateInternal();
@@ -1095,6 +1109,7 @@ public final class BluetoothAdapter {
* @hide
*/
@RequiresLegacyBluetoothPermission
+ @RequiresNoPermission
@AdapterState
@UnsupportedAppUsage(publicAlternatives = "Use {@link #getState()} instead to determine "
+ "whether you can use BLE & BT classic.")
@@ -1649,6 +1664,7 @@ public final class BluetoothAdapter {
/** @hide */
@UnsupportedAppUsage
+ @RequiresBluetoothScanPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
public int getDiscoverableTimeout() {
if (getState() != STATE_ON) {
@@ -1669,6 +1685,7 @@ public final class BluetoothAdapter {
/** @hide */
@UnsupportedAppUsage
+ @RequiresBluetoothScanPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
public void setDiscoverableTimeout(int timeout) {
if (getState() != STATE_ON) {
@@ -1714,6 +1731,7 @@ public final class BluetoothAdapter {
* Set the context for this BluetoothAdapter (only called from BluetoothManager)
* @hide
*/
+ @RequiresNoPermission
public void setContext(Context context) {
mContext = context;
}
@@ -1872,6 +1890,7 @@ public final class BluetoothAdapter {
* @hide
*/
@SystemApi
+ @RequiresBluetoothConnectPermission
@RequiresPermission(allOf = {
android.Manifest.permission.BLUETOOTH_CONNECT,
android.Manifest.permission.BLUETOOTH_PRIVILEGED,
@@ -1916,6 +1935,7 @@ public final class BluetoothAdapter {
* @hide
*/
@SystemApi
+ @RequiresBluetoothConnectPermission
@RequiresPermission(allOf = {
android.Manifest.permission.BLUETOOTH_CONNECT,
android.Manifest.permission.BLUETOOTH_PRIVILEGED,
@@ -1964,6 +1984,7 @@ public final class BluetoothAdapter {
*
* @hide
*/
+ @RequiresBluetoothConnectPermission
@RequiresPermission(allOf = {
android.Manifest.permission.BLUETOOTH_CONNECT,
android.Manifest.permission.BLUETOOTH_PRIVILEGED,
@@ -1996,6 +2017,7 @@ public final class BluetoothAdapter {
*
* @hide
*/
+ @RequiresBluetoothConnectPermission
@RequiresPermission(allOf = {
android.Manifest.permission.BLUETOOTH_CONNECT,
android.Manifest.permission.BLUETOOTH_PRIVILEGED,
@@ -2021,6 +2043,7 @@ public final class BluetoothAdapter {
* @return true if Multiple Advertisement feature is supported
*/
@RequiresLegacyBluetoothPermission
+ @RequiresNoPermission
public boolean isMultipleAdvertisementSupported() {
if (getState() != STATE_ON) {
return false;
@@ -2049,6 +2072,7 @@ public final class BluetoothAdapter {
* @hide
*/
@SystemApi
+ @RequiresNoPermission
public boolean isBleScanAlwaysAvailable() {
try {
return mManagerService.isBleScanAlwaysAvailable();
@@ -2082,6 +2106,7 @@ public final class BluetoothAdapter {
};
/** @hide */
+ @RequiresNoPermission
public void disableIsOffloadedFilteringSupportedCache() {
mBluetoothFilteringCache.disableLocal();
}
@@ -2097,6 +2122,7 @@ public final class BluetoothAdapter {
* @return true if chipset supports on-chip filtering
*/
@RequiresLegacyBluetoothPermission
+ @RequiresNoPermission
public boolean isOffloadedFilteringSupported() {
if (!getLeAccess()) {
return false;
@@ -2110,6 +2136,7 @@ public final class BluetoothAdapter {
* @return true if chipset supports on-chip scan batching
*/
@RequiresLegacyBluetoothPermission
+ @RequiresNoPermission
public boolean isOffloadedScanBatchingSupported() {
if (!getLeAccess()) {
return false;
@@ -2133,6 +2160,7 @@ public final class BluetoothAdapter {
* @return true if chipset supports LE 2M PHY feature
*/
@RequiresLegacyBluetoothPermission
+ @RequiresNoPermission
public boolean isLe2MPhySupported() {
if (!getLeAccess()) {
return false;
@@ -2156,6 +2184,7 @@ public final class BluetoothAdapter {
* @return true if chipset supports LE Coded PHY feature
*/
@RequiresLegacyBluetoothPermission
+ @RequiresNoPermission
public boolean isLeCodedPhySupported() {
if (!getLeAccess()) {
return false;
@@ -2179,6 +2208,7 @@ public final class BluetoothAdapter {
* @return true if chipset supports LE Extended Advertising feature
*/
@RequiresLegacyBluetoothPermission
+ @RequiresNoPermission
public boolean isLeExtendedAdvertisingSupported() {
if (!getLeAccess()) {
return false;
@@ -2202,6 +2232,7 @@ public final class BluetoothAdapter {
* @return true if chipset supports LE Periodic Advertising feature
*/
@RequiresLegacyBluetoothPermission
+ @RequiresNoPermission
public boolean isLePeriodicAdvertisingSupported() {
if (!getLeAccess()) {
return false;
@@ -2226,6 +2257,7 @@ public final class BluetoothAdapter {
* @return the maximum LE advertising data length.
*/
@RequiresLegacyBluetoothPermission
+ @RequiresNoPermission
public int getLeMaximumAdvertisingDataLength() {
if (!getLeAccess()) {
return 0;
@@ -2248,6 +2280,7 @@ public final class BluetoothAdapter {
*
* @return true if phone supports Hearing Aid Profile
*/
+ @RequiresNoPermission
private boolean isHearingAidProfileSupported() {
try {
return mManagerService.isHearingAidProfileSupported();
@@ -2286,6 +2319,7 @@ public final class BluetoothAdapter {
* @return true if there are hw entries available for matching beacons
* @hide
*/
+ @RequiresBluetoothConnectPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean isHardwareTrackingFiltersAvailable() {
if (!getLeAccess()) {
@@ -2432,6 +2466,7 @@ public final class BluetoothAdapter {
* BluetoothProfile}.
* @hide
*/
+ @RequiresNoPermission
public @NonNull List getSupportedProfiles() {
final ArrayList supportedProfiles = new ArrayList();
@@ -2479,6 +2514,7 @@ public final class BluetoothAdapter {
};
/** @hide */
+ @RequiresNoPermission
public void disableGetAdapterConnectionStateCache() {
mBluetoothGetAdapterConnectionStateCache.disableLocal();
}
@@ -2503,6 +2539,7 @@ public final class BluetoothAdapter {
*/
@UnsupportedAppUsage
@RequiresLegacyBluetoothPermission
+ @RequiresNoPermission
public int getConnectionState() {
if (getState() != STATE_ON) {
return BluetoothAdapter.STATE_DISCONNECTED;
@@ -2553,6 +2590,7 @@ public final class BluetoothAdapter {
};
/** @hide */
+ @RequiresNoPermission
public void disableGetProfileConnectionStateCache() {
mGetProfileConnectionStateCache.disableLocal();
}
@@ -2753,6 +2791,7 @@ public final class BluetoothAdapter {
return createNewRfcommSocketAndRecord(name, uuid, false, true);
}
+ @RequiresBluetoothConnectPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
private BluetoothServerSocket createNewRfcommSocketAndRecord(String name, UUID uuid,
boolean auth, boolean encrypt) throws IOException {
@@ -2779,6 +2818,7 @@ public final class BluetoothAdapter {
* permissions.
* @hide
*/
+ @RequiresBluetoothConnectPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public BluetoothServerSocket listenUsingInsecureRfcommOn(int port) throws IOException {
BluetoothServerSocket socket =
@@ -2811,6 +2851,7 @@ public final class BluetoothAdapter {
* permissions.
* @hide
*/
+ @RequiresBluetoothConnectPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public BluetoothServerSocket listenUsingL2capOn(int port, boolean mitm, boolean min16DigitPin)
throws IOException {
@@ -2844,6 +2885,7 @@ public final class BluetoothAdapter {
* permissions.
* @hide
*/
+ @RequiresBluetoothConnectPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public BluetoothServerSocket listenUsingL2capOn(int port) throws IOException {
return listenUsingL2capOn(port, false, false);
@@ -2861,6 +2903,7 @@ public final class BluetoothAdapter {
* permissions.
* @hide
*/
+ @RequiresBluetoothConnectPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public BluetoothServerSocket listenUsingInsecureL2capOn(int port) throws IOException {
Log.d(TAG, "listenUsingInsecureL2capOn: port=" + port);
@@ -2916,6 +2959,10 @@ public final class BluetoothAdapter {
* BluetoothProfile#HEARING_AID} or {@link BluetoothProfile#GATT_SERVER}.
* @return true on success, false on error
*/
+ @SuppressLint({
+ "AndroidFrameworkRequiresPermission",
+ "AndroidFrameworkBluetoothPermission"
+ })
public boolean getProfileProxy(Context context, BluetoothProfile.ServiceListener listener,
int profile) {
if (context == null || listener == null) {
@@ -2985,7 +3032,10 @@ public final class BluetoothAdapter {
* @param profile
* @param proxy Profile proxy object
*/
- @SuppressLint("AndroidFrameworkRequiresPermission")
+ @SuppressLint({
+ "AndroidFrameworkRequiresPermission",
+ "AndroidFrameworkBluetoothPermission"
+ })
public void closeProfileProxy(int profile, BluetoothProfile proxy) {
if (proxy == null) {
return;
@@ -3058,6 +3108,7 @@ public final class BluetoothAdapter {
}
}
+ @SuppressLint("AndroidFrameworkBluetoothPermission")
private final IBluetoothManagerCallback mManagerCallback =
new IBluetoothManagerCallback.Stub() {
@SuppressLint("AndroidFrameworkRequiresPermission")
@@ -3380,7 +3431,6 @@ public final class BluetoothAdapter {
/**
* @hide
*/
- @SuppressLint("AndroidFrameworkRequiresPermission")
public class StateChangeCallbackWrapper extends IBluetoothStateChangeCallback.Stub {
private BluetoothStateChangeCallback mCallback;
@@ -3631,6 +3681,7 @@ public final class BluetoothAdapter {
return false;
}
+ @SuppressLint("AndroidFrameworkBluetoothPermission")
ScanCallback scanCallback = new ScanCallback() {
@Override
public void onScanResult(int callbackType, ScanResult result) {
@@ -3961,6 +4012,7 @@ public final class BluetoothAdapter {
@Nullable byte[] value);
}
+ @SuppressLint("AndroidFrameworkBluetoothPermission")
private final IBluetoothConnectionCallback mConnectionCallback =
new IBluetoothConnectionCallback.Stub() {
@Override
diff --git a/core/java/android/bluetooth/BluetoothGatt.java b/core/java/android/bluetooth/BluetoothGatt.java
index 942f8432639cc..9d3eed8f6fa19 100644
--- a/core/java/android/bluetooth/BluetoothGatt.java
+++ b/core/java/android/bluetooth/BluetoothGatt.java
@@ -16,15 +16,12 @@
package android.bluetooth;
-import android.compat.annotation.UnsupportedAppUsage;
+import android.annotation.RequiresNoPermission;
import android.annotation.RequiresPermission;
import android.annotation.SuppressLint;
-import android.annotation.RequiresPermission;
-import android.bluetooth.annotations.RequiresLegacyBluetoothAdminPermission;
import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
-import android.bluetooth.annotations.RequiresBluetoothLocationPermission;
import android.bluetooth.annotations.RequiresLegacyBluetoothPermission;
-import android.bluetooth.annotations.RequiresBluetoothScanPermission;
+import android.compat.annotation.UnsupportedAppUsage;
import android.os.Build;
import android.os.Handler;
import android.os.ParcelUuid;
@@ -158,6 +155,7 @@ public final class BluetoothGatt implements BluetoothProfile {
/**
* Bluetooth GATT callbacks. Overrides the default BluetoothGattCallback implementation.
*/
+ @SuppressLint("AndroidFrameworkBluetoothPermission")
private final IBluetoothGattCallback mBluetoothGattCallback =
new IBluetoothGattCallback.Stub() {
/**
@@ -747,6 +745,7 @@ public final class BluetoothGatt implements BluetoothProfile {
* Application should call this method as early as possible after it is done with
* this GATT client.
*/
+ @RequiresBluetoothConnectPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public void close() {
if (DBG) Log.d(TAG, "close()");
@@ -881,6 +880,7 @@ public final class BluetoothGatt implements BluetoothProfile {
* Unregister the current application and callbacks.
*/
@UnsupportedAppUsage
+ @RequiresBluetoothConnectPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
private void unregisterApp() {
if (DBG) Log.d(TAG, "unregisterApp() - mClientIf=" + mClientIf);
@@ -973,6 +973,7 @@ public final class BluetoothGatt implements BluetoothProfile {
*
* @return true, if the connection attempt was initiated successfully
*/
+ @RequiresBluetoothConnectPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean connect() {
try {
@@ -1003,6 +1004,7 @@ public final class BluetoothGatt implements BluetoothProfile {
* of {@link BluetoothDevice#PHY_OPTION_NO_PREFERRED}, {@link BluetoothDevice#PHY_OPTION_S2} or
* {@link BluetoothDevice#PHY_OPTION_S8}
*/
+ @RequiresBluetoothConnectPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public void setPreferredPhy(int txPhy, int rxPhy, int phyOptions) {
try {
@@ -1017,6 +1019,7 @@ public final class BluetoothGatt implements BluetoothProfile {
* Read the current transmitter PHY and receiver PHY of the connection. The values are returned
* in {@link BluetoothGattCallback#onPhyRead}
*/
+ @RequiresBluetoothConnectPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public void readPhy() {
try {
@@ -1031,6 +1034,7 @@ public final class BluetoothGatt implements BluetoothProfile {
*
* @return remote bluetooth device
*/
+ @RequiresNoPermission
public BluetoothDevice getDevice() {
return mDevice;
}
@@ -1101,6 +1105,7 @@ public final class BluetoothGatt implements BluetoothProfile {
* not yet been performed.
*/
@RequiresLegacyBluetoothPermission
+ @RequiresNoPermission
public List getServices() {
List result =
new ArrayList();
@@ -1129,6 +1134,7 @@ public final class BluetoothGatt implements BluetoothProfile {
* the remote device.
*/
@RequiresLegacyBluetoothPermission
+ @RequiresNoPermission
public BluetoothGattService getService(UUID uuid) {
for (BluetoothGattService service : mServices) {
if (service.getDevice().equals(mDevice) && service.getUuid().equals(uuid)) {
@@ -1444,6 +1450,7 @@ public final class BluetoothGatt implements BluetoothProfile {
* @deprecated Use {@link #abortReliableWrite()}
*/
@Deprecated
+ @RequiresBluetoothConnectPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public void abortReliableWrite(BluetoothDevice mDevice) {
abortReliableWrite();
@@ -1496,6 +1503,7 @@ public final class BluetoothGatt implements BluetoothProfile {
* @hide
*/
@UnsupportedAppUsage
+ @RequiresBluetoothConnectPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean refresh() {
if (DBG) Log.d(TAG, "refresh() - device: " + mDevice.getAddress());
@@ -1579,6 +1587,7 @@ public final class BluetoothGatt implements BluetoothProfile {
* or {@link BluetoothGatt#CONNECTION_PRIORITY_LOW_POWER}.
* @throws IllegalArgumentException If the parameters are outside of their specified range.
*/
+ @RequiresBluetoothConnectPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean requestConnectionPriority(int connectionPriority) {
if (connectionPriority < CONNECTION_PRIORITY_BALANCED
@@ -1607,6 +1616,7 @@ public final class BluetoothGatt implements BluetoothProfile {
* @return true, if the request is send to the Bluetooth stack.
* @hide
*/
+ @RequiresBluetoothConnectPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean requestLeConnectionUpdate(int minConnectionInterval, int maxConnectionInterval,
int slaveLatency, int supervisionTimeout,
@@ -1641,6 +1651,7 @@ public final class BluetoothGatt implements BluetoothProfile {
* @throws UnsupportedOperationException
*/
@Override
+ @RequiresNoPermission
public int getConnectionState(BluetoothDevice device) {
throw new UnsupportedOperationException("Use BluetoothManager#getConnectionState instead.");
}
@@ -1652,6 +1663,7 @@ public final class BluetoothGatt implements BluetoothProfile {
* @throws UnsupportedOperationException
*/
@Override
+ @RequiresNoPermission
public List getConnectedDevices() {
throw new UnsupportedOperationException(
"Use BluetoothManager#getConnectedDevices instead.");
@@ -1665,6 +1677,7 @@ public final class BluetoothGatt implements BluetoothProfile {
* @throws UnsupportedOperationException
*/
@Override
+ @RequiresNoPermission
public List getDevicesMatchingConnectionStates(int[] states) {
throw new UnsupportedOperationException(
"Use BluetoothManager#getDevicesMatchingConnectionStates instead.");
diff --git a/core/java/android/bluetooth/BluetoothGattServer.java b/core/java/android/bluetooth/BluetoothGattServer.java
index fdb801850e8e6..865f476e78695 100644
--- a/core/java/android/bluetooth/BluetoothGattServer.java
+++ b/core/java/android/bluetooth/BluetoothGattServer.java
@@ -16,7 +16,9 @@
package android.bluetooth;
+import android.annotation.RequiresNoPermission;
import android.annotation.RequiresPermission;
+import android.annotation.SuppressLint;
import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
import android.bluetooth.annotations.RequiresLegacyBluetoothPermission;
import android.os.ParcelUuid;
@@ -58,6 +60,7 @@ public final class BluetoothGattServer implements BluetoothProfile {
/**
* Bluetooth GATT interface callbacks
*/
+ @SuppressLint("AndroidFrameworkBluetoothPermission")
private final IBluetoothGattServerCallback mBluetoothGattServerCallback =
new IBluetoothGattServerCallback.Stub() {
/**
@@ -428,6 +431,7 @@ public final class BluetoothGattServer implements BluetoothProfile {
* Application should call this method as early as possible after it is done with
* this GATT server.
*/
+ @RequiresBluetoothConnectPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public void close() {
if (DBG) Log.d(TAG, "close()");
@@ -510,6 +514,7 @@ public final class BluetoothGattServer implements BluetoothProfile {
/**
* Unregister the current application and callbacks.
*/
+ @RequiresBluetoothConnectPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
private void unregisterCallback() {
if (DBG) Log.d(TAG, "unregisterCallback() - mServerIf=" + mServerIf);
@@ -618,6 +623,7 @@ public final class BluetoothGattServer implements BluetoothProfile {
* of {@link BluetoothDevice#PHY_OPTION_NO_PREFERRED}, {@link BluetoothDevice#PHY_OPTION_S2} or
* {@link BluetoothDevice#PHY_OPTION_S8}
*/
+ @RequiresBluetoothConnectPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public void setPreferredPhy(BluetoothDevice device, int txPhy, int rxPhy, int phyOptions) {
try {
@@ -634,6 +640,7 @@ public final class BluetoothGattServer implements BluetoothProfile {
*
* @param device The remote device to send this response to
*/
+ @RequiresBluetoothConnectPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public void readPhy(BluetoothDevice device) {
try {
@@ -814,6 +821,7 @@ public final class BluetoothGattServer implements BluetoothProfile {
* @return List of services. Returns an empty list if no services have been added yet.
*/
@RequiresLegacyBluetoothPermission
+ @RequiresNoPermission
public List getServices() {
return mServices;
}
@@ -830,6 +838,7 @@ public final class BluetoothGattServer implements BluetoothProfile {
* this device.
*/
@RequiresLegacyBluetoothPermission
+ @RequiresNoPermission
public BluetoothGattService getService(UUID uuid) {
for (BluetoothGattService service : mServices) {
if (service.getUuid().equals(uuid)) {
@@ -848,6 +857,7 @@ public final class BluetoothGattServer implements BluetoothProfile {
* @throws UnsupportedOperationException
*/
@Override
+ @RequiresNoPermission
public int getConnectionState(BluetoothDevice device) {
throw new UnsupportedOperationException("Use BluetoothManager#getConnectionState instead.");
}
@@ -859,6 +869,7 @@ public final class BluetoothGattServer implements BluetoothProfile {
* @throws UnsupportedOperationException
*/
@Override
+ @RequiresNoPermission
public List getConnectedDevices() {
throw new UnsupportedOperationException(
"Use BluetoothManager#getConnectedDevices instead.");
@@ -872,6 +883,7 @@ public final class BluetoothGattServer implements BluetoothProfile {
* @throws UnsupportedOperationException
*/
@Override
+ @RequiresNoPermission
public List getDevicesMatchingConnectionStates(int[] states) {
throw new UnsupportedOperationException(
"Use BluetoothManager#getDevicesMatchingConnectionStates instead.");
diff --git a/core/java/android/bluetooth/BluetoothHeadset.java b/core/java/android/bluetooth/BluetoothHeadset.java
index 84e8c5134e7b0..a1ece7fc825d3 100644
--- a/core/java/android/bluetooth/BluetoothHeadset.java
+++ b/core/java/android/bluetooth/BluetoothHeadset.java
@@ -21,6 +21,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
+import android.annotation.SuppressLint;
import android.annotation.SdkConstant.SdkConstantType;
import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
import android.bluetooth.annotations.RequiresLegacyBluetoothAdminPermission;
@@ -339,6 +340,7 @@ public final class BluetoothHeadset implements BluetoothProfile {
private volatile IBluetoothHeadset mService;
private BluetoothAdapter mAdapter;
+ @SuppressLint("AndroidFrameworkBluetoothPermission")
private final IBluetoothStateChangeCallback mBluetoothStateChangeCallback =
new IBluetoothStateChangeCallback.Stub() {
public void onBluetoothStateChange(boolean up) {
@@ -509,6 +511,7 @@ public final class BluetoothHeadset implements BluetoothProfile {
* {@inheritDoc}
*/
@Override
+ @RequiresBluetoothConnectPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public List getConnectedDevices() {
if (VDBG) log("getConnectedDevices()");
@@ -529,6 +532,7 @@ public final class BluetoothHeadset implements BluetoothProfile {
* {@inheritDoc}
*/
@Override
+ @RequiresBluetoothConnectPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public List getDevicesMatchingConnectionStates(int[] states) {
if (VDBG) log("getDevicesMatchingStates()");
@@ -549,6 +553,7 @@ public final class BluetoothHeadset implements BluetoothProfile {
* {@inheritDoc}
*/
@Override
+ @RequiresBluetoothConnectPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public int getConnectionState(BluetoothDevice device) {
if (VDBG) log("getConnectionState(" + device + ")");
@@ -620,6 +625,7 @@ public final class BluetoothHeadset implements BluetoothProfile {
* @hide
*/
@SystemApi
+ @RequiresBluetoothConnectPermission
@RequiresPermission(allOf = {
android.Manifest.permission.BLUETOOTH_CONNECT,
android.Manifest.permission.BLUETOOTH_PRIVILEGED,
@@ -858,6 +864,7 @@ public final class BluetoothHeadset implements BluetoothProfile {
* @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+ @RequiresBluetoothConnectPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public int getAudioState(BluetoothDevice device) {
if (VDBG) log("getAudioState");
@@ -885,6 +892,7 @@ public final class BluetoothHeadset implements BluetoothProfile {
* @param allowed {@code true} if the profile can reroute audio, {@code false} otherwise.
* @hide
*/
+ @RequiresBluetoothConnectPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public void setAudioRouteAllowed(boolean allowed) {
if (VDBG) log("setAudioRouteAllowed");
@@ -907,6 +915,7 @@ public final class BluetoothHeadset implements BluetoothProfile {
*
* @hide
*/
+ @RequiresBluetoothConnectPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean getAudioRouteAllowed() {
if (VDBG) log("getAudioRouteAllowed");
@@ -931,6 +940,7 @@ public final class BluetoothHeadset implements BluetoothProfile {
* False to use SCO audio in normal manner
* @hide
*/
+ @RequiresBluetoothConnectPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public void setForceScoAudio(boolean forced) {
if (VDBG) log("setForceScoAudio " + String.valueOf(forced));
@@ -991,6 +1001,7 @@ public final class BluetoothHeadset implements BluetoothProfile {
* @hide
*/
@UnsupportedAppUsage
+ @RequiresBluetoothConnectPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean connectAudio() {
final IBluetoothHeadset service = mService;
@@ -1019,6 +1030,7 @@ public final class BluetoothHeadset implements BluetoothProfile {
* @hide
*/
@UnsupportedAppUsage
+ @RequiresBluetoothConnectPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean disconnectAudio() {
final IBluetoothHeadset service = mService;
@@ -1123,6 +1135,7 @@ public final class BluetoothHeadset implements BluetoothProfile {
* @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+ @RequiresBluetoothConnectPermission
@RequiresPermission(allOf = {
android.Manifest.permission.BLUETOOTH_CONNECT,
android.Manifest.permission.MODIFY_PHONE_STATE,
@@ -1147,6 +1160,7 @@ public final class BluetoothHeadset implements BluetoothProfile {
*
* @hide
*/
+ @RequiresBluetoothConnectPermission
@RequiresPermission(allOf = {
android.Manifest.permission.BLUETOOTH_CONNECT,
android.Manifest.permission.MODIFY_PHONE_STATE,
@@ -1320,6 +1334,7 @@ public final class BluetoothHeadset implements BluetoothProfile {
com.android.internal.R.bool.config_bluetooth_hfp_inband_ringing_support);
}
+ @SuppressLint("AndroidFrameworkBluetoothPermission")
private final IBluetoothProfileServiceConnection mConnection =
new IBluetoothProfileServiceConnection.Stub() {
@Override
@@ -1356,6 +1371,7 @@ public final class BluetoothHeadset implements BluetoothProfile {
Log.d(TAG, msg);
}
+ @SuppressLint("AndroidFrameworkBluetoothPermission")
private final Handler mHandler = new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(Message msg) {
diff --git a/core/java/android/bluetooth/BluetoothHeadsetClient.java b/core/java/android/bluetooth/BluetoothHeadsetClient.java
index 092130d0ce913..5816500d2c37d 100644
--- a/core/java/android/bluetooth/BluetoothHeadsetClient.java
+++ b/core/java/android/bluetooth/BluetoothHeadsetClient.java
@@ -16,7 +16,6 @@
package android.bluetooth;
-import android.Manifest;
import android.annotation.NonNull;
import android.annotation.RequiresPermission;
import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
@@ -449,6 +448,7 @@ public final class BluetoothHeadsetClient implements BluetoothProfile {
* @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+ @RequiresBluetoothConnectPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean connect(BluetoothDevice device) {
if (DBG) log("connect(" + device + ")");
@@ -476,6 +476,7 @@ public final class BluetoothHeadsetClient implements BluetoothProfile {
* @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+ @RequiresBluetoothConnectPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean disconnect(BluetoothDevice device) {
if (DBG) log("disconnect(" + device + ")");
@@ -499,6 +500,7 @@ public final class BluetoothHeadsetClient implements BluetoothProfile {
* @return list of connected devices; empty list if nothing is connected.
*/
@Override
+ @RequiresBluetoothConnectPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public List getConnectedDevices() {
if (VDBG) log("getConnectedDevices()");
@@ -524,6 +526,7 @@ public final class BluetoothHeadsetClient implements BluetoothProfile {
* list if nothing matches the states
*/
@Override
+ @RequiresBluetoothConnectPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public List getDevicesMatchingConnectionStates(int[] states) {
if (VDBG) log("getDevicesMatchingStates()");
@@ -548,6 +551,7 @@ public final class BluetoothHeadsetClient implements BluetoothProfile {
* @return the state of connection of the device
*/
@Override
+ @RequiresBluetoothConnectPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public int getConnectionState(BluetoothDevice device) {
if (VDBG) log("getConnectionState(" + device + ")");
@@ -576,6 +580,7 @@ public final class BluetoothHeadsetClient implements BluetoothProfile {
* @return true if priority is set, false on error
* @hide
*/
+ @RequiresBluetoothConnectPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean setPriority(BluetoothDevice device, int priority) {
if (DBG) log("setPriority(" + device + ", " + priority + ")");
@@ -594,6 +599,7 @@ public final class BluetoothHeadsetClient implements BluetoothProfile {
* @return true if connectionPolicy is set, false on error
* @hide
*/
+ @RequiresBluetoothConnectPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean setConnectionPolicy(@NonNull BluetoothDevice device,
@ConnectionPolicy int connectionPolicy) {
@@ -675,6 +681,7 @@ public final class BluetoothHeadsetClient implements BluetoothProfile {
* #EXTRA_AG_FEATURE_VOICE_RECOGNITION}. This method invocation will fail silently when feature
* is not supported.
*/
+ @RequiresBluetoothConnectPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean startVoiceRecognition(BluetoothDevice device) {
if (DBG) log("startVoiceRecognition()");
@@ -700,6 +707,7 @@ public final class BluetoothHeadsetClient implements BluetoothProfile {
* @return true if command has been issued successfully; false
* otherwise.
*/
+ @RequiresBluetoothConnectPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean sendVendorAtCommand(BluetoothDevice device, int vendorId,
String atCommand) {
@@ -728,6 +736,7 @@ public final class BluetoothHeadsetClient implements BluetoothProfile {
* #EXTRA_AG_FEATURE_VOICE_RECOGNITION}. This method invocation will fail silently when feature
* is not supported.
*/
+ @RequiresBluetoothConnectPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean stopVoiceRecognition(BluetoothDevice device) {
if (DBG) log("stopVoiceRecognition()");
@@ -750,6 +759,7 @@ public final class BluetoothHeadsetClient implements BluetoothProfile {
* @param device remote device
* @return list of calls; empty list if none call exists
*/
+ @RequiresBluetoothConnectPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public List getCurrentCalls(BluetoothDevice device) {
if (DBG) log("getCurrentCalls()");
@@ -772,6 +782,7 @@ public final class BluetoothHeadsetClient implements BluetoothProfile {
* @param device remote device
* @return bundle of AG indicators; null if device is not in CONNECTED state
*/
+ @RequiresBluetoothConnectPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public Bundle getCurrentAgEvents(BluetoothDevice device) {
if (DBG) log("getCurrentCalls()");
@@ -798,6 +809,7 @@ public final class BluetoothHeadsetClient implements BluetoothProfile {
* otherwise; upon completion HFP sends {@link #ACTION_CALL_CHANGED} intent.
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+ @RequiresBluetoothConnectPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean acceptCall(BluetoothDevice device, int flag) {
if (DBG) log("acceptCall()");
@@ -821,6 +833,7 @@ public final class BluetoothHeadsetClient implements BluetoothProfile {
* @return true if command has been issued successfully; false
* otherwise; upon completion HFP sends {@link #ACTION_CALL_CHANGED} intent.
*/
+ @RequiresBluetoothConnectPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean holdCall(BluetoothDevice device) {
if (DBG) log("holdCall()");
@@ -849,6 +862,7 @@ public final class BluetoothHeadsetClient implements BluetoothProfile {
* supported.
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+ @RequiresBluetoothConnectPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean rejectCall(BluetoothDevice device) {
if (DBG) log("rejectCall()");
@@ -881,6 +895,7 @@ public final class BluetoothHeadsetClient implements BluetoothProfile {
* #EXTRA_AG_FEATURE_ECC}. This method invocation will fail silently when feature is not
* supported.
*/
+ @RequiresBluetoothConnectPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean terminateCall(BluetoothDevice device, BluetoothHeadsetClientCall call) {
if (DBG) log("terminateCall()");
@@ -911,6 +926,7 @@ public final class BluetoothHeadsetClient implements BluetoothProfile {
* #EXTRA_AG_FEATURE_ECC}. This method invocation will fail silently when feature is not
* supported.
*/
+ @RequiresBluetoothConnectPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean enterPrivateMode(BluetoothDevice device, int index) {
if (DBG) log("enterPrivateMode()");
@@ -940,6 +956,7 @@ public final class BluetoothHeadsetClient implements BluetoothProfile {
* #EXTRA_AG_FEATURE_MERGE_AND_DETACH}. This method invocation will fail silently when feature
* is not supported.
*/
+ @RequiresBluetoothConnectPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean explicitCallTransfer(BluetoothDevice device) {
if (DBG) log("explicitCallTransfer()");
@@ -965,6 +982,7 @@ public final class BluetoothHeadsetClient implements BluetoothProfile {
* successfully; {@link null} otherwise; upon completion HFP sends {@link
* #ACTION_CALL_CHANGED} intent in case of success; {@link #ACTION_RESULT} is sent otherwise;
*/
+ @RequiresBluetoothConnectPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public BluetoothHeadsetClientCall dial(BluetoothDevice device, String number) {
if (DBG) log("dial()");
@@ -991,6 +1009,7 @@ public final class BluetoothHeadsetClient implements BluetoothProfile {
* @return true if command has been issued successfully; false
* otherwise; upon completion HFP sends {@link #ACTION_RESULT} intent;
*/
+ @RequiresBluetoothConnectPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean sendDTMF(BluetoothDevice device, byte code) {
if (DBG) log("sendDTMF()");
@@ -1113,6 +1132,7 @@ public final class BluetoothHeadsetClient implements BluetoothProfile {
* @return true if command has been issued successfully; false
* otherwise; upon completion HFP sends {@link #ACTION_AUDIO_STATE_CHANGED} intent;
*/
+ @RequiresBluetoothConnectPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean connectAudio(BluetoothDevice device) {
final IBluetoothHeadsetClient service =
@@ -1139,6 +1159,7 @@ public final class BluetoothHeadsetClient implements BluetoothProfile {
* @return true if command has been issued successfully; false
* otherwise; upon completion HFP sends {@link #ACTION_AUDIO_STATE_CHANGED} intent;
*/
+ @RequiresBluetoothConnectPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean disconnectAudio(BluetoothDevice device) {
final IBluetoothHeadsetClient service =
@@ -1162,6 +1183,7 @@ public final class BluetoothHeadsetClient implements BluetoothProfile {
* @param device remote device
* @return bundle of AG features; null if no service or AG not connected
*/
+ @RequiresBluetoothConnectPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public Bundle getCurrentAgFeatures(BluetoothDevice device) {
final IBluetoothHeadsetClient service =
diff --git a/core/java/android/bluetooth/BluetoothHearingAid.java b/core/java/android/bluetooth/BluetoothHearingAid.java
index 8ceeff53b1300..1fd779a17dbd7 100644
--- a/core/java/android/bluetooth/BluetoothHearingAid.java
+++ b/core/java/android/bluetooth/BluetoothHearingAid.java
@@ -21,6 +21,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
+import android.annotation.SuppressLint;
import android.annotation.SdkConstant.SdkConstantType;
import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
import android.bluetooth.annotations.RequiresLegacyBluetoothAdminPermission;
@@ -170,6 +171,7 @@ public final class BluetoothHearingAid implements BluetoothProfile {
* @return false on immediate error, true otherwise
* @hide
*/
+ @RequiresBluetoothConnectPermission
@RequiresPermission(allOf = {
android.Manifest.permission.BLUETOOTH_CONNECT,
android.Manifest.permission.BLUETOOTH_PRIVILEGED,
@@ -231,6 +233,7 @@ public final class BluetoothHearingAid implements BluetoothProfile {
* {@inheritDoc}
*/
@Override
+ @RequiresBluetoothConnectPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public @NonNull List getConnectedDevices() {
if (VDBG) log("getConnectedDevices()");
@@ -251,6 +254,7 @@ public final class BluetoothHearingAid implements BluetoothProfile {
* {@inheritDoc}
*/
@Override
+ @RequiresBluetoothConnectPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public @NonNull List getDevicesMatchingConnectionStates(
@NonNull int[] states) {
@@ -272,6 +276,7 @@ public final class BluetoothHearingAid implements BluetoothProfile {
* {@inheritDoc}
*/
@Override
+ @RequiresBluetoothConnectPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public @BluetoothProfile.BtProfileState int getConnectionState(
@NonNull BluetoothDevice device) {
@@ -368,6 +373,7 @@ public final class BluetoothHearingAid implements BluetoothProfile {
* @return true if priority is set, false on error
* @hide
*/
+ @RequiresBluetoothConnectPermission
@RequiresPermission(allOf = {
android.Manifest.permission.BLUETOOTH_CONNECT,
android.Manifest.permission.BLUETOOTH_PRIVILEGED,
@@ -390,6 +396,7 @@ public final class BluetoothHearingAid implements BluetoothProfile {
* @hide
*/
@SystemApi
+ @RequiresBluetoothConnectPermission
@RequiresPermission(allOf = {
android.Manifest.permission.BLUETOOTH_CONNECT,
android.Manifest.permission.BLUETOOTH_PRIVILEGED,
diff --git a/core/java/android/bluetooth/BluetoothHidDevice.java b/core/java/android/bluetooth/BluetoothHidDevice.java
index c214d2b85ac5b..6565ec0566bf7 100644
--- a/core/java/android/bluetooth/BluetoothHidDevice.java
+++ b/core/java/android/bluetooth/BluetoothHidDevice.java
@@ -20,6 +20,7 @@ import android.Manifest;
import android.annotation.NonNull;
import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
+import android.annotation.SuppressLint;
import android.annotation.SdkConstant.SdkConstantType;
import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
import android.bluetooth.annotations.RequiresLegacyBluetoothPermission;
@@ -439,6 +440,7 @@ public final class BluetoothHidDevice implements BluetoothProfile {
/** {@inheritDoc} */
@Override
+ @RequiresBluetoothConnectPermission
@RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT)
public List getConnectedDevices() {
final IBluetoothHidDevice service = getService();
@@ -457,6 +459,7 @@ public final class BluetoothHidDevice implements BluetoothProfile {
/** {@inheritDoc} */
@Override
+ @RequiresBluetoothConnectPermission
@RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT)
public List getDevicesMatchingConnectionStates(int[] states) {
final IBluetoothHidDevice service = getService();
@@ -475,6 +478,7 @@ public final class BluetoothHidDevice implements BluetoothProfile {
/** {@inheritDoc} */
@Override
+ @RequiresBluetoothConnectPermission
@RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT)
public int getConnectionState(BluetoothDevice device) {
final IBluetoothHidDevice service = getService();
@@ -514,6 +518,7 @@ public final class BluetoothHidDevice implements BluetoothProfile {
* object is required.
* @return true if the command is successfully sent; otherwise false.
*/
+ @RequiresBluetoothConnectPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean registerApp(
BluetoothHidDeviceAppSdpSettings sdp,
@@ -560,6 +565,7 @@ public final class BluetoothHidDevice implements BluetoothProfile {
*
* @return true if the command is successfully sent; otherwise false.
*/
+ @RequiresBluetoothConnectPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean unregisterApp() {
boolean result = false;
@@ -586,6 +592,7 @@ public final class BluetoothHidDevice implements BluetoothProfile {
* @param data Report data, not including Report Id.
* @return true if the command is successfully sent; otherwise false.
*/
+ @RequiresBluetoothConnectPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean sendReport(BluetoothDevice device, int id, byte[] data) {
boolean result = false;
@@ -613,6 +620,7 @@ public final class BluetoothHidDevice implements BluetoothProfile {
* @param data Report data, not including Report Id.
* @return true if the command is successfully sent; otherwise false.
*/
+ @RequiresBluetoothConnectPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean replyReport(BluetoothDevice device, byte type, byte id, byte[] data) {
boolean result = false;
@@ -638,6 +646,7 @@ public final class BluetoothHidDevice implements BluetoothProfile {
* @param error Error to be sent for SET_REPORT via HANDSHAKE.
* @return true if the command is successfully sent; otherwise false.
*/
+ @RequiresBluetoothConnectPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean reportError(BluetoothDevice device, byte error) {
boolean result = false;
@@ -662,6 +671,7 @@ public final class BluetoothHidDevice implements BluetoothProfile {
* @return the current user name, or empty string if cannot get the name
* {@hide}
*/
+ @RequiresBluetoothConnectPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public String getUserAppName() {
final IBluetoothHidDevice service = getService();
@@ -687,6 +697,7 @@ public final class BluetoothHidDevice implements BluetoothProfile {
*
* @return true if the command is successfully sent; otherwise false.
*/
+ @RequiresBluetoothConnectPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean connect(BluetoothDevice device) {
boolean result = false;
@@ -712,6 +723,7 @@ public final class BluetoothHidDevice implements BluetoothProfile {
*
* @return true if the command is successfully sent; otherwise false.
*/
+ @RequiresBluetoothConnectPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean disconnect(BluetoothDevice device) {
boolean result = false;
@@ -748,6 +760,7 @@ public final class BluetoothHidDevice implements BluetoothProfile {
* @hide
*/
@SystemApi
+ @RequiresBluetoothConnectPermission
@RequiresPermission(allOf = {
android.Manifest.permission.BLUETOOTH_CONNECT,
android.Manifest.permission.BLUETOOTH_PRIVILEGED,
diff --git a/core/java/android/bluetooth/BluetoothHidHost.java b/core/java/android/bluetooth/BluetoothHidHost.java
index 70e3809cb5909..bef4472b4a28d 100644
--- a/core/java/android/bluetooth/BluetoothHidHost.java
+++ b/core/java/android/bluetooth/BluetoothHidHost.java
@@ -331,6 +331,7 @@ public final class BluetoothHidHost implements BluetoothProfile {
*/
@SystemApi
@Override
+ @RequiresBluetoothConnectPermission
@RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT)
public @NonNull List getConnectedDevices() {
if (VDBG) log("getConnectedDevices()");
@@ -353,6 +354,7 @@ public final class BluetoothHidHost implements BluetoothProfile {
* @hide
*/
@Override
+ @RequiresBluetoothConnectPermission
@RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT)
public List getDevicesMatchingConnectionStates(int[] states) {
if (VDBG) log("getDevicesMatchingStates()");
@@ -376,6 +378,7 @@ public final class BluetoothHidHost implements BluetoothProfile {
*/
@SystemApi
@Override
+ @RequiresBluetoothConnectPermission
@RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT)
public int getConnectionState(@NonNull BluetoothDevice device) {
if (VDBG) log("getState(" + device + ")");
diff --git a/core/java/android/bluetooth/BluetoothInputStream.java b/core/java/android/bluetooth/BluetoothInputStream.java
index 8eb79b248d645..95f9229f0446a 100644
--- a/core/java/android/bluetooth/BluetoothInputStream.java
+++ b/core/java/android/bluetooth/BluetoothInputStream.java
@@ -16,6 +16,8 @@
package android.bluetooth;
+import android.annotation.SuppressLint;
+
import java.io.IOException;
import java.io.InputStream;
@@ -26,6 +28,7 @@ import java.io.InputStream;
*
* @hide
*/
+@SuppressLint("AndroidFrameworkBluetoothPermission")
/*package*/ final class BluetoothInputStream extends InputStream {
private BluetoothSocket mSocket;
diff --git a/core/java/android/bluetooth/BluetoothLeAudio.java b/core/java/android/bluetooth/BluetoothLeAudio.java
index 4f095f6c70014..c12b1f77fb9e6 100644
--- a/core/java/android/bluetooth/BluetoothLeAudio.java
+++ b/core/java/android/bluetooth/BluetoothLeAudio.java
@@ -155,6 +155,7 @@ public final class BluetoothLeAudio implements BluetoothProfile, AutoCloseable {
* @return false on immediate error, true otherwise
* @hide
*/
+ @RequiresBluetoothConnectPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean connect(@Nullable BluetoothDevice device) {
if (DBG) log("connect(" + device + ")");
@@ -194,6 +195,7 @@ public final class BluetoothLeAudio implements BluetoothProfile, AutoCloseable {
* @return false on immediate error, true otherwise
* @hide
*/
+ @RequiresBluetoothConnectPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean disconnect(@Nullable BluetoothDevice device) {
if (DBG) log("disconnect(" + device + ")");
@@ -214,6 +216,7 @@ public final class BluetoothLeAudio implements BluetoothProfile, AutoCloseable {
* {@inheritDoc}
*/
@Override
+ @RequiresBluetoothConnectPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public @NonNull List getConnectedDevices() {
if (VDBG) log("getConnectedDevices()");
@@ -234,6 +237,7 @@ public final class BluetoothLeAudio implements BluetoothProfile, AutoCloseable {
* {@inheritDoc}
*/
@Override
+ @RequiresBluetoothConnectPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public @NonNull List getDevicesMatchingConnectionStates(
@NonNull int[] states) {
@@ -294,6 +298,7 @@ public final class BluetoothLeAudio implements BluetoothProfile, AutoCloseable {
* @return false on immediate error, true otherwise
* @hide
*/
+ @RequiresBluetoothConnectPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean setActiveDevice(@Nullable BluetoothDevice device) {
if (DBG) log("setActiveDevice(" + device + ")");
@@ -370,6 +375,7 @@ public final class BluetoothLeAudio implements BluetoothProfile, AutoCloseable {
* @return true if connectionPolicy is set, false on error
* @hide
*/
+ @RequiresBluetoothConnectPermission
@RequiresPermission(allOf = {
android.Manifest.permission.BLUETOOTH_CONNECT,
android.Manifest.permission.BLUETOOTH_PRIVILEGED,
@@ -406,6 +412,7 @@ public final class BluetoothLeAudio implements BluetoothProfile, AutoCloseable {
* @return connection policy of the device
* @hide
*/
+ @RequiresBluetoothConnectPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public @ConnectionPolicy int getConnectionPolicy(@Nullable BluetoothDevice device) {
if (VDBG) log("getConnectionPolicy(" + device + ")");
diff --git a/core/java/android/bluetooth/BluetoothManager.java b/core/java/android/bluetooth/BluetoothManager.java
index a1e1b63050832..2374f1cdc5287 100644
--- a/core/java/android/bluetooth/BluetoothManager.java
+++ b/core/java/android/bluetooth/BluetoothManager.java
@@ -18,7 +18,9 @@ package android.bluetooth;
import android.Manifest;
import android.annotation.RequiresFeature;
+import android.annotation.RequiresNoPermission;
import android.annotation.RequiresPermission;
+import android.annotation.SuppressLint;
import android.annotation.SystemService;
import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
import android.bluetooth.annotations.RequiresLegacyBluetoothPermission;
@@ -93,6 +95,7 @@ public final class BluetoothManager {
*
* @return the BLUETOOTH Adapter
*/
+ @RequiresNoPermission
public BluetoothAdapter getAdapter() {
return mAdapter;
}
@@ -218,6 +221,7 @@ public final class BluetoothManager {
* @param callback GATT server callback handler that will receive asynchronous callbacks.
* @return BluetoothGattServer instance
*/
+ @RequiresBluetoothConnectPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public BluetoothGattServer openGattServer(Context context,
BluetoothGattServerCallback callback) {
@@ -238,6 +242,7 @@ public final class BluetoothManager {
* @return BluetoothGattServer instance
* @hide
*/
+ @RequiresBluetoothConnectPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public BluetoothGattServer openGattServer(Context context,
BluetoothGattServerCallback callback, boolean eatt_support) {
@@ -259,6 +264,7 @@ public final class BluetoothManager {
* @return BluetoothGattServer instance
* @hide
*/
+ @RequiresBluetoothConnectPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public BluetoothGattServer openGattServer(Context context,
BluetoothGattServerCallback callback, int transport) {
@@ -281,6 +287,7 @@ public final class BluetoothManager {
* @return BluetoothGattServer instance
* @hide
*/
+ @RequiresBluetoothConnectPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public BluetoothGattServer openGattServer(Context context,
BluetoothGattServerCallback callback, int transport, boolean eatt_support) {
diff --git a/core/java/android/bluetooth/BluetoothMap.java b/core/java/android/bluetooth/BluetoothMap.java
index 3e7b75aa1f628..998fde02832d9 100644
--- a/core/java/android/bluetooth/BluetoothMap.java
+++ b/core/java/android/bluetooth/BluetoothMap.java
@@ -18,9 +18,11 @@ package android.bluetooth;
import android.Manifest;
import android.annotation.NonNull;
+import android.annotation.RequiresNoPermission;
import android.annotation.RequiresPermission;
import android.annotation.SuppressLint;
import android.annotation.SystemApi;
+import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.os.Binder;
@@ -126,6 +128,7 @@ public final class BluetoothMap implements BluetoothProfile, AutoCloseable {
*
* @hide
*/
+ @RequiresBluetoothConnectPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public int getState() {
if (VDBG) log("getState()");
@@ -151,6 +154,7 @@ public final class BluetoothMap implements BluetoothProfile, AutoCloseable {
*
* @hide
*/
+ @RequiresBluetoothConnectPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public BluetoothDevice getClient() {
if (VDBG) log("getClient()");
@@ -175,6 +179,7 @@ public final class BluetoothMap implements BluetoothProfile, AutoCloseable {
*
* @hide
*/
+ @RequiresBluetoothConnectPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean isConnected(BluetoothDevice device) {
if (VDBG) log("isConnected(" + device + ")");
@@ -198,6 +203,7 @@ public final class BluetoothMap implements BluetoothProfile, AutoCloseable {
*
* @hide
*/
+ @RequiresNoPermission
public boolean connect(BluetoothDevice device) {
if (DBG) log("connect(" + device + ")" + "not supported for MAPS");
return false;
@@ -212,6 +218,7 @@ public final class BluetoothMap implements BluetoothProfile, AutoCloseable {
* @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+ @RequiresBluetoothConnectPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean disconnect(BluetoothDevice device) {
if (DBG) log("disconnect(" + device + ")");
@@ -259,6 +266,7 @@ public final class BluetoothMap implements BluetoothProfile, AutoCloseable {
* @hide
*/
@SystemApi
+ @RequiresBluetoothConnectPermission
@RequiresPermission(allOf = {
android.Manifest.permission.BLUETOOTH_CONNECT,
android.Manifest.permission.BLUETOOTH_PRIVILEGED,
@@ -285,6 +293,7 @@ public final class BluetoothMap implements BluetoothProfile, AutoCloseable {
*
* @hide
*/
+ @RequiresBluetoothConnectPermission
@RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT)
public List getDevicesMatchingConnectionStates(int[] states) {
if (DBG) log("getDevicesMatchingStates()");
@@ -308,6 +317,7 @@ public final class BluetoothMap implements BluetoothProfile, AutoCloseable {
*
* @hide
*/
+ @RequiresBluetoothConnectPermission
@RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT)
public int getConnectionState(BluetoothDevice device) {
if (DBG) log("getConnectionState(" + device + ")");
@@ -335,6 +345,7 @@ public final class BluetoothMap implements BluetoothProfile, AutoCloseable {
* @return true if priority is set, false on error
* @hide
*/
+ @RequiresBluetoothConnectPermission
@RequiresPermission(allOf = {
android.Manifest.permission.BLUETOOTH_CONNECT,
android.Manifest.permission.BLUETOOTH_PRIVILEGED,
@@ -357,6 +368,7 @@ public final class BluetoothMap implements BluetoothProfile, AutoCloseable {
* @hide
*/
@SystemApi
+ @RequiresBluetoothConnectPermission
@RequiresPermission(allOf = {
android.Manifest.permission.BLUETOOTH_CONNECT,
android.Manifest.permission.BLUETOOTH_PRIVILEGED,
@@ -391,6 +403,7 @@ public final class BluetoothMap implements BluetoothProfile, AutoCloseable {
* @return priority of the device
* @hide
*/
+ @RequiresBluetoothConnectPermission
@RequiresPermission(allOf = {
android.Manifest.permission.BLUETOOTH_CONNECT,
android.Manifest.permission.BLUETOOTH_PRIVILEGED,
@@ -412,6 +425,7 @@ public final class BluetoothMap implements BluetoothProfile, AutoCloseable {
* @hide
*/
@SystemApi
+ @RequiresBluetoothConnectPermission
@RequiresPermission(allOf = {
android.Manifest.permission.BLUETOOTH_CONNECT,
android.Manifest.permission.BLUETOOTH_PRIVILEGED,
diff --git a/core/java/android/bluetooth/BluetoothMapClient.java b/core/java/android/bluetooth/BluetoothMapClient.java
index db74a90f603b5..f20b533af045f 100644
--- a/core/java/android/bluetooth/BluetoothMapClient.java
+++ b/core/java/android/bluetooth/BluetoothMapClient.java
@@ -20,8 +20,10 @@ import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
+import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.app.PendingIntent;
+import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.net.Uri;
@@ -192,6 +194,7 @@ public final class BluetoothMapClient implements BluetoothProfile {
* currently connected to the Map service.
* @hide
*/
+ @RequiresBluetoothConnectPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean isConnected(BluetoothDevice device) {
if (VDBG) Log.d(TAG, "isConnected(" + device + ")");
@@ -215,6 +218,7 @@ public final class BluetoothMapClient implements BluetoothProfile {
*
* @hide
*/
+ @RequiresBluetoothConnectPermission
@RequiresPermission(allOf = {
android.Manifest.permission.BLUETOOTH_CONNECT,
android.Manifest.permission.BLUETOOTH_PRIVILEGED,
@@ -243,6 +247,7 @@ public final class BluetoothMapClient implements BluetoothProfile {
*
* @hide
*/
+ @RequiresBluetoothConnectPermission
@RequiresPermission(allOf = {
android.Manifest.permission.BLUETOOTH_CONNECT,
android.Manifest.permission.BLUETOOTH_PRIVILEGED,
@@ -268,6 +273,7 @@ public final class BluetoothMapClient implements BluetoothProfile {
* @hide
*/
@Override
+ @RequiresBluetoothConnectPermission
@RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT)
public List getConnectedDevices() {
if (DBG) Log.d(TAG, "getConnectedDevices()");
@@ -291,6 +297,7 @@ public final class BluetoothMapClient implements BluetoothProfile {
* @hide
*/
@Override
+ @RequiresBluetoothConnectPermission
@RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT)
public List getDevicesMatchingConnectionStates(int[] states) {
if (DBG) Log.d(TAG, "getDevicesMatchingStates()");
@@ -314,6 +321,7 @@ public final class BluetoothMapClient implements BluetoothProfile {
* @hide
*/
@Override
+ @RequiresBluetoothConnectPermission
@RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT)
public int getConnectionState(BluetoothDevice device) {
if (DBG) Log.d(TAG, "getConnectionState(" + device + ")");
@@ -341,6 +349,7 @@ public final class BluetoothMapClient implements BluetoothProfile {
* @return true if priority is set, false on error
* @hide
*/
+ @RequiresBluetoothConnectPermission
@RequiresPermission(allOf = {
android.Manifest.permission.BLUETOOTH_CONNECT,
android.Manifest.permission.BLUETOOTH_PRIVILEGED,
@@ -362,6 +371,7 @@ public final class BluetoothMapClient implements BluetoothProfile {
* @return true if connectionPolicy is set, false on error
* @hide
*/
+ @RequiresBluetoothConnectPermission
@RequiresPermission(allOf = {
android.Manifest.permission.BLUETOOTH_CONNECT,
android.Manifest.permission.BLUETOOTH_PRIVILEGED,
@@ -396,6 +406,7 @@ public final class BluetoothMapClient implements BluetoothProfile {
* @return priority of the device
* @hide
*/
+ @RequiresBluetoothConnectPermission
@RequiresPermission(allOf = {
android.Manifest.permission.BLUETOOTH_CONNECT,
android.Manifest.permission.BLUETOOTH_PRIVILEGED,
@@ -416,6 +427,7 @@ public final class BluetoothMapClient implements BluetoothProfile {
* @return connection policy of the device
* @hide
*/
+ @RequiresBluetoothConnectPermission
@RequiresPermission(allOf = {
android.Manifest.permission.BLUETOOTH_CONNECT,
android.Manifest.permission.BLUETOOTH_PRIVILEGED,
@@ -449,6 +461,7 @@ public final class BluetoothMapClient implements BluetoothProfile {
* @hide
*/
@SystemApi
+ @RequiresBluetoothConnectPermission
@RequiresPermission(allOf = {
android.Manifest.permission.BLUETOOTH_CONNECT,
android.Manifest.permission.SEND_SMS,
@@ -484,6 +497,7 @@ public final class BluetoothMapClient implements BluetoothProfile {
* @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+ @RequiresBluetoothConnectPermission
@RequiresPermission(allOf = {
android.Manifest.permission.BLUETOOTH_CONNECT,
android.Manifest.permission.SEND_SMS,
@@ -510,6 +524,7 @@ public final class BluetoothMapClient implements BluetoothProfile {
* @return true if the message is enqueued, false on error
* @hide
*/
+ @RequiresBluetoothConnectPermission
@RequiresPermission(allOf = {
android.Manifest.permission.BLUETOOTH_CONNECT,
android.Manifest.permission.READ_SMS,
@@ -536,6 +551,7 @@ public final class BluetoothMapClient implements BluetoothProfile {
* MapSupportedFeatures field is set. False is returned otherwise.
* @hide
*/
+ @RequiresBluetoothConnectPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean isUploadingSupported(BluetoothDevice device) {
final IBluetoothMapClient service = getService();
@@ -564,6 +580,7 @@ public final class BluetoothMapClient implements BluetoothProfile {
* @return true if request has been sent, false on error
* @hide
*/
+ @RequiresBluetoothConnectPermission
@RequiresPermission(allOf = {
android.Manifest.permission.BLUETOOTH_CONNECT,
android.Manifest.permission.READ_SMS,
diff --git a/core/java/android/bluetooth/BluetoothOutputStream.java b/core/java/android/bluetooth/BluetoothOutputStream.java
index a0aa2dee9d348..ac2b3edb0eb85 100644
--- a/core/java/android/bluetooth/BluetoothOutputStream.java
+++ b/core/java/android/bluetooth/BluetoothOutputStream.java
@@ -16,6 +16,8 @@
package android.bluetooth;
+import android.annotation.SuppressLint;
+
import java.io.IOException;
import java.io.OutputStream;
@@ -26,6 +28,7 @@ import java.io.OutputStream;
*
* @hide
*/
+@SuppressLint("AndroidFrameworkBluetoothPermission")
/*package*/ final class BluetoothOutputStream extends OutputStream {
private BluetoothSocket mSocket;
diff --git a/core/java/android/bluetooth/BluetoothPan.java b/core/java/android/bluetooth/BluetoothPan.java
index b3924b1fa9207..c41c9dee2547e 100644
--- a/core/java/android/bluetooth/BluetoothPan.java
+++ b/core/java/android/bluetooth/BluetoothPan.java
@@ -240,6 +240,7 @@ public final class BluetoothPan implements BluetoothProfile {
* @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+ @RequiresBluetoothConnectPermission
@RequiresPermission(allOf = {
android.Manifest.permission.BLUETOOTH_CONNECT,
android.Manifest.permission.BLUETOOTH_PRIVILEGED,
@@ -282,6 +283,7 @@ public final class BluetoothPan implements BluetoothProfile {
* @hide
*/
@UnsupportedAppUsage
+ @RequiresBluetoothConnectPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean disconnect(BluetoothDevice device) {
if (DBG) log("disconnect(" + device + ")");
@@ -311,6 +313,7 @@ public final class BluetoothPan implements BluetoothProfile {
* @hide
*/
@SystemApi
+ @RequiresBluetoothConnectPermission
@RequiresPermission(allOf = {
android.Manifest.permission.BLUETOOTH_CONNECT,
android.Manifest.permission.BLUETOOTH_PRIVILEGED,
@@ -342,6 +345,7 @@ public final class BluetoothPan implements BluetoothProfile {
*/
@SystemApi
@Override
+ @RequiresBluetoothConnectPermission
@RequiresPermission(allOf = {
android.Manifest.permission.BLUETOOTH_CONNECT,
android.Manifest.permission.BLUETOOTH_PRIVILEGED,
@@ -416,6 +420,7 @@ public final class BluetoothPan implements BluetoothProfile {
* @hide
*/
@SystemApi
+ @RequiresBluetoothConnectPermission
@RequiresPermission(allOf = {
android.Manifest.permission.BLUETOOTH_CONNECT,
android.Manifest.permission.BLUETOOTH_PRIVILEGED,
@@ -441,6 +446,7 @@ public final class BluetoothPan implements BluetoothProfile {
* @hide
*/
@SystemApi
+ @RequiresBluetoothConnectPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean isTetheringOn() {
if (VDBG) log("isTetheringOn()");
diff --git a/core/java/android/bluetooth/BluetoothPbap.java b/core/java/android/bluetooth/BluetoothPbap.java
index 6c2e5bf2d3913..e41eb4f258102 100644
--- a/core/java/android/bluetooth/BluetoothPbap.java
+++ b/core/java/android/bluetooth/BluetoothPbap.java
@@ -110,6 +110,7 @@ public class BluetoothPbap implements BluetoothProfile {
*/
public static final int RESULT_CANCELED = 2;
+ @SuppressLint("AndroidFrameworkBluetoothPermission")
private final IBluetoothStateChangeCallback mBluetoothStateChangeCallback =
new IBluetoothStateChangeCallback.Stub() {
public void onBluetoothStateChange(boolean up) {
@@ -217,6 +218,7 @@ public class BluetoothPbap implements BluetoothProfile {
* @hide
*/
@Override
+ @RequiresBluetoothConnectPermission
@RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT)
public List getConnectedDevices() {
log("getConnectedDevices()");
@@ -264,6 +266,7 @@ public class BluetoothPbap implements BluetoothProfile {
* @hide
*/
@Override
+ @RequiresBluetoothConnectPermission
@RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT)
public List getDevicesMatchingConnectionStates(int[] states) {
log("getDevicesMatchingConnectionStates: states=" + Arrays.toString(states));
@@ -297,6 +300,7 @@ public class BluetoothPbap implements BluetoothProfile {
* @hide
*/
@SystemApi
+ @RequiresBluetoothConnectPermission
@RequiresPermission(allOf = {
android.Manifest.permission.BLUETOOTH_CONNECT,
android.Manifest.permission.BLUETOOTH_PRIVILEGED,
@@ -330,6 +334,7 @@ public class BluetoothPbap implements BluetoothProfile {
* @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+ @RequiresBluetoothConnectPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean disconnect(BluetoothDevice device) {
log("disconnect()");
@@ -347,6 +352,7 @@ public class BluetoothPbap implements BluetoothProfile {
return false;
}
+ @SuppressLint("AndroidFrameworkBluetoothPermission")
private final ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
log("Proxy object connected");
diff --git a/core/java/android/bluetooth/BluetoothPbapClient.java b/core/java/android/bluetooth/BluetoothPbapClient.java
index 2c8fbc2509ff2..85b8650765084 100644
--- a/core/java/android/bluetooth/BluetoothPbapClient.java
+++ b/core/java/android/bluetooth/BluetoothPbapClient.java
@@ -20,6 +20,7 @@ import android.Manifest;
import android.annotation.NonNull;
import android.annotation.RequiresPermission;
import android.annotation.SuppressLint;
+import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
import android.content.Context;
import android.os.Binder;
import android.os.IBinder;
@@ -161,6 +162,7 @@ public final class BluetoothPbapClient implements BluetoothProfile {
* @return list of connected devices
*/
@Override
+ @RequiresBluetoothConnectPermission
@RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT)
public List getConnectedDevices() {
if (DBG) {
@@ -187,6 +189,7 @@ public final class BluetoothPbapClient implements BluetoothProfile {
* @return list of matching devices
*/
@Override
+ @RequiresBluetoothConnectPermission
@RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT)
public List getDevicesMatchingConnectionStates(int[] states) {
if (DBG) {
@@ -213,6 +216,7 @@ public final class BluetoothPbapClient implements BluetoothProfile {
* @return device connection state
*/
@Override
+ @RequiresBluetoothConnectPermission
@RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT)
public int getConnectionState(BluetoothDevice device) {
if (DBG) {
diff --git a/core/java/android/bluetooth/BluetoothProfile.java b/core/java/android/bluetooth/BluetoothProfile.java
index 70053ee71491d..161c843f03982 100644
--- a/core/java/android/bluetooth/BluetoothProfile.java
+++ b/core/java/android/bluetooth/BluetoothProfile.java
@@ -17,6 +17,7 @@
package android.bluetooth;
import android.annotation.IntDef;
+import android.annotation.RequiresNoPermission;
import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.compat.annotation.UnsupportedAppUsage;
@@ -333,6 +334,7 @@ public interface BluetoothProfile {
* @param profile - One of {@link #HEADSET} or {@link #A2DP}
* @param proxy - One of {@link BluetoothHeadset} or {@link BluetoothA2dp}
*/
+ @RequiresNoPermission
public void onServiceConnected(int profile, BluetoothProfile proxy);
/**
@@ -341,6 +343,7 @@ public interface BluetoothProfile {
*
* @param profile - One of {@link #HEADSET} or {@link #A2DP}
*/
+ @RequiresNoPermission
public void onServiceDisconnected(int profile);
}
diff --git a/core/java/android/bluetooth/BluetoothProfileConnector.java b/core/java/android/bluetooth/BluetoothProfileConnector.java
index 12abcc4d11da5..b20ab754932c6 100644
--- a/core/java/android/bluetooth/BluetoothProfileConnector.java
+++ b/core/java/android/bluetooth/BluetoothProfileConnector.java
@@ -16,7 +16,6 @@
package android.bluetooth;
-import android.annotation.RequiresPermission;
import android.annotation.SuppressLint;
import android.content.ComponentName;
import android.content.Context;
@@ -33,6 +32,7 @@ import android.util.Log;
* @param The Bluetooth profile interface for this connection.
* @hide
*/
+@SuppressLint("AndroidFrameworkBluetoothPermission")
public abstract class BluetoothProfileConnector {
private final int mProfileId;
private BluetoothProfile.ServiceListener mServiceListener;
diff --git a/core/java/android/bluetooth/BluetoothSap.java b/core/java/android/bluetooth/BluetoothSap.java
index c85494c01b25c..87da22cbb7f5e 100644
--- a/core/java/android/bluetooth/BluetoothSap.java
+++ b/core/java/android/bluetooth/BluetoothSap.java
@@ -17,6 +17,7 @@
package android.bluetooth;
import android.Manifest;
+import android.annotation.RequiresNoPermission;
import android.annotation.RequiresPermission;
import android.annotation.SuppressLint;
import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
@@ -143,6 +144,7 @@ public final class BluetoothSap implements BluetoothProfile {
* connected to the Sap service.
* @hide
*/
+ @RequiresBluetoothConnectPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public int getState() {
if (VDBG) log("getState()");
@@ -167,6 +169,7 @@ public final class BluetoothSap implements BluetoothProfile {
* this proxy object is not connected to the Sap service.
* @hide
*/
+ @RequiresBluetoothConnectPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public BluetoothDevice getClient() {
if (VDBG) log("getClient()");
@@ -191,6 +194,7 @@ public final class BluetoothSap implements BluetoothProfile {
*
* @hide
*/
+ @RequiresBluetoothConnectPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean isConnected(BluetoothDevice device) {
if (VDBG) log("isConnected(" + device + ")");
@@ -214,6 +218,7 @@ public final class BluetoothSap implements BluetoothProfile {
*
* @hide
*/
+ @RequiresNoPermission
public boolean connect(BluetoothDevice device) {
if (DBG) log("connect(" + device + ")" + "not supported for SAPS");
return false;
@@ -227,6 +232,7 @@ public final class BluetoothSap implements BluetoothProfile {
* @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+ @RequiresBluetoothConnectPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean disconnect(BluetoothDevice device) {
if (DBG) log("disconnect(" + device + ")");
@@ -249,6 +255,7 @@ public final class BluetoothSap implements BluetoothProfile {
* @return list of connected devices
* @hide
*/
+ @RequiresBluetoothConnectPermission
@RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT)
public List getConnectedDevices() {
if (DBG) log("getConnectedDevices()");
@@ -271,6 +278,7 @@ public final class BluetoothSap implements BluetoothProfile {
* @return list of matching devices
* @hide
*/
+ @RequiresBluetoothConnectPermission
@RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT)
public List getDevicesMatchingConnectionStates(int[] states) {
if (DBG) log("getDevicesMatchingStates()");
@@ -293,6 +301,7 @@ public final class BluetoothSap implements BluetoothProfile {
* @return device connection state
* @hide
*/
+ @RequiresBluetoothConnectPermission
@RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT)
public int getConnectionState(BluetoothDevice device) {
if (DBG) log("getConnectionState(" + device + ")");
@@ -320,6 +329,7 @@ public final class BluetoothSap implements BluetoothProfile {
* @return true if priority is set, false on error
* @hide
*/
+ @RequiresBluetoothConnectPermission
@RequiresPermission(allOf = {
android.Manifest.permission.BLUETOOTH_CONNECT,
android.Manifest.permission.BLUETOOTH_PRIVILEGED,
@@ -341,6 +351,7 @@ public final class BluetoothSap implements BluetoothProfile {
* @return true if connectionPolicy is set, false on error
* @hide
*/
+ @RequiresBluetoothConnectPermission
@RequiresPermission(allOf = {
android.Manifest.permission.BLUETOOTH_CONNECT,
android.Manifest.permission.BLUETOOTH_PRIVILEGED,
@@ -375,6 +386,7 @@ public final class BluetoothSap implements BluetoothProfile {
* @return priority of the device
* @hide
*/
+ @RequiresBluetoothConnectPermission
@RequiresPermission(allOf = {
android.Manifest.permission.BLUETOOTH_CONNECT,
android.Manifest.permission.BLUETOOTH_PRIVILEGED,
@@ -395,6 +407,7 @@ public final class BluetoothSap implements BluetoothProfile {
* @return connection policy of the device
* @hide
*/
+ @RequiresBluetoothConnectPermission
@RequiresPermission(allOf = {
android.Manifest.permission.BLUETOOTH_CONNECT,
android.Manifest.permission.BLUETOOTH_PRIVILEGED,
diff --git a/core/java/android/bluetooth/BluetoothServerSocket.java b/core/java/android/bluetooth/BluetoothServerSocket.java
index 50822354d69fc..bb4e35483fea8 100644
--- a/core/java/android/bluetooth/BluetoothServerSocket.java
+++ b/core/java/android/bluetooth/BluetoothServerSocket.java
@@ -16,6 +16,7 @@
package android.bluetooth;
+import android.annotation.SuppressLint;
import android.compat.annotation.UnsupportedAppUsage;
import android.os.Handler;
import android.os.ParcelUuid;
@@ -70,6 +71,7 @@ import java.io.IOException;
*
* {@see BluetoothSocket}
*/
+@SuppressLint("AndroidFrameworkBluetoothPermission")
public final class BluetoothServerSocket implements Closeable {
private static final String TAG = "BluetoothServerSocket";
diff --git a/core/java/android/bluetooth/BluetoothSocket.java b/core/java/android/bluetooth/BluetoothSocket.java
index ef88147a40fb5..bb409d5360f91 100644
--- a/core/java/android/bluetooth/BluetoothSocket.java
+++ b/core/java/android/bluetooth/BluetoothSocket.java
@@ -16,8 +16,10 @@
package android.bluetooth;
+import android.annotation.RequiresNoPermission;
import android.annotation.RequiresPermission;
import android.annotation.SuppressLint;
+import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
import android.compat.annotation.UnsupportedAppUsage;
import android.net.LocalSocket;
import android.os.Build;
@@ -198,7 +200,6 @@ public final class BluetoothSocket implements Closeable {
* @throws IOException On error, for example Bluetooth not available, or insufficient
* privileges
*/
- @SuppressLint("AndroidFrameworkRequiresPermission")
/*package*/ BluetoothSocket(int type, int fd, boolean auth, boolean encrypt,
BluetoothDevice device, int port, ParcelUuid uuid, boolean mitm, boolean min16DigitPin)
throws IOException {
@@ -326,6 +327,7 @@ public final class BluetoothSocket implements Closeable {
*
* @return remote device
*/
+ @RequiresNoPermission
public BluetoothDevice getRemoteDevice() {
return mDevice;
}
@@ -338,6 +340,7 @@ public final class BluetoothSocket implements Closeable {
*
* @return InputStream
*/
+ @RequiresNoPermission
public InputStream getInputStream() throws IOException {
return mInputStream;
}
@@ -350,6 +353,7 @@ public final class BluetoothSocket implements Closeable {
*
* @return OutputStream
*/
+ @RequiresNoPermission
public OutputStream getOutputStream() throws IOException {
return mOutputStream;
}
@@ -360,6 +364,7 @@ public final class BluetoothSocket implements Closeable {
*
* @return true if connected false if not connected
*/
+ @RequiresNoPermission
public boolean isConnected() {
return mSocketState == SocketState.CONNECTED;
}
@@ -386,6 +391,7 @@ public final class BluetoothSocket implements Closeable {
*
* @throws IOException on error, for example connection failure
*/
+ @RequiresBluetoothConnectPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public void connect() throws IOException {
if (mDevice == null) throw new IOException("Connect is called on null device");
@@ -637,6 +643,7 @@ public final class BluetoothSocket implements Closeable {
*
* @return the maximum supported Transmit packet size for the underlying transport.
*/
+ @RequiresNoPermission
public int getMaxTransmitPacketSize() {
return mMaxTxPacketSize;
}
@@ -649,6 +656,7 @@ public final class BluetoothSocket implements Closeable {
*
* @return the maximum supported Receive packet size for the underlying transport.
*/
+ @RequiresNoPermission
public int getMaxReceivePacketSize() {
return mMaxRxPacketSize;
}
@@ -658,6 +666,7 @@ public final class BluetoothSocket implements Closeable {
*
* @return one of {@link #TYPE_RFCOMM}, {@link #TYPE_SCO} or {@link #TYPE_L2CAP}
*/
+ @RequiresNoPermission
public int getConnectionType() {
if (mType == TYPE_L2CAP_LE) {
// Treat the LE CoC to be the same type as L2CAP.
@@ -674,6 +683,7 @@ public final class BluetoothSocket implements Closeable {
* generate SPP SDP record.
* @hide
*/
+ @RequiresNoPermission
public void setExcludeSdp(boolean excludeSdp) {
mExcludeSdp = excludeSdp;
}
@@ -684,6 +694,7 @@ public final class BluetoothSocket implements Closeable {
* connection. This function is currently used for testing only.
* @hide
*/
+ @RequiresBluetoothConnectPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public void requestMaximumTxDataLength() throws IOException {
if (mDevice == null) {
diff --git a/core/java/android/bluetooth/BluetoothUuid.java b/core/java/android/bluetooth/BluetoothUuid.java
index d82cf19e88223..bc3754a2fc564 100644
--- a/core/java/android/bluetooth/BluetoothUuid.java
+++ b/core/java/android/bluetooth/BluetoothUuid.java
@@ -18,6 +18,7 @@ package android.bluetooth;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.compat.annotation.UnsupportedAppUsage;
import android.os.ParcelUuid;
@@ -34,6 +35,7 @@ import java.util.UUID;
* @hide
*/
@SystemApi
+@SuppressLint("AndroidFrameworkBluetoothPermission")
public final class BluetoothUuid {
/* See Bluetooth Assigned Numbers document - SDP section, to get the values of UUIDs
diff --git a/core/java/android/bluetooth/le/AdvertisingSet.java b/core/java/android/bluetooth/le/AdvertisingSet.java
index 54a18e6f1d62e..d7e48ca543ca1 100644
--- a/core/java/android/bluetooth/le/AdvertisingSet.java
+++ b/core/java/android/bluetooth/le/AdvertisingSet.java
@@ -16,7 +16,9 @@
package android.bluetooth.le;
+import android.annotation.RequiresNoPermission;
import android.annotation.RequiresPermission;
+import android.annotation.SuppressLint;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.IBluetoothGatt;
import android.bluetooth.IBluetoothManager;
@@ -216,6 +218,7 @@ public final class AdvertisingSet {
*
* @hide
*/
+ @RequiresNoPermission
public int getAdvertiserId() {
return mAdvertiserId;
}
diff --git a/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java b/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java
index 710fa6827b0bf..ff279d859873c 100644
--- a/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java
+++ b/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java
@@ -16,6 +16,7 @@
package android.bluetooth.le;
+import android.annotation.RequiresNoPermission;
import android.annotation.RequiresPermission;
import android.annotation.SuppressLint;
import android.bluetooth.BluetoothAdapter;
@@ -163,11 +164,13 @@ public final class BluetoothLeAdvertiser {
}
}
- @SuppressLint("AndroidFrameworkRequiresPermission")
+ @SuppressLint({
+ "AndroidFrameworkBluetoothPermission",
+ "AndroidFrameworkRequiresPermission",
+ })
AdvertisingSetCallback wrapOldCallback(AdvertiseCallback callback, AdvertiseSettings settings) {
return new AdvertisingSetCallback() {
@Override
- @SuppressLint("AndroidFrameworkRequiresPermission")
public void onAdvertisingSetStarted(AdvertisingSet advertisingSet, int txPower,
int status) {
if (status != AdvertisingSetCallback.ADVERTISE_SUCCESS) {
@@ -180,7 +183,6 @@ public final class BluetoothLeAdvertiser {
/* Legacy advertiser is disabled on timeout */
@Override
- @SuppressLint("AndroidFrameworkRequiresPermission")
public void onAdvertisingEnabled(AdvertisingSet advertisingSet, boolean enabled,
int status) {
if (enabled) {
@@ -491,6 +493,7 @@ public final class BluetoothLeAdvertiser {
*
* @hide
*/
+ @RequiresNoPermission
public void cleanup() {
mLegacyAdvertisers.clear();
mCallbackWrappers.clear();
@@ -498,6 +501,7 @@ public final class BluetoothLeAdvertiser {
}
// Compute the size of advertisement data or scan resp
+ @RequiresBluetoothAdvertisePermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE)
private int totalBytes(AdvertiseData data, boolean isFlagsIncluded) {
if (data == null) return 0;
@@ -582,6 +586,7 @@ public final class BluetoothLeAdvertiser {
return array == null ? 0 : array.length;
}
+ @SuppressLint("AndroidFrameworkBluetoothPermission")
IAdvertisingSetCallback wrap(AdvertisingSetCallback callback, Handler handler) {
return new IAdvertisingSetCallback.Stub() {
@Override
@@ -706,6 +711,7 @@ public final class BluetoothLeAdvertiser {
};
}
+ @SuppressLint("AndroidFrameworkBluetoothPermission")
private void postStartSetFailure(Handler handler, final AdvertisingSetCallback callback,
final int error) {
handler.post(new Runnable() {
@@ -716,6 +722,7 @@ public final class BluetoothLeAdvertiser {
});
}
+ @SuppressLint("AndroidFrameworkBluetoothPermission")
private void postStartFailure(final AdvertiseCallback callback, final int error) {
mHandler.post(new Runnable() {
@Override
@@ -725,6 +732,7 @@ public final class BluetoothLeAdvertiser {
});
}
+ @SuppressLint("AndroidFrameworkBluetoothPermission")
private void postStartSuccess(final AdvertiseCallback callback,
final AdvertiseSettings settings) {
mHandler.post(new Runnable() {
diff --git a/core/java/android/bluetooth/le/BluetoothLeScanner.java b/core/java/android/bluetooth/le/BluetoothLeScanner.java
index 4271a905c2204..09cd11d075906 100644
--- a/core/java/android/bluetooth/le/BluetoothLeScanner.java
+++ b/core/java/android/bluetooth/le/BluetoothLeScanner.java
@@ -16,9 +16,9 @@
package android.bluetooth.le;
-import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.RequiresNoPermission;
import android.annotation.RequiresPermission;
import android.annotation.SuppressLint;
import android.annotation.SystemApi;
@@ -357,6 +357,7 @@ public final class BluetoothLeScanner {
* @hide
*/
@SystemApi
+ @RequiresBluetoothScanPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
public void startTruncatedScan(List truncatedFilters, ScanSettings settings,
final ScanCallback callback) {
@@ -376,6 +377,7 @@ public final class BluetoothLeScanner {
*
* @hide
*/
+ @RequiresNoPermission
public void cleanup() {
mLeScanClients.clear();
}
@@ -383,6 +385,7 @@ public final class BluetoothLeScanner {
/**
* Bluetooth GATT interface callbacks
*/
+ @SuppressLint("AndroidFrameworkRequiresPermission")
private class BleScanCallbackWrapper extends IScannerCallback.Stub {
private static final int REGISTRATION_CALLBACK_TIMEOUT_MILLIS = 2000;
@@ -412,8 +415,6 @@ public final class BluetoothLeScanner {
mResultStorages = resultStorages;
}
- @SuppressLint("AndroidFrameworkRequiresPermission")
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
public void startRegistration() {
synchronized (this) {
// Scan stopped.
@@ -441,8 +442,6 @@ public final class BluetoothLeScanner {
}
}
- @SuppressLint("AndroidFrameworkRequiresPermission")
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
public void stopLeScan() {
synchronized (this) {
if (mScannerId <= 0) {
@@ -459,8 +458,6 @@ public final class BluetoothLeScanner {
}
}
- @SuppressLint("AndroidFrameworkRequiresPermission")
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
void flushPendingBatchResults() {
synchronized (this) {
if (mScannerId <= 0) {
@@ -479,7 +476,6 @@ public final class BluetoothLeScanner {
* Application interface registered - app is ready to go
*/
@Override
- @SuppressLint("AndroidFrameworkRequiresPermission")
public void onScannerRegistered(int status, int scannerId) {
Log.d(TAG, "onScannerRegistered() - status=" + status
+ " scannerId=" + scannerId + " mScannerId=" + mScannerId);
diff --git a/core/java/android/bluetooth/le/PeriodicAdvertisingManager.java b/core/java/android/bluetooth/le/PeriodicAdvertisingManager.java
index 9ea6c4866f6d6..26978e398072d 100644
--- a/core/java/android/bluetooth/le/PeriodicAdvertisingManager.java
+++ b/core/java/android/bluetooth/le/PeriodicAdvertisingManager.java
@@ -17,6 +17,7 @@
package android.bluetooth.le;
import android.annotation.RequiresPermission;
+import android.annotation.SuppressLint;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.IBluetoothGatt;
@@ -208,6 +209,7 @@ public final class PeriodicAdvertisingManager {
}
}
+ @SuppressLint("AndroidFrameworkBluetoothPermission")
private IPeriodicAdvertisingCallback wrap(PeriodicAdvertisingCallback callback,
Handler handler) {
return new IPeriodicAdvertisingCallback.Stub() {
diff --git a/core/java/android/bluetooth/le/ScanFilter.java b/core/java/android/bluetooth/le/ScanFilter.java
index 27c579b3cdfe7..c5c4277d9eb83 100644
--- a/core/java/android/bluetooth/le/ScanFilter.java
+++ b/core/java/android/bluetooth/le/ScanFilter.java
@@ -16,7 +16,6 @@
package android.bluetooth.le;
-import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
diff --git a/core/java/android/bluetooth/le/ScanRecord.java b/core/java/android/bluetooth/le/ScanRecord.java
index 794b512772fe8..9b8c2eaf4d197 100644
--- a/core/java/android/bluetooth/le/ScanRecord.java
+++ b/core/java/android/bluetooth/le/ScanRecord.java
@@ -18,6 +18,7 @@ package android.bluetooth.le;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.SuppressLint;
import android.bluetooth.BluetoothUuid;
import android.compat.annotation.UnsupportedAppUsage;
import android.os.ParcelUuid;
@@ -34,6 +35,7 @@ import java.util.function.Predicate;
/**
* Represents a scan record from Bluetooth LE scan.
*/
+@SuppressLint("AndroidFrameworkBluetoothPermission")
public final class ScanRecord {
private static final String TAG = "ScanRecord";
diff --git a/core/java/android/bluetooth/le/TruncatedFilter.java b/core/java/android/bluetooth/le/TruncatedFilter.java
index a753aa6fef170..93f526bb9f093 100644
--- a/core/java/android/bluetooth/le/TruncatedFilter.java
+++ b/core/java/android/bluetooth/le/TruncatedFilter.java
@@ -16,6 +16,7 @@
package android.bluetooth.le;
+import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import java.util.List;
@@ -26,6 +27,7 @@ import java.util.List;
* @hide
*/
@SystemApi
+@SuppressLint("AndroidFrameworkBluetoothPermission")
public final class TruncatedFilter {
private final ScanFilter mFilter;
private final List mStorageDescriptors;
diff --git a/errorprone/java/android/annotation/RequiresNoPermission.java b/errorprone/java/android/annotation/RequiresNoPermission.java
new file mode 100644
index 0000000000000..6ff4d6e34957e
--- /dev/null
+++ b/errorprone/java/android/annotation/RequiresNoPermission.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.annotation;
+
+import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
+import static java.lang.annotation.ElementType.CONSTRUCTOR;
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.RetentionPolicy.CLASS;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * Denotes that the annotated element requires no permissions.
+ *
+ * @hide
+ */
+@Retention(CLASS)
+@Target({ANNOTATION_TYPE,METHOD,CONSTRUCTOR,FIELD,PARAMETER})
+public @interface RequiresNoPermission {
+}
diff --git a/errorprone/java/android/annotation/RequiresPermission.java b/errorprone/java/android/annotation/RequiresPermission.java
new file mode 100644
index 0000000000000..303ab41bec8ef
--- /dev/null
+++ b/errorprone/java/android/annotation/RequiresPermission.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.annotation;
+
+import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
+import static java.lang.annotation.ElementType.CONSTRUCTOR;
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.RetentionPolicy.CLASS;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * Denotes that the annotated element requires (or may require) one or more permissions.
+ *
+ * Example of requiring a single permission:
+ * {@code
+ * {@literal @}RequiresPermission(Manifest.permission.SET_WALLPAPER)
+ * public abstract void setWallpaper(Bitmap bitmap) throws IOException;
+ *
+ * {@literal @}RequiresPermission(ACCESS_COARSE_LOCATION)
+ * public abstract Location getLastKnownLocation(String provider);
+ * }
+ * Example of requiring at least one permission from a set:
+ * {@code
+ * {@literal @}RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
+ * public abstract Location getLastKnownLocation(String provider);
+ * }
+ * Example of requiring multiple permissions:
+ * {@code
+ * {@literal @}RequiresPermission(allOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
+ * public abstract Location getLastKnownLocation(String provider);
+ * }
+ * Example of requiring separate read and write permissions for a content provider:
+ * {@code
+ * {@literal @}RequiresPermission.Read(@RequiresPermission(READ_HISTORY_BOOKMARKS))
+ * {@literal @}RequiresPermission.Write(@RequiresPermission(WRITE_HISTORY_BOOKMARKS))
+ * public static final Uri BOOKMARKS_URI = Uri.parse("content://browser/bookmarks");
+ * }
+ *
+ * When specified on a parameter, the annotation indicates that the method requires
+ * a permission which depends on the value of the parameter. For example, consider
+ * {@link android.app.Activity#startActivity(android.content.Intent)
+ * Activity#startActivity(Intent)}:
+ *
{@code
+ * public void startActivity(@RequiresPermission Intent intent) { ... }
+ * }
+ * Notice how there are no actual permission names listed in the annotation. The actual
+ * permissions required will depend on the particular intent passed in. For example,
+ * the code may look like this:
+ * {@code
+ * Intent intent = new Intent(Intent.ACTION_CALL);
+ * startActivity(intent);
+ * }
+ * and the actual permission requirement for this particular intent is described on
+ * the Intent name itself:
+ * {@code
+ * {@literal @}RequiresPermission(Manifest.permission.CALL_PHONE)
+ * public static final String ACTION_CALL = "android.intent.action.CALL";
+ * }
+ *
+ * @hide
+ */
+@Retention(CLASS)
+@Target({ANNOTATION_TYPE,METHOD,CONSTRUCTOR,FIELD,PARAMETER})
+public @interface RequiresPermission {
+ /**
+ * The name of the permission that is required, if precisely one permission
+ * is required. If more than one permission is required, specify either
+ * {@link #allOf()} or {@link #anyOf()} instead.
+ *
+ * If specified, {@link #anyOf()} and {@link #allOf()} must both be null.
+ */
+ String value() default "";
+
+ /**
+ * Specifies a list of permission names that are all required.
+ *
+ * If specified, {@link #anyOf()} and {@link #value()} must both be null.
+ */
+ String[] allOf() default {};
+
+ /**
+ * Specifies a list of permission names where at least one is required
+ *
+ * If specified, {@link #allOf()} and {@link #value()} must both be null.
+ */
+ String[] anyOf() default {};
+
+ /**
+ * If true, the permission may not be required in all cases (e.g. it may only be
+ * enforced on certain platforms, or for certain call parameters, etc.
+ */
+ boolean conditional() default false;
+
+ /**
+ * Specifies that the given permission is required for read operations.
+ *
+ * When specified on a parameter, the annotation indicates that the method requires
+ * a permission which depends on the value of the parameter (and typically
+ * the corresponding field passed in will be one of a set of constants which have
+ * been annotated with a @RequiresPermission annotation.)
+ */
+ @Target({FIELD, METHOD, PARAMETER})
+ @interface Read {
+ RequiresPermission value() default @RequiresPermission;
+ }
+
+ /**
+ * Specifies that the given permission is required for write operations.
+ *
+ * When specified on a parameter, the annotation indicates that the method requires
+ * a permission which depends on the value of the parameter (and typically
+ * the corresponding field passed in will be one of a set of constants which have
+ * been annotated with a @RequiresPermission annotation.)
+ */
+ @Target({FIELD, METHOD, PARAMETER})
+ @interface Write {
+ RequiresPermission value() default @RequiresPermission;
+ }
+}
diff --git a/errorprone/java/com/google/errorprone/bugpatterns/android/BluetoothPermissionChecker.java b/errorprone/java/com/google/errorprone/bugpatterns/android/BluetoothPermissionChecker.java
new file mode 100644
index 0000000000000..9d1cf87a5f9dc
--- /dev/null
+++ b/errorprone/java/com/google/errorprone/bugpatterns/android/BluetoothPermissionChecker.java
@@ -0,0 +1,213 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.errorprone.bugpatterns.android;
+
+import static com.google.errorprone.BugPattern.SeverityLevel.WARNING;
+import static com.google.errorprone.bugpatterns.android.RequiresPermissionChecker.simpleNameMatches;
+import static com.google.errorprone.matchers.Matchers.allOf;
+import static com.google.errorprone.matchers.Matchers.anyOf;
+import static com.google.errorprone.matchers.Matchers.enclosingClass;
+import static com.google.errorprone.matchers.Matchers.isStatic;
+import static com.google.errorprone.matchers.Matchers.isSubtypeOf;
+import static com.google.errorprone.matchers.Matchers.methodHasVisibility;
+import static com.google.errorprone.matchers.Matchers.methodIsConstructor;
+import static com.google.errorprone.matchers.Matchers.methodIsNamed;
+import static com.google.errorprone.matchers.Matchers.not;
+import static com.google.errorprone.matchers.Matchers.packageStartsWith;
+
+import android.annotation.RequiresNoPermission;
+import android.annotation.RequiresPermission;
+import android.annotation.SuppressLint;
+
+import com.google.auto.service.AutoService;
+import com.google.errorprone.BugPattern;
+import com.google.errorprone.VisitorState;
+import com.google.errorprone.bugpatterns.BugChecker;
+import com.google.errorprone.bugpatterns.BugChecker.MethodTreeMatcher;
+import com.google.errorprone.matchers.Description;
+import com.google.errorprone.matchers.Matcher;
+import com.google.errorprone.matchers.MethodVisibility.Visibility;
+import com.google.errorprone.util.ASTHelpers;
+import com.sun.source.tree.ClassTree;
+import com.sun.source.tree.MethodTree;
+import com.sun.source.tree.Tree;
+import com.sun.source.util.TreePath;
+import com.sun.tools.javac.code.Symbol;
+import com.sun.tools.javac.code.Symbol.MethodSymbol;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.regex.Pattern;
+
+/**
+ * Verifies that all Bluetooth APIs have consistent permissions.
+ */
+@AutoService(BugChecker.class)
+@BugPattern(
+ name = "AndroidFrameworkBluetoothPermission",
+ summary = "Verifies that all Bluetooth APIs have consistent permissions",
+ severity = WARNING)
+public final class BluetoothPermissionChecker extends BugChecker implements MethodTreeMatcher {
+ private static final Matcher BLUETOOTH_API = allOf(
+ packageStartsWith("android.bluetooth"),
+ methodHasVisibility(Visibility.PUBLIC),
+ not(isStatic()),
+ not(methodIsConstructor()),
+ not(enclosingClass(isInsideParcelable())),
+ not(enclosingClass(simpleNameMatches(Pattern.compile(".+Callback$")))),
+ not(enclosingClass(isSubtypeOf("android.bluetooth.BluetoothProfileConnector"))),
+ not(enclosingClass(isSubtypeOf("android.app.PropertyInvalidatedCache"))));
+
+ private static final Matcher PARCELABLE_CLASS =
+ isSubtypeOf("android.os.Parcelable");
+ private static final Matcher BINDER_METHOD = enclosingClass(
+ isSubtypeOf("android.os.IInterface"));
+
+ private static final Matcher BINDER_INTERNALS = allOf(
+ enclosingClass(isSubtypeOf("android.os.IInterface")),
+ anyOf(
+ methodIsNamed("onTransact"),
+ methodIsNamed("dump"),
+ enclosingClass(simpleNameMatches(Pattern.compile("^(Stub|Default|Proxy)$")))));
+
+ private static final Matcher GENERIC_INTERNALS = anyOf(
+ methodIsNamed("close"),
+ methodIsNamed("finalize"),
+ methodIsNamed("equals"),
+ methodIsNamed("hashCode"),
+ methodIsNamed("toString"));
+
+ private static final String PERMISSION_ADVERTISE = "android.permission.BLUETOOTH_ADVERTISE";
+ private static final String PERMISSION_CONNECT = "android.permission.BLUETOOTH_CONNECT";
+ private static final String PERMISSION_SCAN = "android.permission.BLUETOOTH_SCAN";
+
+ private static final String ANNOTATION_ADVERTISE =
+ "android.bluetooth.annotations.RequiresBluetoothAdvertisePermission";
+ private static final String ANNOTATION_CONNECT =
+ "android.bluetooth.annotations.RequiresBluetoothConnectPermission";
+ private static final String ANNOTATION_SCAN =
+ "android.bluetooth.annotations.RequiresBluetoothScanPermission";
+
+ @Override
+ public Description matchMethod(MethodTree tree, VisitorState state) {
+ // Ignore methods outside Bluetooth area
+ if (!BLUETOOTH_API.matches(tree, state)) return Description.NO_MATCH;
+
+ // Ignore certain types of generated or internal code
+ if (BINDER_INTERNALS.matches(tree, state)) return Description.NO_MATCH;
+ if (GENERIC_INTERNALS.matches(tree, state)) return Description.NO_MATCH;
+
+ // Skip abstract methods, except for binder interfaces
+ if (tree.getBody() == null && !BINDER_METHOD.matches(tree, state)) {
+ return Description.NO_MATCH;
+ }
+
+ // Ignore callbacks which don't need permission enforcement
+ final MethodSymbol symbol = ASTHelpers.getSymbol(tree);
+ if (isCallbackOrWrapper(symbol)) return Description.NO_MATCH;
+
+ // Ignore when suppressed
+ if (isSuppressed(symbol)) return Description.NO_MATCH;
+
+ final RequiresPermission requiresPerm = ASTHelpers.getAnnotation(tree,
+ RequiresPermission.class);
+ final RequiresNoPermission requiresNoPerm = ASTHelpers.getAnnotation(tree,
+ RequiresNoPermission.class);
+
+ final boolean requiresValid = requiresPerm != null
+ && (requiresPerm.value() != null || requiresPerm.allOf() != null);
+ final boolean requiresNoValid = requiresNoPerm != null;
+ if (!requiresValid && !requiresNoValid) {
+ return buildDescription(tree)
+ .setMessage("Method " + symbol.name.toString()
+ + "() must be protected by at least one permission")
+ .build();
+ }
+
+ // No additional checks needed for Binder generated code
+ if (BINDER_METHOD.matches(tree, state)) return Description.NO_MATCH;
+
+ if (ASTHelpers.hasAnnotation(tree, ANNOTATION_ADVERTISE,
+ state) != isPermissionReferenced(requiresPerm, PERMISSION_ADVERTISE)) {
+ return buildDescription(tree)
+ .setMessage("Method " + symbol.name.toString()
+ + "() has inconsistent annotations for " + PERMISSION_ADVERTISE)
+ .build();
+ }
+ if (ASTHelpers.hasAnnotation(tree, ANNOTATION_CONNECT,
+ state) != isPermissionReferenced(requiresPerm, PERMISSION_CONNECT)) {
+ return buildDescription(tree)
+ .setMessage("Method " + symbol.name.toString()
+ + "() has inconsistent annotations for " + PERMISSION_CONNECT)
+ .build();
+ }
+ if (ASTHelpers.hasAnnotation(tree, ANNOTATION_SCAN,
+ state) != isPermissionReferenced(requiresPerm, PERMISSION_SCAN)) {
+ return buildDescription(tree)
+ .setMessage("Method " + symbol.name.toString()
+ + "() has inconsistent annotations for " + PERMISSION_SCAN)
+ .build();
+ }
+
+ return Description.NO_MATCH;
+ }
+
+ private static boolean isPermissionReferenced(RequiresPermission anno, String perm) {
+ if (anno == null) return false;
+ if (perm.equals(anno.value())) return true;
+ return anno.allOf() != null && Arrays.asList(anno.allOf()).contains(perm);
+ }
+
+ private static boolean isCallbackOrWrapper(Symbol symbol) {
+ if (symbol == null) return false;
+ final String name = symbol.name.toString();
+ return isCallbackOrWrapper(ASTHelpers.enclosingClass(symbol))
+ || name.endsWith("Callback")
+ || name.endsWith("Wrapper");
+ }
+
+ public boolean isSuppressed(Symbol symbol) {
+ if (symbol == null) return false;
+ return isSuppressed(ASTHelpers.enclosingClass(symbol))
+ || isSuppressed(ASTHelpers.getAnnotation(symbol, SuppressWarnings.class))
+ || isSuppressed(ASTHelpers.getAnnotation(symbol, SuppressLint.class));
+ }
+
+ private boolean isSuppressed(SuppressWarnings anno) {
+ return (anno != null) && !Collections.disjoint(Arrays.asList(anno.value()), allNames());
+ }
+
+ private boolean isSuppressed(SuppressLint anno) {
+ return (anno != null) && !Collections.disjoint(Arrays.asList(anno.value()), allNames());
+ }
+
+ private static Matcher isInsideParcelable() {
+ return new Matcher() {
+ @Override
+ public boolean matches(ClassTree tree, VisitorState state) {
+ final TreePath path = state.getPath();
+ for (Tree node : path) {
+ if (node instanceof ClassTree
+ && PARCELABLE_CLASS.matches((ClassTree) node, state)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ };
+ }
+}
diff --git a/errorprone/java/com/google/errorprone/bugpatterns/android/RequiresPermissionChecker.java b/errorprone/java/com/google/errorprone/bugpatterns/android/RequiresPermissionChecker.java
index 3b5a58c46f713..f54782d4eb77d 100644
--- a/errorprone/java/com/google/errorprone/bugpatterns/android/RequiresPermissionChecker.java
+++ b/errorprone/java/com/google/errorprone/bugpatterns/android/RequiresPermissionChecker.java
@@ -143,8 +143,11 @@ public final class RequiresPermissionChecker extends BugChecker implements Metho
final ParsedRequiresPermission nodePerm = parseRequiresPermissionRecursively(
node, state);
if (!expectedPerm.containsAll(nodePerm)) {
- return buildDescription(node).setMessage("Annotated " + expectedPerm
- + " but too narrow; invokes method requiring " + nodePerm).build();
+ return buildDescription(node)
+ .setMessage("Method " + method.name.toString() + "() annotated "
+ + expectedPerm
+ + " but too narrow; invokes method requiring " + nodePerm)
+ .build();
} else {
actualPerm.addAll(nodePerm);
}
@@ -162,8 +165,10 @@ public final class RequiresPermissionChecker extends BugChecker implements Metho
// Second, determine if we actually used all permissions that we claim
// to require; yell if we're too broad
if (!actualPerm.containsAll(expectedPerm)) {
- return buildDescription(tree).setMessage("Annotated " + expectedPerm
- + " but too wide; only invokes methods requiring " + actualPerm).build();
+ return buildDescription(tree)
+ .setMessage("Method " + method.name.toString() + "() annotated " + expectedPerm
+ + " but too wide; only invokes methods requiring " + actualPerm)
+ .build();
}
return Description.NO_MATCH;
@@ -316,7 +321,7 @@ public final class RequiresPermissionChecker extends BugChecker implements Metho
return (anno != null) && !Collections.disjoint(Arrays.asList(anno.value()), allNames());
}
- private static Matcher simpleNameMatches(Pattern pattern) {
+ static Matcher simpleNameMatches(Pattern pattern) {
return new Matcher() {
@Override
public boolean matches(ClassTree tree, VisitorState state) {