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) {