Merge "Annotations for Bluetooth broadcast intents." into sc-dev
This commit is contained in:
@@ -9046,8 +9046,8 @@ package android.bluetooth {
|
||||
field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_CLASS_CHANGED = "android.bluetooth.device.action.CLASS_CHANGED";
|
||||
field @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) public static final String ACTION_FOUND = "android.bluetooth.device.action.FOUND";
|
||||
field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_NAME_CHANGED = "android.bluetooth.device.action.NAME_CHANGED";
|
||||
field @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) public static final String ACTION_PAIRING_REQUEST = "android.bluetooth.device.action.PAIRING_REQUEST";
|
||||
field @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) public static final String ACTION_UUID = "android.bluetooth.device.action.UUID";
|
||||
field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_PAIRING_REQUEST = "android.bluetooth.device.action.PAIRING_REQUEST";
|
||||
field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_UUID = "android.bluetooth.device.action.UUID";
|
||||
field public static final int ADDRESS_TYPE_PUBLIC = 0; // 0x0
|
||||
field public static final int ADDRESS_TYPE_RANDOM = 1; // 0x1
|
||||
field public static final int BOND_BONDED = 12; // 0xc
|
||||
|
||||
@@ -1922,7 +1922,7 @@ package android.bluetooth {
|
||||
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public int getConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice);
|
||||
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean isAudioPlaying(@NonNull android.bluetooth.BluetoothDevice);
|
||||
method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int);
|
||||
field @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.a2dp-sink.profile.action.CONNECTION_STATE_CHANGED";
|
||||
field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.a2dp-sink.profile.action.CONNECTION_STATE_CHANGED";
|
||||
}
|
||||
|
||||
public final class BluetoothAdapter {
|
||||
@@ -1974,7 +1974,7 @@ package android.bluetooth {
|
||||
field public static final int ACCESS_ALLOWED = 1; // 0x1
|
||||
field public static final int ACCESS_REJECTED = 2; // 0x2
|
||||
field public static final int ACCESS_UNKNOWN = 0; // 0x0
|
||||
field public static final String ACTION_SILENCE_MODE_CHANGED = "android.bluetooth.device.action.SILENCE_MODE_CHANGED";
|
||||
field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_SILENCE_MODE_CHANGED = "android.bluetooth.device.action.SILENCE_MODE_CHANGED";
|
||||
field public static final String DEVICE_TYPE_DEFAULT = "Default";
|
||||
field public static final String DEVICE_TYPE_UNTETHERED_HEADSET = "Untethered Headset";
|
||||
field public static final String DEVICE_TYPE_WATCH = "Watch";
|
||||
@@ -2036,7 +2036,7 @@ package android.bluetooth {
|
||||
method @NonNull @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
|
||||
method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public int getConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice);
|
||||
method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int);
|
||||
field public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.map.profile.action.CONNECTION_STATE_CHANGED";
|
||||
field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.map.profile.action.CONNECTION_STATE_CHANGED";
|
||||
}
|
||||
|
||||
public final class BluetoothMapClient implements android.bluetooth.BluetoothProfile {
|
||||
@@ -2065,7 +2065,7 @@ package android.bluetooth {
|
||||
public class BluetoothPbap implements android.bluetooth.BluetoothProfile {
|
||||
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public int getConnectionState(@NonNull android.bluetooth.BluetoothDevice);
|
||||
method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int);
|
||||
field @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.pbap.profile.action.CONNECTION_STATE_CHANGED";
|
||||
field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.pbap.profile.action.CONNECTION_STATE_CHANGED";
|
||||
}
|
||||
|
||||
public interface BluetoothProfile {
|
||||
|
||||
@@ -27,7 +27,19 @@ import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Denotes that the annotated element requires no permissions.
|
||||
* <p>
|
||||
* This explicit annotation helps distinguish which of three states that an
|
||||
* element may exist in:
|
||||
* <ul>
|
||||
* <li>Annotated with {@link RequiresPermission}, indicating that an element
|
||||
* requires (or may require) one or more permissions.
|
||||
* <li>Annotated with {@link RequiresNoPermission}, indicating that an element
|
||||
* requires no permissions.
|
||||
* <li>Neither annotation, indicating that no explicit declaration about
|
||||
* permissions has been made for that element.
|
||||
* </ul>
|
||||
*
|
||||
* @see RequiresPermission
|
||||
* @hide
|
||||
*/
|
||||
@Retention(CLASS)
|
||||
|
||||
@@ -74,6 +74,7 @@ import java.lang.annotation.Target;
|
||||
* public static final String ACTION_CALL = "android.intent.action.CALL";
|
||||
* }</pre>
|
||||
*
|
||||
* @see RequiresNoPermission
|
||||
* @hide
|
||||
*/
|
||||
@Retention(CLASS)
|
||||
|
||||
@@ -104,6 +104,8 @@ public final class BluetoothA2dp implements BluetoothProfile {
|
||||
"android.bluetooth.a2dp.profile.action.PLAYING_STATE_CHANGED";
|
||||
|
||||
/** @hide */
|
||||
@RequiresBluetoothConnectPermission
|
||||
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
|
||||
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
|
||||
public static final String ACTION_AVRCP_CONNECTION_STATE_CHANGED =
|
||||
"android.bluetooth.a2dp.profile.action.AVRCP_CONNECTION_STATE_CHANGED";
|
||||
|
||||
@@ -19,8 +19,10 @@ package android.bluetooth;
|
||||
import android.Manifest;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.RequiresPermission;
|
||||
import android.annotation.SdkConstant;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.annotation.SystemApi;
|
||||
import android.annotation.SdkConstant.SdkConstantType;
|
||||
import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
|
||||
import android.bluetooth.annotations.RequiresLegacyBluetoothAdminPermission;
|
||||
import android.bluetooth.annotations.RequiresLegacyBluetoothPermission;
|
||||
@@ -70,7 +72,9 @@ public final class BluetoothA2dpSink implements BluetoothProfile {
|
||||
*/
|
||||
@SystemApi
|
||||
@SuppressLint("ActionValue")
|
||||
@RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
|
||||
@RequiresBluetoothConnectPermission
|
||||
@RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT)
|
||||
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
|
||||
public static final String ACTION_CONNECTION_STATE_CHANGED =
|
||||
"android.bluetooth.a2dp-sink.profile.action.CONNECTION_STATE_CHANGED";
|
||||
|
||||
|
||||
@@ -604,6 +604,7 @@ public final class BluetoothAdapter {
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
|
||||
@SystemApi public static final String ACTION_BLE_STATE_CHANGED =
|
||||
"android.bluetooth.adapter.action.BLE_STATE_CHANGED";
|
||||
|
||||
@@ -618,6 +619,9 @@ public final class BluetoothAdapter {
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@RequiresBluetoothConnectPermission
|
||||
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
|
||||
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
|
||||
public static final String ACTION_BLUETOOTH_ADDRESS_CHANGED =
|
||||
"android.bluetooth.adapter.action.BLUETOOTH_ADDRESS_CHANGED";
|
||||
|
||||
@@ -642,6 +646,9 @@ public final class BluetoothAdapter {
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@RequiresBluetoothConnectPermission
|
||||
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
|
||||
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
|
||||
public static final String ACTION_BLE_ACL_CONNECTED =
|
||||
"android.bluetooth.adapter.action.BLE_ACL_CONNECTED";
|
||||
|
||||
@@ -656,6 +663,9 @@ public final class BluetoothAdapter {
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@RequiresBluetoothConnectPermission
|
||||
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
|
||||
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
|
||||
public static final String ACTION_BLE_ACL_DISCONNECTED =
|
||||
"android.bluetooth.adapter.action.BLE_ACL_DISCONNECTED";
|
||||
|
||||
|
||||
@@ -17,7 +17,9 @@
|
||||
package android.bluetooth;
|
||||
|
||||
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;
|
||||
import android.content.Context;
|
||||
@@ -62,6 +64,7 @@ public final class BluetoothAvrcpController implements BluetoothProfile {
|
||||
@RequiresLegacyBluetoothPermission
|
||||
@RequiresBluetoothConnectPermission
|
||||
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
|
||||
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
|
||||
public static final String ACTION_CONNECTION_STATE_CHANGED =
|
||||
"android.bluetooth.avrcp-controller.profile.action.CONNECTION_STATE_CHANGED";
|
||||
|
||||
@@ -74,6 +77,9 @@ public final class BluetoothAvrcpController implements BluetoothProfile {
|
||||
* most recent player setting. </li>
|
||||
* </ul>
|
||||
*/
|
||||
@RequiresBluetoothConnectPermission
|
||||
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
|
||||
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
|
||||
public static final String ACTION_PLAYER_SETTING =
|
||||
"android.bluetooth.avrcp-controller.profile.action.PLAYER_SETTING";
|
||||
|
||||
|
||||
@@ -389,6 +389,8 @@ public final class BluetoothDevice implements Parcelable {
|
||||
|
||||
|
||||
/** @hide */
|
||||
@RequiresBluetoothConnectPermission
|
||||
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
|
||||
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
|
||||
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
|
||||
public static final String ACTION_SDP_RECORD =
|
||||
@@ -663,13 +665,15 @@ public final class BluetoothDevice implements Parcelable {
|
||||
* <p> Always contains the extra field {@link #EXTRA_UUID}
|
||||
*/
|
||||
@RequiresLegacyBluetoothAdminPermission
|
||||
@RequiresBluetoothScanPermission
|
||||
@RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
|
||||
@RequiresBluetoothConnectPermission
|
||||
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
|
||||
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
|
||||
public static final String ACTION_UUID =
|
||||
"android.bluetooth.device.action.UUID";
|
||||
|
||||
/** @hide */
|
||||
@RequiresBluetoothConnectPermission
|
||||
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
|
||||
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
|
||||
public static final String ACTION_MAS_INSTANCE =
|
||||
"android.bluetooth.device.action.MAS_INSTANCE";
|
||||
@@ -693,28 +697,36 @@ public final class BluetoothDevice implements Parcelable {
|
||||
* Broadcast Action: This intent is used to broadcast PAIRING REQUEST
|
||||
*/
|
||||
@RequiresLegacyBluetoothAdminPermission
|
||||
@RequiresBluetoothScanPermission
|
||||
@RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
|
||||
@RequiresBluetoothConnectPermission
|
||||
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
|
||||
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
|
||||
public static final String ACTION_PAIRING_REQUEST =
|
||||
"android.bluetooth.device.action.PAIRING_REQUEST";
|
||||
/** @hide */
|
||||
@RequiresBluetoothConnectPermission
|
||||
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
|
||||
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
|
||||
@UnsupportedAppUsage
|
||||
public static final String ACTION_PAIRING_CANCEL =
|
||||
"android.bluetooth.device.action.PAIRING_CANCEL";
|
||||
|
||||
/** @hide */
|
||||
@RequiresBluetoothConnectPermission
|
||||
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
|
||||
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
|
||||
public static final String ACTION_CONNECTION_ACCESS_REQUEST =
|
||||
"android.bluetooth.device.action.CONNECTION_ACCESS_REQUEST";
|
||||
|
||||
/** @hide */
|
||||
@RequiresBluetoothConnectPermission
|
||||
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
|
||||
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
|
||||
public static final String ACTION_CONNECTION_ACCESS_REPLY =
|
||||
"android.bluetooth.device.action.CONNECTION_ACCESS_REPLY";
|
||||
|
||||
/** @hide */
|
||||
@RequiresBluetoothConnectPermission
|
||||
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
|
||||
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
|
||||
public static final String ACTION_CONNECTION_ACCESS_CANCEL =
|
||||
"android.bluetooth.device.action.CONNECTION_ACCESS_CANCEL";
|
||||
@@ -725,6 +737,8 @@ public final class BluetoothDevice implements Parcelable {
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@RequiresBluetoothConnectPermission
|
||||
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
|
||||
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
|
||||
@SystemApi
|
||||
public static final String ACTION_SILENCE_MODE_CHANGED =
|
||||
|
||||
@@ -16,8 +16,10 @@
|
||||
|
||||
package android.bluetooth;
|
||||
|
||||
import android.annotation.RequiresPermission;
|
||||
import android.annotation.SdkConstant;
|
||||
import android.annotation.SdkConstant.SdkConstantType;
|
||||
import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
|
||||
|
||||
/**
|
||||
* A helper to show a system "Device Picker" activity to the user.
|
||||
@@ -39,6 +41,8 @@ public interface BluetoothDevicePicker {
|
||||
* Selected {@link BluetoothDevice} is returned in extra data named
|
||||
* {@link BluetoothDevice#EXTRA_DEVICE}.
|
||||
*/
|
||||
@RequiresBluetoothConnectPermission
|
||||
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
|
||||
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
|
||||
public static final String ACTION_DEVICE_SELECTED =
|
||||
"android.bluetooth.devicepicker.action.DEVICE_SELECTED";
|
||||
@@ -54,6 +58,8 @@ public interface BluetoothDevicePicker {
|
||||
* - {@link #EXTRA_LAUNCH_CLASS} (string): where(which class) this intent
|
||||
* come from
|
||||
*/
|
||||
@RequiresBluetoothConnectPermission
|
||||
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
|
||||
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
|
||||
public static final String ACTION_LAUNCH =
|
||||
"android.bluetooth.devicepicker.action.LAUNCH";
|
||||
|
||||
@@ -310,6 +310,7 @@ public final class BluetoothHeadset implements BluetoothProfile {
|
||||
@RequiresLegacyBluetoothPermission
|
||||
@RequiresBluetoothConnectPermission
|
||||
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
|
||||
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
|
||||
public static final String ACTION_HF_INDICATORS_VALUE_CHANGED =
|
||||
"android.bluetooth.headset.action.HF_INDICATORS_VALUE_CHANGED";
|
||||
|
||||
|
||||
@@ -18,6 +18,8 @@ package android.bluetooth;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.RequiresPermission;
|
||||
import android.annotation.SdkConstant;
|
||||
import android.annotation.SdkConstant.SdkConstantType;
|
||||
import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
|
||||
import android.bluetooth.annotations.RequiresLegacyBluetoothPermission;
|
||||
import android.compat.annotation.UnsupportedAppUsage;
|
||||
@@ -72,6 +74,9 @@ public final class BluetoothHeadsetClient implements BluetoothProfile {
|
||||
* booleans with value <code>true</code>,
|
||||
* and not supported ones are <strong>not</strong> being sent at all.</p>
|
||||
*/
|
||||
@RequiresBluetoothConnectPermission
|
||||
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
|
||||
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
|
||||
public static final String ACTION_CONNECTION_STATE_CHANGED =
|
||||
"android.bluetooth.headsetclient.profile.action.CONNECTION_STATE_CHANGED";
|
||||
|
||||
@@ -90,6 +95,9 @@ public final class BluetoothHeadsetClient implements BluetoothProfile {
|
||||
* it also includes {@link #EXTRA_AUDIO_WBS}
|
||||
* indicating wide band speech support.</p>
|
||||
*/
|
||||
@RequiresBluetoothConnectPermission
|
||||
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
|
||||
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
|
||||
public static final String ACTION_AUDIO_STATE_CHANGED =
|
||||
"android.bluetooth.headsetclient.profile.action.AUDIO_STATE_CHANGED";
|
||||
|
||||
@@ -106,6 +114,9 @@ public final class BluetoothHeadsetClient implements BluetoothProfile {
|
||||
* {@link #EXTRA_VOICE_RECOGNITION},
|
||||
* {@link #EXTRA_IN_BAND_RING}</p>
|
||||
*/
|
||||
@RequiresBluetoothConnectPermission
|
||||
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
|
||||
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
|
||||
public static final String ACTION_AG_EVENT =
|
||||
"android.bluetooth.headsetclient.profile.action.AG_EVENT";
|
||||
|
||||
@@ -117,6 +128,9 @@ public final class BluetoothHeadsetClient implements BluetoothProfile {
|
||||
* with value of {@link BluetoothHeadsetClientCall} instance,
|
||||
* representing actual call state.</p>
|
||||
*/
|
||||
@RequiresBluetoothConnectPermission
|
||||
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
|
||||
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
|
||||
public static final String ACTION_CALL_CHANGED =
|
||||
"android.bluetooth.headsetclient.profile.action.AG_CALL_CHANGED";
|
||||
|
||||
@@ -127,6 +141,9 @@ public final class BluetoothHeadsetClient implements BluetoothProfile {
|
||||
* like <code>ACTION_AG_EVENT</code> with <code>EXTRA_VOICE_RECOGNITION</code> value
|
||||
* when for example user started voice recognition from HF unit.
|
||||
*/
|
||||
@RequiresBluetoothConnectPermission
|
||||
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
|
||||
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
|
||||
public static final String ACTION_RESULT =
|
||||
"android.bluetooth.headsetclient.profile.action.RESULT";
|
||||
|
||||
@@ -138,6 +155,9 @@ public final class BluetoothHeadsetClient implements BluetoothProfile {
|
||||
* Vendor event can be a response to an vendor specific command or unsolicited.
|
||||
*
|
||||
*/
|
||||
@RequiresBluetoothConnectPermission
|
||||
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
|
||||
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
|
||||
public static final String ACTION_VENDOR_SPECIFIC_HEADSETCLIENT_EVENT =
|
||||
"android.bluetooth.headsetclient.profile.action.VENDOR_SPECIFIC_EVENT";
|
||||
|
||||
@@ -149,6 +169,9 @@ public final class BluetoothHeadsetClient implements BluetoothProfile {
|
||||
* {@link #EXTRA_NUMBER},
|
||||
* with a <code>String</code> value representing phone number.</p>
|
||||
*/
|
||||
@RequiresBluetoothConnectPermission
|
||||
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
|
||||
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
|
||||
public static final String ACTION_LAST_VTAG =
|
||||
"android.bluetooth.headsetclient.profile.action.LAST_VTAG";
|
||||
|
||||
|
||||
@@ -80,6 +80,8 @@ public final class BluetoothHidHost implements BluetoothProfile {
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
@RequiresBluetoothConnectPermission
|
||||
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
|
||||
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
|
||||
public static final String ACTION_PROTOCOL_MODE_CHANGED =
|
||||
"android.bluetooth.input.profile.action.PROTOCOL_MODE_CHANGED";
|
||||
@@ -87,6 +89,8 @@ public final class BluetoothHidHost implements BluetoothProfile {
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
@RequiresBluetoothConnectPermission
|
||||
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
|
||||
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
|
||||
public static final String ACTION_HANDSHAKE =
|
||||
"android.bluetooth.input.profile.action.HANDSHAKE";
|
||||
@@ -94,6 +98,8 @@ public final class BluetoothHidHost implements BluetoothProfile {
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
@RequiresBluetoothConnectPermission
|
||||
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
|
||||
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
|
||||
public static final String ACTION_REPORT =
|
||||
"android.bluetooth.input.profile.action.REPORT";
|
||||
@@ -101,6 +107,8 @@ public final class BluetoothHidHost implements BluetoothProfile {
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
@RequiresBluetoothConnectPermission
|
||||
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
|
||||
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
|
||||
public static final String ACTION_VIRTUAL_UNPLUG_STATUS =
|
||||
"android.bluetooth.input.profile.action.VIRTUAL_UNPLUG_STATUS";
|
||||
@@ -108,6 +116,8 @@ public final class BluetoothHidHost implements BluetoothProfile {
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
@RequiresBluetoothConnectPermission
|
||||
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
|
||||
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
|
||||
public static final String ACTION_IDLE_TIME_CHANGED =
|
||||
"android.bluetooth.input.profile.action.IDLE_TIME_CHANGED";
|
||||
|
||||
@@ -20,8 +20,10 @@ import android.Manifest;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.RequiresNoPermission;
|
||||
import android.annotation.RequiresPermission;
|
||||
import android.annotation.SdkConstant;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.annotation.SystemApi;
|
||||
import android.annotation.SdkConstant.SdkConstantType;
|
||||
import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
|
||||
import android.compat.annotation.UnsupportedAppUsage;
|
||||
import android.content.Context;
|
||||
@@ -53,6 +55,9 @@ public final class BluetoothMap implements BluetoothProfile, AutoCloseable {
|
||||
/** @hide */
|
||||
@SuppressLint("ActionValue")
|
||||
@SystemApi
|
||||
@RequiresBluetoothConnectPermission
|
||||
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
|
||||
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
|
||||
public static final String ACTION_CONNECTION_STATE_CHANGED =
|
||||
"android.bluetooth.map.profile.action.CONNECTION_STATE_CHANGED";
|
||||
|
||||
|
||||
@@ -20,8 +20,10 @@ import android.Manifest;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.RequiresPermission;
|
||||
import android.annotation.SdkConstant;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.annotation.SystemApi;
|
||||
import android.annotation.SdkConstant.SdkConstantType;
|
||||
import android.app.PendingIntent;
|
||||
import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
|
||||
import android.compat.annotation.UnsupportedAppUsage;
|
||||
@@ -50,16 +52,27 @@ public final class BluetoothMapClient implements BluetoothProfile {
|
||||
private static final boolean VDBG = Log.isLoggable(TAG, Log.VERBOSE);
|
||||
|
||||
/** @hide */
|
||||
@RequiresBluetoothConnectPermission
|
||||
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
|
||||
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
|
||||
public static final String ACTION_CONNECTION_STATE_CHANGED =
|
||||
"android.bluetooth.mapmce.profile.action.CONNECTION_STATE_CHANGED";
|
||||
/** @hide */
|
||||
@RequiresPermission(android.Manifest.permission.RECEIVE_SMS)
|
||||
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
|
||||
public static final String ACTION_MESSAGE_RECEIVED =
|
||||
"android.bluetooth.mapmce.profile.action.MESSAGE_RECEIVED";
|
||||
/* Actions to be used for pending intents */
|
||||
/** @hide */
|
||||
@RequiresBluetoothConnectPermission
|
||||
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
|
||||
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
|
||||
public static final String ACTION_MESSAGE_SENT_SUCCESSFULLY =
|
||||
"android.bluetooth.mapmce.profile.action.MESSAGE_SENT_SUCCESSFULLY";
|
||||
/** @hide */
|
||||
@RequiresBluetoothConnectPermission
|
||||
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
|
||||
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
|
||||
public static final String ACTION_MESSAGE_DELIVERED_SUCCESSFULLY =
|
||||
"android.bluetooth.mapmce.profile.action.MESSAGE_DELIVERED_SUCCESSFULLY";
|
||||
|
||||
@@ -68,6 +81,9 @@ public final class BluetoothMapClient implements BluetoothProfile {
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@RequiresBluetoothConnectPermission
|
||||
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
|
||||
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
|
||||
public static final String ACTION_MESSAGE_READ_STATUS_CHANGED =
|
||||
"android.bluetooth.mapmce.profile.action.MESSAGE_READ_STATUS_CHANGED";
|
||||
|
||||
@@ -76,6 +92,9 @@ public final class BluetoothMapClient implements BluetoothProfile {
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@RequiresBluetoothConnectPermission
|
||||
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
|
||||
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
|
||||
public static final String ACTION_MESSAGE_DELETED_STATUS_CHANGED =
|
||||
"android.bluetooth.mapmce.profile.action.MESSAGE_DELETED_STATUS_CHANGED";
|
||||
|
||||
|
||||
@@ -89,7 +89,8 @@ public class BluetoothPbap implements BluetoothProfile {
|
||||
*/
|
||||
@SuppressLint("ActionValue")
|
||||
@SystemApi
|
||||
@RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
|
||||
@RequiresBluetoothConnectPermission
|
||||
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
|
||||
@SdkConstant(SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION)
|
||||
public static final String ACTION_CONNECTION_STATE_CHANGED =
|
||||
"android.bluetooth.pbap.profile.action.CONNECTION_STATE_CHANGED";
|
||||
|
||||
@@ -19,7 +19,9 @@ package android.bluetooth;
|
||||
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.content.Context;
|
||||
import android.os.Binder;
|
||||
@@ -41,6 +43,9 @@ public final class BluetoothPbapClient implements BluetoothProfile {
|
||||
private static final boolean DBG = false;
|
||||
private static final boolean VDBG = false;
|
||||
|
||||
@RequiresBluetoothConnectPermission
|
||||
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
|
||||
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
|
||||
public static final String ACTION_CONNECTION_STATE_CHANGED =
|
||||
"android.bluetooth.pbapclient.profile.action.CONNECTION_STATE_CHANGED";
|
||||
|
||||
|
||||
@@ -19,7 +19,9 @@ package android.bluetooth;
|
||||
import android.Manifest;
|
||||
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.RequiresLegacyBluetoothPermission;
|
||||
import android.compat.annotation.UnsupportedAppUsage;
|
||||
@@ -70,6 +72,7 @@ public final class BluetoothSap implements BluetoothProfile {
|
||||
@RequiresLegacyBluetoothPermission
|
||||
@RequiresBluetoothConnectPermission
|
||||
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
|
||||
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
|
||||
public static final String ACTION_CONNECTION_STATE_CHANGED =
|
||||
"android.bluetooth.sap.profile.action.CONNECTION_STATE_CHANGED";
|
||||
|
||||
|
||||
36
errorprone/java/android/annotation/SdkConstant.java
Normal file
36
errorprone/java/android/annotation/SdkConstant.java
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (C) 2008 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 java.lang.annotation.Target;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
/**
|
||||
* Indicates a constant field value should be exported to be used in the SDK tools.
|
||||
* @hide
|
||||
*/
|
||||
@Target({ ElementType.FIELD })
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface SdkConstant {
|
||||
public static enum SdkConstantType {
|
||||
ACTIVITY_INTENT_ACTION, BROADCAST_INTENT_ACTION, SERVICE_ACTION, INTENT_CATEGORY, FEATURE;
|
||||
}
|
||||
|
||||
SdkConstantType value();
|
||||
}
|
||||
@@ -26,40 +26,49 @@ import static com.google.errorprone.matchers.Matchers.methodInvocation;
|
||||
import static com.google.errorprone.matchers.Matchers.methodIsNamed;
|
||||
import static com.google.errorprone.matchers.Matchers.staticMethod;
|
||||
|
||||
import android.annotation.RequiresPermission;
|
||||
import android.annotation.SuppressLint;
|
||||
|
||||
import com.google.auto.service.AutoService;
|
||||
import com.google.common.base.Objects;
|
||||
import com.google.errorprone.BugPattern;
|
||||
import com.google.errorprone.VisitorState;
|
||||
import com.google.errorprone.bugpatterns.BugChecker;
|
||||
import com.google.errorprone.bugpatterns.BugChecker.MethodInvocationTreeMatcher;
|
||||
import com.google.errorprone.bugpatterns.BugChecker.MethodTreeMatcher;
|
||||
import com.google.errorprone.matchers.Description;
|
||||
import com.google.errorprone.matchers.Matcher;
|
||||
import com.google.errorprone.util.ASTHelpers;
|
||||
import com.sun.source.tree.AssignmentTree;
|
||||
import com.sun.source.tree.ClassTree;
|
||||
import com.sun.source.tree.ExpressionTree;
|
||||
import com.sun.source.tree.IdentifierTree;
|
||||
import com.sun.source.tree.MemberSelectTree;
|
||||
import com.sun.source.tree.MethodInvocationTree;
|
||||
import com.sun.source.tree.MethodTree;
|
||||
import com.sun.source.tree.NewClassTree;
|
||||
import com.sun.source.tree.Tree;
|
||||
import com.sun.source.tree.VariableTree;
|
||||
import com.sun.source.util.TreeScanner;
|
||||
import com.sun.tools.javac.code.Symbol;
|
||||
import com.sun.tools.javac.code.Symbol.ClassSymbol;
|
||||
import com.sun.tools.javac.code.Symbol.MethodSymbol;
|
||||
import com.sun.tools.javac.code.Symbol.VarSymbol;
|
||||
import com.sun.tools.javac.code.Type;
|
||||
import com.sun.tools.javac.code.Type.ClassType;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import javax.lang.model.element.AnnotationMirror;
|
||||
import javax.lang.model.element.AnnotationValue;
|
||||
import javax.lang.model.element.ExecutableElement;
|
||||
import javax.lang.model.element.Name;
|
||||
|
||||
/**
|
||||
* Inspects both the client and server side of AIDL interfaces to ensure that
|
||||
@@ -71,9 +80,8 @@ import javax.lang.model.element.ExecutableElement;
|
||||
name = "AndroidFrameworkRequiresPermission",
|
||||
summary = "Verifies that @RequiresPermission annotations are consistent across AIDL",
|
||||
severity = WARNING)
|
||||
public final class RequiresPermissionChecker extends BugChecker implements MethodTreeMatcher {
|
||||
private static final String ANNOTATION_REQUIRES_PERMISSION = "RequiresPermission";
|
||||
|
||||
public final class RequiresPermissionChecker extends BugChecker
|
||||
implements MethodTreeMatcher, MethodInvocationTreeMatcher {
|
||||
private static final Matcher<ExpressionTree> ENFORCE_VIA_CONTEXT = methodInvocation(
|
||||
instanceMethod()
|
||||
.onDescendantOf("android.content.Context")
|
||||
@@ -110,6 +118,18 @@ public final class RequiresPermissionChecker extends BugChecker implements Metho
|
||||
private static final Matcher<ExpressionTree> RESTORE_CALL = methodInvocation(staticMethod()
|
||||
.onClass("android.os.Binder").withSignature("restoreCallingIdentity(long)"));
|
||||
|
||||
private static final Matcher<ExpressionTree> SEND_BROADCAST = methodInvocation(
|
||||
instanceMethod()
|
||||
.onDescendantOf("android.content.Context")
|
||||
.withNameMatching(Pattern.compile("^send(Ordered|Sticky)?Broadcast.*$")));
|
||||
private static final Matcher<ExpressionTree> SEND_PENDING_INTENT = methodInvocation(
|
||||
instanceMethod()
|
||||
.onDescendantOf("android.app.PendingIntent")
|
||||
.named("send"));
|
||||
|
||||
private static final Matcher<ExpressionTree> INTENT_SET_ACTION = methodInvocation(
|
||||
instanceMethod().onDescendantOf("android.content.Intent").named("setAction"));
|
||||
|
||||
@Override
|
||||
public Description matchMethod(MethodTree tree, VisitorState state) {
|
||||
// Ignore methods without an implementation
|
||||
@@ -166,7 +186,7 @@ public final class RequiresPermissionChecker extends BugChecker implements Metho
|
||||
// to require; yell if we're too broad
|
||||
if (!actualPerm.containsAll(expectedPerm)) {
|
||||
return buildDescription(tree)
|
||||
.setMessage("Method " + method.name.toString() + "() annotated " + expectedPerm
|
||||
.setMessage("Method " + method.name.toString() + "() annotated " + expectedPerm
|
||||
+ " but too wide; only invokes methods requiring " + actualPerm)
|
||||
.build();
|
||||
}
|
||||
@@ -174,6 +194,27 @@ public final class RequiresPermissionChecker extends BugChecker implements Metho
|
||||
return Description.NO_MATCH;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) {
|
||||
if (SEND_BROADCAST.matches(tree, state)) {
|
||||
final ParsedRequiresPermission sourcePerm =
|
||||
parseBroadcastSourceRequiresPermission(tree, state);
|
||||
final ParsedRequiresPermission targetPerm =
|
||||
parseBroadcastTargetRequiresPermission(tree, state);
|
||||
if (sourcePerm == null) {
|
||||
return buildDescription(tree)
|
||||
.setMessage("Failed to resolve broadcast intent action for validation")
|
||||
.build();
|
||||
} else if (!Objects.equal(sourcePerm, targetPerm)) {
|
||||
return buildDescription(tree)
|
||||
.setMessage("Broadcast annotated " + sourcePerm + " but protected with "
|
||||
+ targetPerm)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
return Description.NO_MATCH;
|
||||
}
|
||||
|
||||
static class ParsedRequiresPermission {
|
||||
final Set<String> allOf = new HashSet<>();
|
||||
final Set<String> anyOf = new HashSet<>();
|
||||
@@ -202,6 +243,16 @@ public final class RequiresPermissionChecker extends BugChecker implements Metho
|
||||
return allMet && anyMet;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj instanceof ParsedRequiresPermission) {
|
||||
final ParsedRequiresPermission other = (ParsedRequiresPermission) obj;
|
||||
return allOf.equals(other.allOf) && anyOf.equals(other.anyOf);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
if (isEmpty()) {
|
||||
@@ -215,39 +266,145 @@ public final class RequiresPermissionChecker extends BugChecker implements Metho
|
||||
return res;
|
||||
}
|
||||
|
||||
public static ParsedRequiresPermission from(RequiresPermission perm) {
|
||||
final ParsedRequiresPermission res = new ParsedRequiresPermission();
|
||||
res.addAll(perm);
|
||||
return res;
|
||||
}
|
||||
|
||||
public void addAll(ParsedRequiresPermission perm) {
|
||||
if (perm == null) return;
|
||||
this.allOf.addAll(perm.allOf);
|
||||
this.anyOf.addAll(perm.anyOf);
|
||||
}
|
||||
|
||||
public void addAll(AnnotationMirror a) {
|
||||
for (Map.Entry<? extends ExecutableElement, ? extends AnnotationValue> entry : a
|
||||
.getElementValues().entrySet()) {
|
||||
if (entry.getKey().getSimpleName().contentEquals("value")) {
|
||||
maybeAdd(allOf, entry.getValue());
|
||||
} else if (entry.getKey().getSimpleName().contentEquals("allOf")) {
|
||||
maybeAdd(allOf, entry.getValue());
|
||||
} else if (entry.getKey().getSimpleName().contentEquals("anyOf")) {
|
||||
maybeAdd(anyOf, entry.getValue());
|
||||
}
|
||||
}
|
||||
public void addAll(RequiresPermission perm) {
|
||||
if (perm == null) return;
|
||||
if (!perm.value().isEmpty()) this.allOf.add(perm.value());
|
||||
if (perm.allOf() != null) this.allOf.addAll(Arrays.asList(perm.allOf()));
|
||||
if (perm.anyOf() != null) this.anyOf.addAll(Arrays.asList(perm.anyOf()));
|
||||
}
|
||||
|
||||
private static void maybeAdd(Set<String> set, Object value) {
|
||||
if (value instanceof AnnotationValue) {
|
||||
maybeAdd(set, ((AnnotationValue) value).getValue());
|
||||
} else if (value instanceof String) {
|
||||
set.add((String) value);
|
||||
} else if (value instanceof Collection) {
|
||||
for (Object o : (Collection) value) {
|
||||
maybeAdd(set, o);
|
||||
}
|
||||
} else {
|
||||
throw new RuntimeException(String.valueOf(value.getClass()));
|
||||
public void addConstValue(Tree tree) {
|
||||
final Object value = ASTHelpers.constValue(tree);
|
||||
if (value != null) {
|
||||
allOf.add(String.valueOf(value));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static ExpressionTree findArgumentByParameterName(MethodInvocationTree tree,
|
||||
Predicate<String> paramName) {
|
||||
final MethodSymbol sym = ASTHelpers.getSymbol(tree);
|
||||
final List<VarSymbol> params = sym.getParameters();
|
||||
for (int i = 0; i < params.size(); i++) {
|
||||
if (paramName.test(params.get(i).name.toString())) {
|
||||
return tree.getArguments().get(i);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static Name resolveName(ExpressionTree tree) {
|
||||
if (tree instanceof IdentifierTree) {
|
||||
return ((IdentifierTree) tree).getName();
|
||||
} else if (tree instanceof MemberSelectTree) {
|
||||
return resolveName(((MemberSelectTree) tree).getExpression());
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static ParsedRequiresPermission parseIntentAction(NewClassTree tree) {
|
||||
final Optional<? extends ExpressionTree> arg = tree.getArguments().stream().findFirst();
|
||||
if (arg.isPresent()) {
|
||||
return ParsedRequiresPermission.from(
|
||||
ASTHelpers.getAnnotation(arg.get(), RequiresPermission.class));
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static ParsedRequiresPermission parseIntentAction(MethodInvocationTree tree) {
|
||||
return ParsedRequiresPermission.from(ASTHelpers.getAnnotation(
|
||||
tree.getArguments().get(0), RequiresPermission.class));
|
||||
}
|
||||
|
||||
private static ParsedRequiresPermission parseBroadcastSourceRequiresPermission(
|
||||
MethodInvocationTree methodTree, VisitorState state) {
|
||||
final ExpressionTree arg = findArgumentByParameterName(methodTree,
|
||||
(name) -> name.toLowerCase().contains("intent"));
|
||||
if (arg instanceof IdentifierTree) {
|
||||
final Name argName = ((IdentifierTree) arg).getName();
|
||||
final MethodTree method = state.findEnclosing(MethodTree.class);
|
||||
final AtomicReference<ParsedRequiresPermission> res = new AtomicReference<>();
|
||||
method.accept(new TreeScanner<Void, Void>() {
|
||||
private ParsedRequiresPermission last;
|
||||
|
||||
@Override
|
||||
public Void visitMethodInvocation(MethodInvocationTree tree, Void param) {
|
||||
if (Objects.equal(methodTree, tree)) {
|
||||
res.set(last);
|
||||
} else {
|
||||
final Name name = resolveName(tree.getMethodSelect());
|
||||
if (Objects.equal(argName, name)
|
||||
&& INTENT_SET_ACTION.matches(tree, state)) {
|
||||
last = parseIntentAction(tree);
|
||||
}
|
||||
}
|
||||
return super.visitMethodInvocation(tree, param);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visitAssignment(AssignmentTree tree, Void param) {
|
||||
final Name name = resolveName(tree.getVariable());
|
||||
final Tree init = tree.getExpression();
|
||||
if (Objects.equal(argName, name)
|
||||
&& init instanceof NewClassTree) {
|
||||
last = parseIntentAction((NewClassTree) init);
|
||||
}
|
||||
return super.visitAssignment(tree, param);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visitVariable(VariableTree tree, Void param) {
|
||||
final Name name = tree.getName();
|
||||
final ExpressionTree init = tree.getInitializer();
|
||||
if (Objects.equal(argName, name)
|
||||
&& init instanceof NewClassTree) {
|
||||
last = parseIntentAction((NewClassTree) init);
|
||||
}
|
||||
return super.visitVariable(tree, param);
|
||||
}
|
||||
}, null);
|
||||
return res.get();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static ParsedRequiresPermission parseBroadcastTargetRequiresPermission(
|
||||
MethodInvocationTree tree, VisitorState state) {
|
||||
final ExpressionTree arg = findArgumentByParameterName(tree,
|
||||
(name) -> name.toLowerCase().contains("permission"));
|
||||
final ParsedRequiresPermission res = new ParsedRequiresPermission();
|
||||
if (arg != null) {
|
||||
arg.accept(new TreeScanner<Void, Void>() {
|
||||
@Override
|
||||
public Void visitIdentifier(IdentifierTree tree, Void param) {
|
||||
res.addConstValue(tree);
|
||||
return super.visitIdentifier(tree, param);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visitMemberSelect(MemberSelectTree tree, Void param) {
|
||||
res.addConstValue(tree);
|
||||
return super.visitMemberSelect(tree, param);
|
||||
}
|
||||
}, null);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
private static ParsedRequiresPermission parseRequiresPermissionRecursively(
|
||||
MethodInvocationTree tree, VisitorState state) {
|
||||
if (ENFORCE_VIA_CONTEXT.matches(tree, state)) {
|
||||
@@ -276,12 +433,7 @@ public final class RequiresPermissionChecker extends BugChecker implements Metho
|
||||
|
||||
final ParsedRequiresPermission res = new ParsedRequiresPermission();
|
||||
for (MethodSymbol symbol : symbols) {
|
||||
for (AnnotationMirror a : symbol.getAnnotationMirrors()) {
|
||||
if (a.getAnnotationType().asElement().getSimpleName()
|
||||
.contentEquals(ANNOTATION_REQUIRES_PERMISSION)) {
|
||||
res.addAll(a);
|
||||
}
|
||||
}
|
||||
res.addAll(symbol.getAnnotation(RequiresPermission.class));
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -38,6 +38,7 @@ public class ContextUserIdCheckerTest {
|
||||
compilationHelper
|
||||
.addSourceFile("/android/annotation/SystemService.java")
|
||||
.addSourceFile("/android/content/Context.java")
|
||||
.addSourceFile("/android/content/Intent.java")
|
||||
.addSourceFile("/android/foo/IFooService.java")
|
||||
.addSourceFile("/android/os/IInterface.java")
|
||||
.addSourceFile("/android/os/RemoteException.java")
|
||||
@@ -68,6 +69,7 @@ public class ContextUserIdCheckerTest {
|
||||
compilationHelper
|
||||
.addSourceFile("/android/annotation/SystemService.java")
|
||||
.addSourceFile("/android/content/Context.java")
|
||||
.addSourceFile("/android/content/Intent.java")
|
||||
.addSourceFile("/android/foo/IFooService.java")
|
||||
.addSourceFile("/android/os/IInterface.java")
|
||||
.addSourceFile("/android/os/UserHandle.java")
|
||||
@@ -98,6 +100,7 @@ public class ContextUserIdCheckerTest {
|
||||
compilationHelper
|
||||
.addSourceFile("/android/annotation/SystemService.java")
|
||||
.addSourceFile("/android/content/Context.java")
|
||||
.addSourceFile("/android/content/Intent.java")
|
||||
.addSourceFile("/android/foo/IFooService.java")
|
||||
.addSourceFile("/android/os/IInterface.java")
|
||||
.addSourceFile("/android/os/UserHandle.java")
|
||||
@@ -124,6 +127,7 @@ public class ContextUserIdCheckerTest {
|
||||
compilationHelper
|
||||
.addSourceFile("/android/annotation/SystemService.java")
|
||||
.addSourceFile("/android/content/Context.java")
|
||||
.addSourceFile("/android/content/Intent.java")
|
||||
.addSourceFile("/android/foo/IFooService.java")
|
||||
.addSourceFile("/android/os/IInterface.java")
|
||||
.addSourceFile("/android/os/UserHandle.java")
|
||||
|
||||
@@ -81,6 +81,7 @@ public class RequiresPermissionCheckerTest {
|
||||
compilationHelper
|
||||
.addSourceFile("/android/annotation/RequiresPermission.java")
|
||||
.addSourceFile("/android/content/Context.java")
|
||||
.addSourceFile("/android/content/Intent.java")
|
||||
.addSourceLines("ColorManager.java",
|
||||
"import android.annotation.RequiresPermission;",
|
||||
"import android.content.Context;",
|
||||
@@ -139,6 +140,7 @@ public class RequiresPermissionCheckerTest {
|
||||
compilationHelper
|
||||
.addSourceFile("/android/annotation/RequiresPermission.java")
|
||||
.addSourceFile("/android/content/Context.java")
|
||||
.addSourceFile("/android/content/Intent.java")
|
||||
.addSourceFile("/android/foo/IColorService.java")
|
||||
.addSourceFile("/android/os/IInterface.java")
|
||||
.addSourceLines("ColorService.java",
|
||||
@@ -322,4 +324,95 @@ public class RequiresPermissionCheckerTest {
|
||||
"}")
|
||||
.doTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSendBroadcast() {
|
||||
compilationHelper
|
||||
.addSourceFile("/android/annotation/RequiresPermission.java")
|
||||
.addSourceFile("/android/annotation/SdkConstant.java")
|
||||
.addSourceFile("/android/content/Context.java")
|
||||
.addSourceFile("/android/content/Intent.java")
|
||||
.addSourceLines("FooManager.java",
|
||||
"import android.annotation.RequiresPermission;",
|
||||
"import android.annotation.SdkConstant;",
|
||||
"import android.content.Context;",
|
||||
"import android.content.Intent;",
|
||||
"public class FooManager {",
|
||||
" private static final String PERMISSION_RED = \"red\";",
|
||||
" private static final String PERMISSION_BLUE = \"blue\";",
|
||||
" @SdkConstant(SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION)",
|
||||
" private static final String ACTION_NONE = \"none\";",
|
||||
" @RequiresPermission(PERMISSION_RED)",
|
||||
" @SdkConstant(SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION)",
|
||||
" private static final String ACTION_RED = \"red\";",
|
||||
" @RequiresPermission(allOf={PERMISSION_RED,PERMISSION_BLUE})",
|
||||
" @SdkConstant(SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION)",
|
||||
" private static final String ACTION_RED_BLUE = \"red_blue\";",
|
||||
" public void exampleNone(Context context) {",
|
||||
" Intent intent = new Intent(ACTION_NONE);",
|
||||
" context.sendBroadcast(intent);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" context.sendBroadcast(intent, PERMISSION_RED);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" context.sendBroadcastWithMultiplePermissions(intent,",
|
||||
" new String[] { PERMISSION_RED });",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" context.sendBroadcastWithMultiplePermissions(intent,",
|
||||
" new String[] { PERMISSION_RED, PERMISSION_BLUE });",
|
||||
" }",
|
||||
" public void exampleRed(Context context) {",
|
||||
" Intent intent = new Intent(FooManager.ACTION_RED);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" context.sendBroadcast(intent);",
|
||||
" context.sendBroadcast(intent, FooManager.PERMISSION_RED);",
|
||||
" context.sendBroadcastWithMultiplePermissions(intent,",
|
||||
" new String[] { FooManager.PERMISSION_RED });",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" context.sendBroadcastWithMultiplePermissions(intent,",
|
||||
" new String[] { FooManager.PERMISSION_RED, PERMISSION_BLUE });",
|
||||
" }",
|
||||
" public void exampleRedBlue(Context context) {",
|
||||
" Intent intent = new Intent(ACTION_RED_BLUE);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" context.sendBroadcast(intent);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" context.sendBroadcast(intent, PERMISSION_RED);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" context.sendBroadcastWithMultiplePermissions(intent,",
|
||||
" new String[] { PERMISSION_RED });",
|
||||
" context.sendBroadcastWithMultiplePermissions(intent,",
|
||||
" new String[] { PERMISSION_RED, PERMISSION_BLUE });",
|
||||
" }",
|
||||
" public void exampleUnknown(Context context, Intent intent) {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" context.sendBroadcast(intent);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" context.sendBroadcast(intent, PERMISSION_RED);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" context.sendBroadcastWithMultiplePermissions(intent,",
|
||||
" new String[] { PERMISSION_RED });",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" context.sendBroadcastWithMultiplePermissions(intent,",
|
||||
" new String[] { PERMISSION_RED, PERMISSION_BLUE });",
|
||||
" }",
|
||||
" public void exampleReuse(Context context) {",
|
||||
" Intent intent = new Intent(ACTION_RED);",
|
||||
" context.sendBroadcast(intent, PERMISSION_RED);",
|
||||
" intent = new Intent(ACTION_NONE);",
|
||||
" context.sendBroadcast(intent);",
|
||||
" intent.setAction(ACTION_RED);",
|
||||
" context.sendBroadcast(intent, PERMISSION_RED);",
|
||||
" }",
|
||||
" public void exampleScoped(Context context) {",
|
||||
" if (true) {",
|
||||
" Intent intent = new Intent(ACTION_RED);",
|
||||
" context.sendBroadcast(intent, PERMISSION_RED);",
|
||||
" } else {",
|
||||
" Intent intent = new Intent(ACTION_NONE);",
|
||||
" context.sendBroadcast(intent);",
|
||||
" }",
|
||||
" }",
|
||||
"}")
|
||||
.doTest();
|
||||
}
|
||||
}
|
||||
|
||||
36
errorprone/tests/res/android/annotation/SdkConstant.java
Normal file
36
errorprone/tests/res/android/annotation/SdkConstant.java
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (C) 2008 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 java.lang.annotation.Target;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
/**
|
||||
* Indicates a constant field value should be exported to be used in the SDK tools.
|
||||
* @hide
|
||||
*/
|
||||
@Target({ ElementType.FIELD })
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface SdkConstant {
|
||||
public static enum SdkConstantType {
|
||||
ACTIVITY_INTENT_ACTION, BROADCAST_INTENT_ACTION, SERVICE_ACTION, INTENT_CATEGORY, FEATURE;
|
||||
}
|
||||
|
||||
SdkConstantType value();
|
||||
}
|
||||
@@ -18,9 +18,22 @@ package android.content;
|
||||
|
||||
public class Context {
|
||||
public int getUserId() {
|
||||
return 0;
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public void enforceCallingOrSelfPermission(String permission, String message) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public void sendBroadcast(Intent intent) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public void sendBroadcast(Intent intent, String receiverPermission) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public void sendBroadcastWithMultiplePermissions(Intent intent, String[] receiverPermissions) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,4 +17,11 @@
|
||||
package android.content;
|
||||
|
||||
public class Intent {
|
||||
public Intent(String action) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public Intent setAction(String action) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2494,7 +2494,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
|
||||
intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, prevState);
|
||||
intent.putExtra(BluetoothAdapter.EXTRA_STATE, newState);
|
||||
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
|
||||
mContext.sendBroadcastAsUser(intent, UserHandle.ALL, BLUETOOTH_CONNECT);
|
||||
mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
|
||||
}
|
||||
|
||||
@RequiresPermission(allOf = {
|
||||
@@ -2577,7 +2577,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
|
||||
intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, prevState);
|
||||
intent.putExtra(BluetoothAdapter.EXTRA_STATE, newState);
|
||||
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
|
||||
mContext.sendBroadcastAsUser(intent, UserHandle.ALL, BLUETOOTH_CONNECT);
|
||||
mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user