diff --git a/Android.bp b/Android.bp index 79930abb4887e611b41a7f0d08699376f7953de7..22fdaad050253266a43ff21a80220bdd27896c67 100644 --- a/Android.bp +++ b/Android.bp @@ -69,6 +69,7 @@ filegroup { // Java/AIDL sources under frameworks/base ":framework-annotations", ":framework-blobstore-sources", + ":framework-bluetooth-sources", // TODO(b/214988855) : Remove once framework-bluetooth jar is ready ":framework-connectivity-tiramisu-sources", ":framework-core-sources", ":framework-drm-sources", diff --git a/core/java/android/bluetooth/Attributable.java b/core/java/android/bluetooth/Attributable.java deleted file mode 100644 index d9acbe3eefb9b65d14a35530e821b2e11a3755a8..0000000000000000000000000000000000000000 --- a/core/java/android/bluetooth/Attributable.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * 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.bluetooth; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.content.AttributionSource; - -import java.util.List; - -/** - * Marker interface for a class which can have an {@link AttributionSource} - * assigned to it; these are typically {@link android.os.Parcelable} classes - * which need to be updated after crossing Binder transaction boundaries. - * - * @hide - */ -public interface Attributable { - void setAttributionSource(@NonNull AttributionSource attributionSource); - - static @Nullable T setAttributionSource( - @Nullable T attributable, - @NonNull AttributionSource attributionSource) { - if (attributable != null) { - attributable.setAttributionSource(attributionSource); - } - return attributable; - } - - static @Nullable List setAttributionSource( - @Nullable List attributableList, - @NonNull AttributionSource attributionSource) { - if (attributableList != null) { - final int size = attributableList.size(); - for (int i = 0; i < size; i++) { - setAttributionSource(attributableList.get(i), attributionSource); - } - } - return attributableList; - } -} diff --git a/core/java/android/bluetooth/BluetoothA2dp.java b/core/java/android/bluetooth/BluetoothA2dp.java deleted file mode 100644 index 8b9cec17a1963c150f15a8b7074588774eb9bd00..0000000000000000000000000000000000000000 --- a/core/java/android/bluetooth/BluetoothA2dp.java +++ /dev/null @@ -1,1149 +0,0 @@ -/* - * 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.bluetooth; - -import static android.bluetooth.BluetoothUtils.getSyncTimeout; - -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; -import android.annotation.SystemApi; -import android.bluetooth.annotations.RequiresBluetoothConnectPermission; -import android.bluetooth.annotations.RequiresLegacyBluetoothAdminPermission; -import android.bluetooth.annotations.RequiresLegacyBluetoothPermission; -import android.compat.annotation.UnsupportedAppUsage; -import android.content.AttributionSource; -import android.content.Context; -import android.os.Build; -import android.os.IBinder; -import android.os.ParcelUuid; -import android.os.RemoteException; -import android.util.Log; - -import com.android.modules.utils.SynchronousResultReceiver; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.TimeoutException; - - -/** - * This class provides the public APIs to control the Bluetooth A2DP - * profile. - * - *

BluetoothA2dp is a proxy object for controlling the Bluetooth A2DP - * Service via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get - * the BluetoothA2dp proxy object. - * - *

Android only supports one connected Bluetooth A2dp device at a time. - * Each method is protected with its appropriate permission. - */ -public final class BluetoothA2dp implements BluetoothProfile { - private static final String TAG = "BluetoothA2dp"; - private static final boolean DBG = true; - private static final boolean VDBG = false; - - /** - * Intent used to broadcast the change in connection state of the A2DP - * profile. - * - *

This intent will have 3 extras: - *

    - *
  • {@link #EXTRA_STATE} - The current state of the profile.
  • - *
  • {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile.
  • - *
  • {@link BluetoothDevice#EXTRA_DEVICE} - The remote device.
  • - *
- * - *

{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of - * {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING}, - * {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}. - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - public static final String ACTION_CONNECTION_STATE_CHANGED = - "android.bluetooth.a2dp.profile.action.CONNECTION_STATE_CHANGED"; - - /** - * Intent used to broadcast the change in the Playing state of the A2DP - * profile. - * - *

This intent will have 3 extras: - *

    - *
  • {@link #EXTRA_STATE} - The current state of the profile.
  • - *
  • {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile.
  • - *
  • {@link BluetoothDevice#EXTRA_DEVICE} - The remote device.
  • - *
- * - *

{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of - * {@link #STATE_PLAYING}, {@link #STATE_NOT_PLAYING}, - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - public static final String ACTION_PLAYING_STATE_CHANGED = - "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"; - - /** - * Intent used to broadcast the selection of a connected device as active. - * - *

This intent will have one extra: - *

    - *
  • {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. It can - * be null if no device is active.
  • - *
- * - * @hide - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - @UnsupportedAppUsage(trackingBug = 171933273) - public static final String ACTION_ACTIVE_DEVICE_CHANGED = - "android.bluetooth.a2dp.profile.action.ACTIVE_DEVICE_CHANGED"; - - /** - * Intent used to broadcast the change in the Audio Codec state of the - * A2DP Source profile. - * - *

This intent will have 2 extras: - *

    - *
  • {@link BluetoothCodecStatus#EXTRA_CODEC_STATUS} - The codec status.
  • - *
  • {@link BluetoothDevice#EXTRA_DEVICE} - The remote device if the device is currently - * connected, otherwise it is not included.
  • - *
- * - * @hide - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - @UnsupportedAppUsage(trackingBug = 181103983) - public static final String ACTION_CODEC_CONFIG_CHANGED = - "android.bluetooth.a2dp.profile.action.CODEC_CONFIG_CHANGED"; - - /** - * A2DP sink device is streaming music. This state can be one of - * {@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} of - * {@link #ACTION_PLAYING_STATE_CHANGED} intent. - */ - public static final int STATE_PLAYING = 10; - - /** - * A2DP sink device is NOT streaming music. This state can be one of - * {@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} of - * {@link #ACTION_PLAYING_STATE_CHANGED} intent. - */ - public static final int STATE_NOT_PLAYING = 11; - - /** @hide */ - @IntDef(prefix = "OPTIONAL_CODECS_", value = { - OPTIONAL_CODECS_SUPPORT_UNKNOWN, - OPTIONAL_CODECS_NOT_SUPPORTED, - OPTIONAL_CODECS_SUPPORTED - }) - @Retention(RetentionPolicy.SOURCE) - public @interface OptionalCodecsSupportStatus {} - - /** - * We don't have a stored preference for whether or not the given A2DP sink device supports - * optional codecs. - * - * @hide - */ - @SystemApi - public static final int OPTIONAL_CODECS_SUPPORT_UNKNOWN = -1; - - /** - * The given A2DP sink device does not support optional codecs. - * - * @hide - */ - @SystemApi - public static final int OPTIONAL_CODECS_NOT_SUPPORTED = 0; - - /** - * The given A2DP sink device does support optional codecs. - * - * @hide - */ - @SystemApi - public static final int OPTIONAL_CODECS_SUPPORTED = 1; - - /** @hide */ - @IntDef(prefix = "OPTIONAL_CODECS_PREF_", value = { - OPTIONAL_CODECS_PREF_UNKNOWN, - OPTIONAL_CODECS_PREF_DISABLED, - OPTIONAL_CODECS_PREF_ENABLED - }) - @Retention(RetentionPolicy.SOURCE) - public @interface OptionalCodecsPreferenceStatus {} - - /** - * We don't have a stored preference for whether optional codecs should be enabled or - * disabled for the given A2DP device. - * - * @hide - */ - @SystemApi - public static final int OPTIONAL_CODECS_PREF_UNKNOWN = -1; - - /** - * Optional codecs should be disabled for the given A2DP device. - * - * @hide - */ - @SystemApi - public static final int OPTIONAL_CODECS_PREF_DISABLED = 0; - - /** - * Optional codecs should be enabled for the given A2DP device. - * - * @hide - */ - @SystemApi - public static final int OPTIONAL_CODECS_PREF_ENABLED = 1; - - /** @hide */ - @IntDef(prefix = "DYNAMIC_BUFFER_SUPPORT_", value = { - DYNAMIC_BUFFER_SUPPORT_NONE, - DYNAMIC_BUFFER_SUPPORT_A2DP_OFFLOAD, - DYNAMIC_BUFFER_SUPPORT_A2DP_SOFTWARE_ENCODING - }) - @Retention(RetentionPolicy.SOURCE) - public @interface Type {} - - /** - * Indicates the supported type of Dynamic Audio Buffer is not supported. - * - * @hide - */ - @SystemApi - public static final int DYNAMIC_BUFFER_SUPPORT_NONE = 0; - - /** - * Indicates the supported type of Dynamic Audio Buffer is A2DP offload. - * - * @hide - */ - @SystemApi - public static final int DYNAMIC_BUFFER_SUPPORT_A2DP_OFFLOAD = 1; - - /** - * Indicates the supported type of Dynamic Audio Buffer is A2DP software encoding. - * - * @hide - */ - @SystemApi - public static final int DYNAMIC_BUFFER_SUPPORT_A2DP_SOFTWARE_ENCODING = 2; - - private final BluetoothAdapter mAdapter; - private final AttributionSource mAttributionSource; - private final BluetoothProfileConnector mProfileConnector = - new BluetoothProfileConnector(this, BluetoothProfile.A2DP, "BluetoothA2dp", - IBluetoothA2dp.class.getName()) { - @Override - public IBluetoothA2dp getServiceInterface(IBinder service) { - return IBluetoothA2dp.Stub.asInterface(service); - } - }; - - /** - * Create a BluetoothA2dp proxy object for interacting with the local - * Bluetooth A2DP service. - */ - /* package */ BluetoothA2dp(Context context, ServiceListener listener, - BluetoothAdapter adapter) { - mAdapter = adapter; - mAttributionSource = adapter.getAttributionSource(); - mProfileConnector.connect(context, listener); - } - - @UnsupportedAppUsage - /*package*/ void close() { - mProfileConnector.disconnect(); - } - - private IBluetoothA2dp getService() { - return mProfileConnector.getService(); - } - - @Override - public void finalize() { - // The empty finalize needs to be kept or the - // cts signature tests would fail. - } - - /** - * Initiate connection to a profile of the remote Bluetooth device. - * - *

This API returns false in scenarios like the profile on the - * device is already connected or Bluetooth is not turned on. - * When this API returns true, it is guaranteed that - * connection state intent for the profile will be broadcasted with - * the state. Users can get the connection state of the profile - * from this intent. - * - * - * @param device Remote Bluetooth Device - * @return false on immediate error, true otherwise - * @hide - */ - @RequiresLegacyBluetoothAdminPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - @UnsupportedAppUsage - public boolean connect(BluetoothDevice device) { - if (DBG) log("connect(" + device + ")"); - final IBluetoothA2dp service = getService(); - final boolean defaultValue = false; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device)) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.connectWithAttribution(device, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Initiate disconnection from a profile - * - *

This API will return false in scenarios like the profile on the - * Bluetooth device is not in connected state etc. When this API returns, - * true, it is guaranteed that the connection state change - * intent will be broadcasted with the state. Users can get the - * disconnection state of the profile from this intent. - * - *

If the disconnection is initiated by a remote device, the state - * will transition from {@link #STATE_CONNECTED} to - * {@link #STATE_DISCONNECTED}. If the disconnect is initiated by the - * host (local) device the state will transition from - * {@link #STATE_CONNECTED} to state {@link #STATE_DISCONNECTING} to - * state {@link #STATE_DISCONNECTED}. The transition to - * {@link #STATE_DISCONNECTING} can be used to distinguish between the - * two scenarios. - * - * - * @param device Remote Bluetooth Device - * @return false on immediate error, true otherwise - * @hide - */ - @RequiresLegacyBluetoothAdminPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - @UnsupportedAppUsage - public boolean disconnect(BluetoothDevice device) { - if (DBG) log("disconnect(" + device + ")"); - final IBluetoothA2dp service = getService(); - final boolean defaultValue = false; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device)) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.disconnectWithAttribution(device, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * {@inheritDoc} - */ - @Override - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public List getConnectedDevices() { - if (VDBG) log("getConnectedDevices()"); - final IBluetoothA2dp service = getService(); - final List defaultValue = new ArrayList(); - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled()) { - try { - final SynchronousResultReceiver> recv = - new SynchronousResultReceiver(); - service.getConnectedDevicesWithAttribution(mAttributionSource, recv); - return Attributable.setAttributionSource( - recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue), - mAttributionSource); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * {@inheritDoc} - */ - @Override - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public List getDevicesMatchingConnectionStates(int[] states) { - if (VDBG) log("getDevicesMatchingStates()"); - final IBluetoothA2dp service = getService(); - final List defaultValue = new ArrayList(); - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled()) { - try { - final SynchronousResultReceiver> recv = - new SynchronousResultReceiver(); - service.getDevicesMatchingConnectionStatesWithAttribution(states, - mAttributionSource, recv); - return Attributable.setAttributionSource( - recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue), - mAttributionSource); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * {@inheritDoc} - */ - @Override - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public @BtProfileState int getConnectionState(BluetoothDevice device) { - if (VDBG) log("getState(" + device + ")"); - final IBluetoothA2dp service = getService(); - final int defaultValue = BluetoothProfile.STATE_DISCONNECTED; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device)) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.getConnectionStateWithAttribution(device, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Select a connected device as active. - * - * The active device selection is per profile. An active device's - * purpose is profile-specific. For example, A2DP audio streaming - * is to the active A2DP Sink device. If a remote device is not - * connected, it cannot be selected as active. - * - *

This API returns false in scenarios like the profile on the - * device is not connected or Bluetooth is not turned on. - * When this API returns true, it is guaranteed that the - * {@link #ACTION_ACTIVE_DEVICE_CHANGED} intent will be broadcasted - * with the active device. - * - * @param device the remote Bluetooth device. Could be null to clear - * the active device and stop streaming audio to a Bluetooth device. - * @return false on immediate error, true otherwise - * @hide - */ - @RequiresLegacyBluetoothAdminPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - @UnsupportedAppUsage(trackingBug = 171933273) - public boolean setActiveDevice(@Nullable BluetoothDevice device) { - if (DBG) log("setActiveDevice(" + device + ")"); - final IBluetoothA2dp service = getService(); - final boolean defaultValue = false; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && ((device == null) || isValidDevice(device))) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.setActiveDevice(device, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Get the connected device that is active. - * - * @return the connected device that is active or null if no device - * is active - * @hide - */ - @UnsupportedAppUsage(trackingBug = 171933273) - @Nullable - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public BluetoothDevice getActiveDevice() { - if (VDBG) log("getActiveDevice()"); - final IBluetoothA2dp service = getService(); - final BluetoothDevice defaultValue = null; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled()) { - try { - final SynchronousResultReceiver recv = - new SynchronousResultReceiver(); - service.getActiveDevice(mAttributionSource, recv); - return Attributable.setAttributionSource( - recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue), - mAttributionSource); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Set priority of the profile - * - *

The device should already be paired. - * Priority can be one of {@link #PRIORITY_ON} or {@link #PRIORITY_OFF} - * - * @param device Paired bluetooth device - * @param priority - * @return true if priority is set, false on error - * @hide - */ - @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) - public boolean setPriority(BluetoothDevice device, int priority) { - if (DBG) log("setPriority(" + device + ", " + priority + ")"); - return setConnectionPolicy(device, BluetoothAdapter.priorityToConnectionPolicy(priority)); - } - - /** - * Set connection policy of the profile - * - *

The device should already be paired. - * Connection policy can be one of {@link #CONNECTION_POLICY_ALLOWED}, - * {@link #CONNECTION_POLICY_FORBIDDEN}, {@link #CONNECTION_POLICY_UNKNOWN} - * - * @param device Paired bluetooth device - * @param connectionPolicy is the connection policy to set to for this profile - * @return true if connectionPolicy is set, false on error - * @hide - */ - @SystemApi - @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) - public boolean setConnectionPolicy(@NonNull BluetoothDevice device, - @ConnectionPolicy int connectionPolicy) { - if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")"); - final IBluetoothA2dp service = getService(); - final boolean defaultValue = false; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device) - && (connectionPolicy == BluetoothProfile.CONNECTION_POLICY_FORBIDDEN - || connectionPolicy == BluetoothProfile.CONNECTION_POLICY_ALLOWED)) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.setConnectionPolicy(device, connectionPolicy, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Get the priority of the profile. - * - *

The priority can be any of: - * {@link #PRIORITY_OFF}, {@link #PRIORITY_ON}, {@link #PRIORITY_UNDEFINED} - * - * @param device Bluetooth device - * @return priority of the device - * @hide - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) - public int getPriority(BluetoothDevice device) { - if (VDBG) log("getPriority(" + device + ")"); - return BluetoothAdapter.connectionPolicyToPriority(getConnectionPolicy(device)); - } - - /** - * Get the connection policy of the profile. - * - *

The connection policy can be any of: - * {@link #CONNECTION_POLICY_ALLOWED}, {@link #CONNECTION_POLICY_FORBIDDEN}, - * {@link #CONNECTION_POLICY_UNKNOWN} - * - * @param device Bluetooth device - * @return connection policy of the device - * @hide - */ - @SystemApi - @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) - public @ConnectionPolicy int getConnectionPolicy(@NonNull BluetoothDevice device) { - if (VDBG) log("getConnectionPolicy(" + device + ")"); - final IBluetoothA2dp service = getService(); - final int defaultValue = BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device)) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.getConnectionPolicy(device, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Checks if Avrcp device supports the absolute volume feature. - * - * @return true if device supports absolute volume - * @hide - */ - @RequiresNoPermission - public boolean isAvrcpAbsoluteVolumeSupported() { - if (DBG) Log.d(TAG, "isAvrcpAbsoluteVolumeSupported"); - final IBluetoothA2dp service = getService(); - final boolean defaultValue = false; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled()) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.isAvrcpAbsoluteVolumeSupported(recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Tells remote device to set an absolute volume. Only if absolute volume is supported - * - * @param volume Absolute volume to be set on AVRCP side - * @hide - */ - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public void setAvrcpAbsoluteVolume(int volume) { - if (DBG) Log.d(TAG, "setAvrcpAbsoluteVolume"); - final IBluetoothA2dp service = getService(); - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled()) { - try { - service.setAvrcpAbsoluteVolume(volume, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - } - - /** - * Check if A2DP profile is streaming music. - * - * @param device BluetoothDevice device - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public boolean isA2dpPlaying(BluetoothDevice device) { - if (DBG) log("isA2dpPlaying(" + device + ")"); - final IBluetoothA2dp service = getService(); - final boolean defaultValue = false; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device)) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.isA2dpPlaying(device, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * This function checks if the remote device is an AVCRP - * target and thus whether we should send volume keys - * changes or not. - * - * @hide - */ - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public boolean shouldSendVolumeKeys(BluetoothDevice device) { - if (isEnabled() && isValidDevice(device)) { - ParcelUuid[] uuids = device.getUuids(); - if (uuids == null) return false; - - for (ParcelUuid uuid : uuids) { - if (uuid.equals(BluetoothUuid.AVRCP_TARGET)) { - return true; - } - } - } - return false; - } - - /** - * Gets the current codec status (configuration and capability). - * - * @param device the remote Bluetooth device. - * @return the current codec status - * @hide - */ - @UnsupportedAppUsage(trackingBug = 181103983) - @Nullable - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public BluetoothCodecStatus getCodecStatus(@NonNull BluetoothDevice device) { - if (DBG) Log.d(TAG, "getCodecStatus(" + device + ")"); - verifyDeviceNotNull(device, "getCodecStatus"); - final IBluetoothA2dp service = getService(); - final BluetoothCodecStatus defaultValue = null; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device)) { - try { - final SynchronousResultReceiver recv = - new SynchronousResultReceiver(); - service.getCodecStatus(device, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Sets the codec configuration preference. - * - * @param device the remote Bluetooth device. - * @param codecConfig the codec configuration preference - * @hide - */ - @UnsupportedAppUsage(trackingBug = 181103983) - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public void setCodecConfigPreference(@NonNull BluetoothDevice device, - @NonNull BluetoothCodecConfig codecConfig) { - if (DBG) Log.d(TAG, "setCodecConfigPreference(" + device + ")"); - verifyDeviceNotNull(device, "setCodecConfigPreference"); - if (codecConfig == null) { - Log.e(TAG, "setCodecConfigPreference: Codec config can't be null"); - throw new IllegalArgumentException("codecConfig cannot be null"); - } - final IBluetoothA2dp service = getService(); - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled()) { - try { - service.setCodecConfigPreference(device, codecConfig, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - } - - /** - * Enables the optional codecs. - * - * @param device the remote Bluetooth device. - * @hide - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public void enableOptionalCodecs(@NonNull BluetoothDevice device) { - if (DBG) Log.d(TAG, "enableOptionalCodecs(" + device + ")"); - verifyDeviceNotNull(device, "enableOptionalCodecs"); - enableDisableOptionalCodecs(device, true); - } - - /** - * Disables the optional codecs. - * - * @param device the remote Bluetooth device. - * @hide - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public void disableOptionalCodecs(@NonNull BluetoothDevice device) { - if (DBG) Log.d(TAG, "disableOptionalCodecs(" + device + ")"); - verifyDeviceNotNull(device, "disableOptionalCodecs"); - enableDisableOptionalCodecs(device, false); - } - - /** - * Enables or disables the optional codecs. - * - * @param device the remote Bluetooth device. - * @param enable if true, enable the optional codecs, other disable them - */ - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - private void enableDisableOptionalCodecs(BluetoothDevice device, boolean enable) { - final IBluetoothA2dp service = getService(); - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device)) { - try { - if (enable) { - service.enableOptionalCodecs(device, mAttributionSource); - } else { - service.disableOptionalCodecs(device, mAttributionSource); - } - } catch (RemoteException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - } - - /** - * Returns whether this device supports optional codecs. - * - * @param device The device to check - * @return one of OPTIONAL_CODECS_SUPPORT_UNKNOWN, OPTIONAL_CODECS_NOT_SUPPORTED, or - * OPTIONAL_CODECS_SUPPORTED. - * @hide - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - @RequiresLegacyBluetoothAdminPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - @OptionalCodecsSupportStatus - public int isOptionalCodecsSupported(@NonNull BluetoothDevice device) { - if (DBG) log("isOptionalCodecsSupported(" + device + ")"); - verifyDeviceNotNull(device, "isOptionalCodecsSupported"); - final IBluetoothA2dp service = getService(); - final int defaultValue = OPTIONAL_CODECS_SUPPORT_UNKNOWN; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device)) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.supportsOptionalCodecs(device, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Returns whether this device should have optional codecs enabled. - * - * @param device The device in question. - * @return one of OPTIONAL_CODECS_PREF_UNKNOWN, OPTIONAL_CODECS_PREF_ENABLED, or - * OPTIONAL_CODECS_PREF_DISABLED. - * @hide - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - @RequiresLegacyBluetoothAdminPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - @OptionalCodecsPreferenceStatus - public int isOptionalCodecsEnabled(@NonNull BluetoothDevice device) { - if (DBG) log("isOptionalCodecsEnabled(" + device + ")"); - verifyDeviceNotNull(device, "isOptionalCodecsEnabled"); - final IBluetoothA2dp service = getService(); - final int defaultValue = OPTIONAL_CODECS_PREF_UNKNOWN; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device)) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.getOptionalCodecsEnabled(device, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Sets a persistent preference for whether a given device should have optional codecs enabled. - * - * @param device The device to set this preference for. - * @param value Whether the optional codecs should be enabled for this device. This should be - * one of OPTIONAL_CODECS_PREF_UNKNOWN, OPTIONAL_CODECS_PREF_ENABLED, or - * OPTIONAL_CODECS_PREF_DISABLED. - * @hide - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - @RequiresLegacyBluetoothAdminPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public void setOptionalCodecsEnabled(@NonNull BluetoothDevice device, - @OptionalCodecsPreferenceStatus int value) { - if (DBG) log("setOptionalCodecsEnabled(" + device + ")"); - verifyDeviceNotNull(device, "setOptionalCodecsEnabled"); - if (value != BluetoothA2dp.OPTIONAL_CODECS_PREF_UNKNOWN - && value != BluetoothA2dp.OPTIONAL_CODECS_PREF_DISABLED - && value != BluetoothA2dp.OPTIONAL_CODECS_PREF_ENABLED) { - Log.e(TAG, "Invalid value passed to setOptionalCodecsEnabled: " + value); - return; - } - final IBluetoothA2dp service = getService(); - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device)) { - try { - service.setOptionalCodecsEnabled(device, value, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - } - - /** - * Get the supported type of the Dynamic Audio Buffer. - *

Possible return values are - * {@link #DYNAMIC_BUFFER_SUPPORT_NONE}, - * {@link #DYNAMIC_BUFFER_SUPPORT_A2DP_OFFLOAD}, - * {@link #DYNAMIC_BUFFER_SUPPORT_A2DP_SOFTWARE_ENCODING}. - * - * @return supported type of Dynamic Audio Buffer feature - * - * @hide - */ - @SystemApi - @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) - public @Type int getDynamicBufferSupport() { - if (VDBG) log("getDynamicBufferSupport()"); - final IBluetoothA2dp service = getService(); - final int defaultValue = DYNAMIC_BUFFER_SUPPORT_NONE; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled()) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.getDynamicBufferSupport(mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Return the record of {@link BufferConstraints} object that - * has the default/maximum/minimum audio buffer. This can be used to inform what the controller - * has support for the audio buffer. - * - * @return a record with {@link BufferConstraints} or null if report is unavailable - * or unsupported - * - * @hide - */ - @SystemApi - @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) - public @Nullable BufferConstraints getBufferConstraints() { - if (VDBG) log("getBufferConstraints()"); - final IBluetoothA2dp service = getService(); - final BufferConstraints defaultValue = null; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled()) { - try { - final SynchronousResultReceiver recv = - new SynchronousResultReceiver(); - service.getBufferConstraints(mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Set Dynamic Audio Buffer Size. - * - * @param codec audio codec - * @param value buffer millis - * @return true to indicate success, or false on immediate error - * - * @hide - */ - @SystemApi - @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) - public boolean setBufferLengthMillis(@BluetoothCodecConfig.SourceCodecType int codec, - int value) { - if (VDBG) log("setBufferLengthMillis(" + codec + ", " + value + ")"); - if (value < 0) { - Log.e(TAG, "Trying to set audio buffer length to a negative value: " + value); - return false; - } - final IBluetoothA2dp service = getService(); - final boolean defaultValue = false; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled()) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.setBufferLengthMillis(codec, value, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Helper for converting a state to a string. - * - * For debug use only - strings are not internationalized. - * - * @hide - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) - public static String stateToString(int state) { - switch (state) { - case STATE_DISCONNECTED: - return "disconnected"; - case STATE_CONNECTING: - return "connecting"; - case STATE_CONNECTED: - return "connected"; - case STATE_DISCONNECTING: - return "disconnecting"; - case STATE_PLAYING: - return "playing"; - case STATE_NOT_PLAYING: - return "not playing"; - default: - return ""; - } - } - - private boolean isEnabled() { - if (mAdapter.getState() == BluetoothAdapter.STATE_ON) return true; - return false; - } - - private void verifyDeviceNotNull(BluetoothDevice device, String methodName) { - if (device == null) { - Log.e(TAG, methodName + ": device param is null"); - throw new IllegalArgumentException("Device cannot be null"); - } - } - - private boolean isValidDevice(BluetoothDevice device) { - if (device == null) return false; - - if (BluetoothAdapter.checkBluetoothAddress(device.getAddress())) return true; - return false; - } - - private static void log(String msg) { - Log.d(TAG, msg); - } -} diff --git a/core/java/android/bluetooth/BluetoothA2dpSink.java b/core/java/android/bluetooth/BluetoothA2dpSink.java deleted file mode 100755 index 59416818ceb3b295c5a934fb74e9b8dc8969af81..0000000000000000000000000000000000000000 --- a/core/java/android/bluetooth/BluetoothA2dpSink.java +++ /dev/null @@ -1,516 +0,0 @@ -/* - * Copyright (C) 2014 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.bluetooth; - -import static android.bluetooth.BluetoothUtils.getSyncTimeout; - -import android.Manifest; -import android.annotation.NonNull; -import android.annotation.RequiresPermission; -import android.annotation.SdkConstant; -import android.annotation.SdkConstant.SdkConstantType; -import android.annotation.SuppressLint; -import android.annotation.SystemApi; -import android.bluetooth.annotations.RequiresBluetoothConnectPermission; -import android.bluetooth.annotations.RequiresLegacyBluetoothAdminPermission; -import android.bluetooth.annotations.RequiresLegacyBluetoothPermission; -import android.compat.annotation.UnsupportedAppUsage; -import android.content.AttributionSource; -import android.content.Context; -import android.os.Build; -import android.os.IBinder; -import android.os.RemoteException; -import android.util.Log; - -import com.android.modules.utils.SynchronousResultReceiver; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.TimeoutException; - -/** - * This class provides the public APIs to control the Bluetooth A2DP Sink - * profile. - * - *

BluetoothA2dpSink is a proxy object for controlling the Bluetooth A2DP Sink - * Service via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get - * the BluetoothA2dpSink proxy object. - * - * @hide - */ -@SystemApi -public final class BluetoothA2dpSink implements BluetoothProfile { - private static final String TAG = "BluetoothA2dpSink"; - private static final boolean DBG = true; - private static final boolean VDBG = false; - - /** - * Intent used to broadcast the change in connection state of the A2DP Sink - * profile. - * - *

This intent will have 3 extras: - *

    - *
  • {@link #EXTRA_STATE} - The current state of the profile.
  • - *
  • {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile.
  • - *
  • {@link BluetoothDevice#EXTRA_DEVICE} - The remote device.
  • - *
- * - *

{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of - * {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING}, - * {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}. - * - * @hide - */ - @SystemApi - @SuppressLint("ActionValue") - @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"; - - private final BluetoothAdapter mAdapter; - private final AttributionSource mAttributionSource; - private final BluetoothProfileConnector mProfileConnector = - new BluetoothProfileConnector(this, BluetoothProfile.A2DP_SINK, - "BluetoothA2dpSink", IBluetoothA2dpSink.class.getName()) { - @Override - public IBluetoothA2dpSink getServiceInterface(IBinder service) { - return IBluetoothA2dpSink.Stub.asInterface(service); - } - }; - - /** - * Create a BluetoothA2dp proxy object for interacting with the local - * Bluetooth A2DP service. - */ - /* package */ BluetoothA2dpSink(Context context, ServiceListener listener, - BluetoothAdapter adapter) { - mAdapter = adapter; - mAttributionSource = adapter.getAttributionSource(); - mProfileConnector.connect(context, listener); - } - - /*package*/ void close() { - mProfileConnector.disconnect(); - } - - private IBluetoothA2dpSink getService() { - return mProfileConnector.getService(); - } - - @Override - public void finalize() { - close(); - } - - /** - * Initiate connection to a profile of the remote bluetooth device. - * - *

Currently, the system supports only 1 connection to the - * A2DP profile. The API will automatically disconnect connected - * devices before connecting. - * - *

This API returns false in scenarios like the profile on the - * device is already connected or Bluetooth is not turned on. - * When this API returns true, it is guaranteed that - * connection state intent for the profile will be broadcasted with - * the state. Users can get the connection state of the profile - * from this intent. - * - * @param device Remote Bluetooth Device - * @return false on immediate error, true otherwise - * @hide - */ - @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) - public boolean connect(BluetoothDevice device) { - if (DBG) log("connect(" + device + ")"); - final IBluetoothA2dpSink service = getService(); - final boolean defaultValue = false; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device)) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.connect(device, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Initiate disconnection from a profile - * - *

This API will return false in scenarios like the profile on the - * Bluetooth device is not in connected state etc. When this API returns, - * true, it is guaranteed that the connection state change - * intent will be broadcasted with the state. Users can get the - * disconnection state of the profile from this intent. - * - *

If the disconnection is initiated by a remote device, the state - * will transition from {@link #STATE_CONNECTED} to - * {@link #STATE_DISCONNECTED}. If the disconnect is initiated by the - * host (local) device the state will transition from - * {@link #STATE_CONNECTED} to state {@link #STATE_DISCONNECTING} to - * state {@link #STATE_DISCONNECTED}. The transition to - * {@link #STATE_DISCONNECTING} can be used to distinguish between the - * two scenarios. - * - * @param device Remote Bluetooth Device - * @return false on immediate error, true otherwise - * @hide - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - @RequiresLegacyBluetoothAdminPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public boolean disconnect(BluetoothDevice device) { - if (DBG) log("disconnect(" + device + ")"); - final IBluetoothA2dpSink service = getService(); - final boolean defaultValue = false; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device)) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.disconnect(device, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * {@inheritDoc} - * - * @hide - */ - @Override - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public List getConnectedDevices() { - if (VDBG) log("getConnectedDevices()"); - final IBluetoothA2dpSink service = getService(); - final List defaultValue = new ArrayList(); - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled()) { - try { - final SynchronousResultReceiver> recv = - new SynchronousResultReceiver(); - service.getConnectedDevices(mAttributionSource, recv); - return Attributable.setAttributionSource( - recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue), - mAttributionSource); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * {@inheritDoc} - * - * @hide - */ - @Override - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public List getDevicesMatchingConnectionStates(int[] states) { - if (VDBG) log("getDevicesMatchingStates()"); - final IBluetoothA2dpSink service = getService(); - final List defaultValue = new ArrayList(); - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled()) { - try { - final SynchronousResultReceiver> recv = - new SynchronousResultReceiver(); - service.getDevicesMatchingConnectionStates(states, mAttributionSource, recv); - return Attributable.setAttributionSource( - recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue), - mAttributionSource); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * {@inheritDoc} - * - * @hide - */ - @Override - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public int getConnectionState(BluetoothDevice device) { - if (VDBG) log("getConnectionState(" + device + ")"); - final IBluetoothA2dpSink service = getService(); - final int defaultValue = BluetoothProfile.STATE_DISCONNECTED; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device)) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.getConnectionState(device, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Get the current audio configuration for the A2DP source device, - * or null if the device has no audio configuration - * - * @param device Remote bluetooth device. - * @return audio configuration for the device, or null - * - * {@see BluetoothAudioConfig} - * - * @hide - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public BluetoothAudioConfig getAudioConfig(BluetoothDevice device) { - if (VDBG) log("getAudioConfig(" + device + ")"); - final IBluetoothA2dpSink service = getService(); - final BluetoothAudioConfig defaultValue = null; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device)) { - try { - final SynchronousResultReceiver recv = - new SynchronousResultReceiver(); - service.getAudioConfig(device, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Set priority of the profile - * - *

The device should already be paired. - * Priority can be one of {@link #PRIORITY_ON} or {@link #PRIORITY_OFF} - * - * @param device Paired bluetooth device - * @param priority - * @return true if priority is set, false on error - * @hide - */ - @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) - public boolean setPriority(BluetoothDevice device, int priority) { - if (DBG) log("setPriority(" + device + ", " + priority + ")"); - return setConnectionPolicy(device, BluetoothAdapter.priorityToConnectionPolicy(priority)); - } - - /** - * Set connection policy of the profile - * - *

The device should already be paired. - * Connection policy can be one of {@link #CONNECTION_POLICY_ALLOWED}, - * {@link #CONNECTION_POLICY_FORBIDDEN}, {@link #CONNECTION_POLICY_UNKNOWN} - * - * @param device Paired bluetooth device - * @param connectionPolicy is the connection policy to set to for this profile - * @return true if connectionPolicy is set, false on error - * @hide - */ - @SystemApi - @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED - }) - public boolean setConnectionPolicy(@NonNull BluetoothDevice device, - @ConnectionPolicy int connectionPolicy) { - if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")"); - final IBluetoothA2dpSink service = getService(); - final boolean defaultValue = false; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device) - && (connectionPolicy == BluetoothProfile.CONNECTION_POLICY_FORBIDDEN - || connectionPolicy == BluetoothProfile.CONNECTION_POLICY_ALLOWED)) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.setConnectionPolicy(device, connectionPolicy, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Get the priority of the profile. - * - *

The priority can be any of: - * {@link #PRIORITY_OFF}, {@link #PRIORITY_ON}, {@link #PRIORITY_UNDEFINED} - * - * @param device Bluetooth device - * @return priority of the device - * @hide - */ - @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) - public int getPriority(BluetoothDevice device) { - if (VDBG) log("getPriority(" + device + ")"); - return BluetoothAdapter.connectionPolicyToPriority(getConnectionPolicy(device)); - } - - /** - * Get the connection policy of the profile. - * - *

The connection policy can be any of: - * {@link #CONNECTION_POLICY_ALLOWED}, {@link #CONNECTION_POLICY_FORBIDDEN}, - * {@link #CONNECTION_POLICY_UNKNOWN} - * - * @param device Bluetooth device - * @return connection policy of the device - * @hide - */ - @SystemApi - @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) - public @ConnectionPolicy int getConnectionPolicy(@NonNull BluetoothDevice device) { - if (VDBG) log("getConnectionPolicy(" + device + ")"); - final IBluetoothA2dpSink service = getService(); - final int defaultValue = BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device)) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.getConnectionPolicy(device, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Check if audio is playing on the bluetooth device (A2DP profile is streaming music). - * - * @param device BluetoothDevice device - * @return true if audio is playing (A2dp is streaming music), false otherwise - * - * @hide - */ - @SystemApi - @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) - public boolean isAudioPlaying(@NonNull BluetoothDevice device) { - if (VDBG) log("isAudioPlaying(" + device + ")"); - final IBluetoothA2dpSink service = getService(); - final boolean defaultValue = false; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device)) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.isA2dpPlaying(device, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Helper for converting a state to a string. - * - * For debug use only - strings are not internationalized. - * - * @hide - */ - public static String stateToString(int state) { - switch (state) { - case STATE_DISCONNECTED: - return "disconnected"; - case STATE_CONNECTING: - return "connecting"; - case STATE_CONNECTED: - return "connected"; - case STATE_DISCONNECTING: - return "disconnecting"; - case BluetoothA2dp.STATE_PLAYING: - return "playing"; - case BluetoothA2dp.STATE_NOT_PLAYING: - return "not playing"; - default: - return ""; - } - } - - private boolean isEnabled() { - return mAdapter.getState() == BluetoothAdapter.STATE_ON; - } - - private static boolean isValidDevice(BluetoothDevice device) { - return device != null && BluetoothAdapter.checkBluetoothAddress(device.getAddress()); - } - - private static void log(String msg) { - Log.d(TAG, msg); - } -} diff --git a/core/java/android/bluetooth/BluetoothActivityEnergyInfo.java b/core/java/android/bluetooth/BluetoothActivityEnergyInfo.java deleted file mode 100644 index c17a7b4b3dfda94f0b0d5966cbb0eca74ea099e7..0000000000000000000000000000000000000000 --- a/core/java/android/bluetooth/BluetoothActivityEnergyInfo.java +++ /dev/null @@ -1,199 +0,0 @@ -/* - * Copyright (C) 2014 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.bluetooth; - -import android.annotation.ElapsedRealtimeLong; -import android.annotation.IntDef; -import android.annotation.NonNull; -import android.annotation.SystemApi; -import android.os.Parcel; -import android.os.Parcelable; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.util.Collections; -import java.util.List; - -/** - * Record of energy and activity information from controller and - * underlying bt stack state.Timestamp the record with system - * time. - * - * @hide - */ -@SystemApi(client = SystemApi.Client.PRIVILEGED_APPS) -public final class BluetoothActivityEnergyInfo implements Parcelable { - private final long mTimestamp; - private int mBluetoothStackState; - private long mControllerTxTimeMs; - private long mControllerRxTimeMs; - private long mControllerIdleTimeMs; - private long mControllerEnergyUsed; - private List mUidTraffic; - - /** @hide */ - @IntDef(prefix = { "BT_STACK_STATE_" }, value = { - BT_STACK_STATE_INVALID, - BT_STACK_STATE_STATE_ACTIVE, - BT_STACK_STATE_STATE_SCANNING, - BT_STACK_STATE_STATE_IDLE - }) - @Retention(RetentionPolicy.SOURCE) - public @interface BluetoothStackState {} - - public static final int BT_STACK_STATE_INVALID = 0; - public static final int BT_STACK_STATE_STATE_ACTIVE = 1; - public static final int BT_STACK_STATE_STATE_SCANNING = 2; - public static final int BT_STACK_STATE_STATE_IDLE = 3; - - /** @hide */ - public BluetoothActivityEnergyInfo(long timestamp, int stackState, - long txTime, long rxTime, long idleTime, long energyUsed) { - mTimestamp = timestamp; - mBluetoothStackState = stackState; - mControllerTxTimeMs = txTime; - mControllerRxTimeMs = rxTime; - mControllerIdleTimeMs = idleTime; - mControllerEnergyUsed = energyUsed; - } - - /** @hide */ - private BluetoothActivityEnergyInfo(Parcel in) { - mTimestamp = in.readLong(); - mBluetoothStackState = in.readInt(); - mControllerTxTimeMs = in.readLong(); - mControllerRxTimeMs = in.readLong(); - mControllerIdleTimeMs = in.readLong(); - mControllerEnergyUsed = in.readLong(); - mUidTraffic = in.createTypedArrayList(UidTraffic.CREATOR); - } - - /** @hide */ - @Override - public String toString() { - return "BluetoothActivityEnergyInfo{" - + " mTimestamp=" + mTimestamp - + " mBluetoothStackState=" + mBluetoothStackState - + " mControllerTxTimeMs=" + mControllerTxTimeMs - + " mControllerRxTimeMs=" + mControllerRxTimeMs - + " mControllerIdleTimeMs=" + mControllerIdleTimeMs - + " mControllerEnergyUsed=" + mControllerEnergyUsed - + " mUidTraffic=" + mUidTraffic - + " }"; - } - - public static final @NonNull Parcelable.Creator CREATOR = - new Parcelable.Creator() { - public BluetoothActivityEnergyInfo createFromParcel(Parcel in) { - return new BluetoothActivityEnergyInfo(in); - } - - public BluetoothActivityEnergyInfo[] newArray(int size) { - return new BluetoothActivityEnergyInfo[size]; - } - }; - - /** @hide */ - @Override - public void writeToParcel(Parcel out, int flags) { - out.writeLong(mTimestamp); - out.writeInt(mBluetoothStackState); - out.writeLong(mControllerTxTimeMs); - out.writeLong(mControllerRxTimeMs); - out.writeLong(mControllerIdleTimeMs); - out.writeLong(mControllerEnergyUsed); - out.writeTypedList(mUidTraffic); - } - - /** @hide */ - @Override - public int describeContents() { - return 0; - } - - /** - * Get the Bluetooth stack state associated with the energy info. - * - * @return one of {@link #BluetoothStackState} states - */ - @BluetoothStackState - public int getBluetoothStackState() { - return mBluetoothStackState; - } - - /** - * @return tx time in ms - */ - public long getControllerTxTimeMillis() { - return mControllerTxTimeMs; - } - - /** - * @return rx time in ms - */ - public long getControllerRxTimeMillis() { - return mControllerRxTimeMs; - } - - /** - * @return idle time in ms - */ - public long getControllerIdleTimeMillis() { - return mControllerIdleTimeMs; - } - - /** - * Get the product of current (mA), voltage (V), and time (ms). - * - * @return energy used - */ - public long getControllerEnergyUsed() { - return mControllerEnergyUsed; - } - - /** - * @return timestamp (real time elapsed in milliseconds since boot) of record creation - */ - public @ElapsedRealtimeLong long getTimestampMillis() { - return mTimestamp; - } - - /** - * Get the {@link List} of each application {@link android.bluetooth.UidTraffic}. - * - * @return current {@link List} of {@link android.bluetooth.UidTraffic} - */ - public @NonNull List getUidTraffic() { - if (mUidTraffic == null) { - return Collections.emptyList(); - } - return mUidTraffic; - } - - /** @hide */ - public void setUidTraffic(List traffic) { - mUidTraffic = traffic; - } - - /** - * @return true if the record Tx time, Rx time, and Idle time are more than 0. - */ - public boolean isValid() { - return ((mControllerTxTimeMs >= 0) && (mControllerRxTimeMs >= 0) - && (mControllerIdleTimeMs >= 0)); - } -} diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java deleted file mode 100644 index f94ee8579eab6a25f5e50cc2503c5f814cc5bd39..0000000000000000000000000000000000000000 --- a/core/java/android/bluetooth/BluetoothAdapter.java +++ /dev/null @@ -1,4434 +0,0 @@ -/* - * Copyright 2009-2016 The Android Open Source Project - * Copyright 2015 Samsung LSI - * - * 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.bluetooth; - -import static java.util.Objects.requireNonNull; - -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; -import android.annotation.SuppressLint; -import android.annotation.SystemApi; //import android.app.PropertyInvalidatedCache; -import android.bluetooth.BluetoothDevice.Transport; -import android.bluetooth.BluetoothProfile.ConnectionPolicy; -import android.bluetooth.annotations.RequiresBluetoothAdvertisePermission; -import android.bluetooth.annotations.RequiresBluetoothConnectPermission; -import android.bluetooth.annotations.RequiresBluetoothLocationPermission; -import android.bluetooth.annotations.RequiresBluetoothScanPermission; -import android.bluetooth.annotations.RequiresLegacyBluetoothAdminPermission; -import android.bluetooth.annotations.RequiresLegacyBluetoothPermission; -import android.bluetooth.le.BluetoothLeAdvertiser; -import android.bluetooth.le.BluetoothLeScanner; -import android.bluetooth.le.PeriodicAdvertisingManager; -import android.bluetooth.le.ScanCallback; -import android.bluetooth.le.ScanFilter; -import android.bluetooth.le.ScanRecord; -import android.bluetooth.le.ScanResult; -import android.bluetooth.le.ScanSettings; -import android.compat.annotation.UnsupportedAppUsage; -import android.content.AttributionSource; -import android.content.Context; -import android.os.Binder; -import android.os.Build; -import android.os.IBinder; -import android.os.ParcelUuid; -import android.os.RemoteException; -import android.os.ResultReceiver; -import android.os.ServiceManager; -import android.sysprop.BluetoothProperties; -import android.util.Log; -import android.util.Pair; - -import com.android.internal.annotations.GuardedBy; - -import java.io.IOException; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Objects; -import java.util.Set; -import java.util.UUID; -import java.util.WeakHashMap; -import java.util.concurrent.Executor; -import java.util.concurrent.locks.ReentrantReadWriteLock; - -/** - * Represents the local device Bluetooth adapter. The {@link BluetoothAdapter} - * lets you perform fundamental Bluetooth tasks, such as initiate - * device discovery, query a list of bonded (paired) devices, - * instantiate a {@link BluetoothDevice} using a known MAC address, and create - * a {@link BluetoothServerSocket} to listen for connection requests from other - * devices, and start a scan for Bluetooth LE devices. - * - *

To get a {@link BluetoothAdapter} representing the local Bluetooth - * adapter, call the {@link BluetoothManager#getAdapter} function on {@link BluetoothManager}. - * On JELLY_BEAN_MR1 and below you will need to use the static {@link #getDefaultAdapter} - * method instead. - *

- * Fundamentally, this is your starting point for all - * Bluetooth actions. Once you have the local adapter, you can get a set of - * {@link BluetoothDevice} objects representing all paired devices with - * {@link #getBondedDevices()}; start device discovery with - * {@link #startDiscovery()}; or create a {@link BluetoothServerSocket} to - * listen for incoming RFComm connection requests with {@link - * #listenUsingRfcommWithServiceRecord(String, UUID)}; listen for incoming L2CAP Connection-oriented - * Channels (CoC) connection requests with {@link #listenUsingL2capChannel()}; or start a scan for - * Bluetooth LE devices with {@link #startLeScan(LeScanCallback callback)}. - *

- *

This class is thread safe.

- *
- *

Developer Guides

- *

- * For more information about using Bluetooth, read the Bluetooth developer - * guide. - *

- *
- * - * {@see BluetoothDevice} - * {@see BluetoothServerSocket} - */ -public final class BluetoothAdapter { - private static final String TAG = "BluetoothAdapter"; - private static final String DESCRIPTOR = "android.bluetooth.BluetoothAdapter"; - private static final boolean DBG = true; - private static final boolean VDBG = false; - - /** - * Default MAC address reported to a client that does not have the - * android.permission.LOCAL_MAC_ADDRESS permission. - * - * @hide - */ - public static final String DEFAULT_MAC_ADDRESS = "02:00:00:00:00:00"; - - /** - * Sentinel error value for this class. Guaranteed to not equal any other - * integer constant in this class. Provided as a convenience for functions - * that require a sentinel error value, for example: - *

Intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, - * BluetoothAdapter.ERROR) - */ - public static final int ERROR = Integer.MIN_VALUE; - - /** - * Broadcast Action: The state of the local Bluetooth adapter has been - * changed. - *

For example, Bluetooth has been turned on or off. - *

Always contains the extra fields {@link #EXTRA_STATE} and {@link - * #EXTRA_PREVIOUS_STATE} containing the new and old states - * respectively. - */ - @RequiresLegacyBluetoothPermission - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String - ACTION_STATE_CHANGED = "android.bluetooth.adapter.action.STATE_CHANGED"; - - /** - * Used as an int extra field in {@link #ACTION_STATE_CHANGED} - * intents to request the current power state. Possible values are: - * {@link #STATE_OFF}, - * {@link #STATE_TURNING_ON}, - * {@link #STATE_ON}, - * {@link #STATE_TURNING_OFF}, - */ - public static final String EXTRA_STATE = "android.bluetooth.adapter.extra.STATE"; - /** - * Used as an int extra field in {@link #ACTION_STATE_CHANGED} - * intents to request the previous power state. Possible values are: - * {@link #STATE_OFF}, - * {@link #STATE_TURNING_ON}, - * {@link #STATE_ON}, - * {@link #STATE_TURNING_OFF} - */ - public static final String EXTRA_PREVIOUS_STATE = - "android.bluetooth.adapter.extra.PREVIOUS_STATE"; - - /** @hide */ - @IntDef(prefix = { "STATE_" }, value = { - STATE_OFF, - STATE_TURNING_ON, - STATE_ON, - STATE_TURNING_OFF, - STATE_BLE_TURNING_ON, - STATE_BLE_ON, - STATE_BLE_TURNING_OFF - }) - @Retention(RetentionPolicy.SOURCE) - public @interface AdapterState {} - - /** - * Indicates the local Bluetooth adapter is off. - */ - public static final int STATE_OFF = 10; - /** - * Indicates the local Bluetooth adapter is turning on. However local - * clients should wait for {@link #STATE_ON} before attempting to - * use the adapter. - */ - public static final int STATE_TURNING_ON = 11; - /** - * Indicates the local Bluetooth adapter is on, and ready for use. - */ - public static final int STATE_ON = 12; - /** - * Indicates the local Bluetooth adapter is turning off. Local clients - * should immediately attempt graceful disconnection of any remote links. - */ - public static final int STATE_TURNING_OFF = 13; - - /** - * Indicates the local Bluetooth adapter is turning Bluetooth LE mode on. - * - * @hide - */ - public static final int STATE_BLE_TURNING_ON = 14; - - /** - * Indicates the local Bluetooth adapter is in LE only mode. - * - * @hide - */ - public static final int STATE_BLE_ON = 15; - - /** - * Indicates the local Bluetooth adapter is turning off LE only mode. - * - * @hide - */ - public static final int STATE_BLE_TURNING_OFF = 16; - - /** - * UUID of the GATT Read Characteristics for LE_PSM value. - * - * @hide - */ - public static final UUID LE_PSM_CHARACTERISTIC_UUID = - UUID.fromString("2d410339-82b6-42aa-b34e-e2e01df8cc1a"); - - /** - * Human-readable string helper for AdapterState - * - * @hide - */ - public static String nameForState(@AdapterState int state) { - switch (state) { - case STATE_OFF: - return "OFF"; - case STATE_TURNING_ON: - return "TURNING_ON"; - case STATE_ON: - return "ON"; - case STATE_TURNING_OFF: - return "TURNING_OFF"; - case STATE_BLE_TURNING_ON: - return "BLE_TURNING_ON"; - case STATE_BLE_ON: - return "BLE_ON"; - case STATE_BLE_TURNING_OFF: - return "BLE_TURNING_OFF"; - default: - return "?!?!? (" + state + ")"; - } - } - - /** - * Activity Action: Show a system activity that requests discoverable mode. - * This activity will also request the user to turn on Bluetooth if it - * is not currently enabled. - *

Discoverable mode is equivalent to {@link - * #SCAN_MODE_CONNECTABLE_DISCOVERABLE}. It allows remote devices to see - * this Bluetooth adapter when they perform a discovery. - *

For privacy, Android is not discoverable by default. - *

The sender of this Intent can optionally use extra field {@link - * #EXTRA_DISCOVERABLE_DURATION} to request the duration of - * discoverability. Currently the default duration is 120 seconds, and - * maximum duration is capped at 300 seconds for each request. - *

Notification of the result of this activity is posted using the - * {@link android.app.Activity#onActivityResult} callback. The - * resultCode - * will be the duration (in seconds) of discoverability or - * {@link android.app.Activity#RESULT_CANCELED} if the user rejected - * discoverability or an error has occurred. - *

Applications can also listen for {@link #ACTION_SCAN_MODE_CHANGED} - * for global notification whenever the scan mode changes. For example, an - * application can be notified when the device has ended discoverability. - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothAdvertisePermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE) - @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) public static final String - ACTION_REQUEST_DISCOVERABLE = "android.bluetooth.adapter.action.REQUEST_DISCOVERABLE"; - - /** - * Used as an optional int extra field in {@link - * #ACTION_REQUEST_DISCOVERABLE} intents to request a specific duration - * for discoverability in seconds. The current default is 120 seconds, and - * requests over 300 seconds will be capped. These values could change. - */ - public static final String EXTRA_DISCOVERABLE_DURATION = - "android.bluetooth.adapter.extra.DISCOVERABLE_DURATION"; - - /** - * Activity Action: Show a system activity that allows the user to turn on - * Bluetooth. - *

This system activity will return once Bluetooth has completed turning - * on, or the user has decided not to turn Bluetooth on. - *

Notification of the result of this activity is posted using the - * {@link android.app.Activity#onActivityResult} callback. The - * resultCode - * will be {@link android.app.Activity#RESULT_OK} if Bluetooth has been - * turned on or {@link android.app.Activity#RESULT_CANCELED} if the user - * has rejected the request or an error has occurred. - *

Applications can also listen for {@link #ACTION_STATE_CHANGED} - * for global notification whenever Bluetooth is turned on or off. - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) public static final String - ACTION_REQUEST_ENABLE = "android.bluetooth.adapter.action.REQUEST_ENABLE"; - - /** - * Activity Action: Show a system activity that allows the user to turn off - * Bluetooth. This is used only if permission review is enabled which is for - * apps targeting API less than 23 require a permission review before any of - * the app's components can run. - *

This system activity will return once Bluetooth has completed turning - * off, or the user has decided not to turn Bluetooth off. - *

Notification of the result of this activity is posted using the - * {@link android.app.Activity#onActivityResult} callback. The - * resultCode - * will be {@link android.app.Activity#RESULT_OK} if Bluetooth has been - * turned off or {@link android.app.Activity#RESULT_CANCELED} if the user - * has rejected the request or an error has occurred. - *

Applications can also listen for {@link #ACTION_STATE_CHANGED} - * for global notification whenever Bluetooth is turned on or off. - * - * @hide - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) public static final String - ACTION_REQUEST_DISABLE = "android.bluetooth.adapter.action.REQUEST_DISABLE"; - - /** - * Activity Action: Show a system activity that allows user to enable BLE scans even when - * Bluetooth is turned off.

- * - * Notification of result of this activity is posted using - * {@link android.app.Activity#onActivityResult}. The resultCode will be - * {@link android.app.Activity#RESULT_OK} if BLE scan always available setting is turned on or - * {@link android.app.Activity#RESULT_CANCELED} if the user has rejected the request or an - * error occurred. - * - * @hide - */ - @SystemApi - @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) - public static final String ACTION_REQUEST_BLE_SCAN_ALWAYS_AVAILABLE = - "android.bluetooth.adapter.action.REQUEST_BLE_SCAN_ALWAYS_AVAILABLE"; - - /** - * Broadcast Action: Indicates the Bluetooth scan mode of the local Adapter - * has changed. - *

Always contains the extra fields {@link #EXTRA_SCAN_MODE} and {@link - * #EXTRA_PREVIOUS_SCAN_MODE} containing the new and old scan modes - * respectively. - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothScanPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String - ACTION_SCAN_MODE_CHANGED = "android.bluetooth.adapter.action.SCAN_MODE_CHANGED"; - - /** - * Used as an int extra field in {@link #ACTION_SCAN_MODE_CHANGED} - * intents to request the current scan mode. Possible values are: - * {@link #SCAN_MODE_NONE}, - * {@link #SCAN_MODE_CONNECTABLE}, - * {@link #SCAN_MODE_CONNECTABLE_DISCOVERABLE}, - */ - public static final String EXTRA_SCAN_MODE = "android.bluetooth.adapter.extra.SCAN_MODE"; - /** - * Used as an int extra field in {@link #ACTION_SCAN_MODE_CHANGED} - * intents to request the previous scan mode. Possible values are: - * {@link #SCAN_MODE_NONE}, - * {@link #SCAN_MODE_CONNECTABLE}, - * {@link #SCAN_MODE_CONNECTABLE_DISCOVERABLE}, - */ - public static final String EXTRA_PREVIOUS_SCAN_MODE = - "android.bluetooth.adapter.extra.PREVIOUS_SCAN_MODE"; - - /** @hide */ - @IntDef(prefix = { "SCAN_" }, value = { - SCAN_MODE_NONE, - SCAN_MODE_CONNECTABLE, - SCAN_MODE_CONNECTABLE_DISCOVERABLE - }) - @Retention(RetentionPolicy.SOURCE) - public @interface ScanMode {} - - /** - * Indicates that both inquiry scan and page scan are disabled on the local - * Bluetooth adapter. Therefore this device is neither discoverable - * nor connectable from remote Bluetooth devices. - */ - public static final int SCAN_MODE_NONE = 20; - /** - * Indicates that inquiry scan is disabled, but page scan is enabled on the - * local Bluetooth adapter. Therefore this device is not discoverable from - * remote Bluetooth devices, but is connectable from remote devices that - * have previously discovered this device. - */ - public static final int SCAN_MODE_CONNECTABLE = 21; - /** - * Indicates that both inquiry scan and page scan are enabled on the local - * Bluetooth adapter. Therefore this device is both discoverable and - * connectable from remote Bluetooth devices. - */ - public static final int SCAN_MODE_CONNECTABLE_DISCOVERABLE = 23; - - /** - * Device only has a display. - * - * @hide - */ - public static final int IO_CAPABILITY_OUT = 0; - - /** - * Device has a display and the ability to input Yes/No. - * - * @hide - */ - public static final int IO_CAPABILITY_IO = 1; - - /** - * Device only has a keyboard for entry but no display. - * - * @hide - */ - public static final int IO_CAPABILITY_IN = 2; - - /** - * Device has no Input or Output capability. - * - * @hide - */ - public static final int IO_CAPABILITY_NONE = 3; - - /** - * Device has a display and a full keyboard. - * - * @hide - */ - public static final int IO_CAPABILITY_KBDISP = 4; - - /** - * Maximum range value for Input/Output capabilities. - * - *

This should be updated when adding a new Input/Output capability. Other code - * like validation depends on this being accurate. - * - * @hide - */ - public static final int IO_CAPABILITY_MAX = 5; - - /** - * The Input/Output capability of the device is unknown. - * - * @hide - */ - public static final int IO_CAPABILITY_UNKNOWN = 255; - - /** @hide */ - @IntDef({IO_CAPABILITY_OUT, IO_CAPABILITY_IO, IO_CAPABILITY_IN, IO_CAPABILITY_NONE, - IO_CAPABILITY_KBDISP}) - @Retention(RetentionPolicy.SOURCE) - public @interface IoCapability {} - - /** @hide */ - @IntDef(prefix = "ACTIVE_DEVICE_", value = {ACTIVE_DEVICE_AUDIO, - ACTIVE_DEVICE_PHONE_CALL, ACTIVE_DEVICE_ALL}) - @Retention(RetentionPolicy.SOURCE) - public @interface ActiveDeviceUse {} - - /** - * Use the specified device for audio (a2dp and hearing aid profile) - * - * @hide - */ - @SystemApi - public static final int ACTIVE_DEVICE_AUDIO = 0; - - /** - * Use the specified device for phone calls (headset profile and hearing - * aid profile) - * - * @hide - */ - @SystemApi - public static final int ACTIVE_DEVICE_PHONE_CALL = 1; - - /** - * Use the specified device for a2dp, hearing aid profile, and headset profile - * - * @hide - */ - @SystemApi - public static final int ACTIVE_DEVICE_ALL = 2; - - /** @hide */ - @IntDef({BluetoothProfile.HEADSET, BluetoothProfile.A2DP, - BluetoothProfile.HEARING_AID}) - @Retention(RetentionPolicy.SOURCE) - public @interface ActiveDeviceProfile {} - - /** - * Broadcast Action: The local Bluetooth adapter has started the remote - * device discovery process. - *

This usually involves an inquiry scan of about 12 seconds, followed - * by a page scan of each new device to retrieve its Bluetooth name. - *

Register for {@link BluetoothDevice#ACTION_FOUND} to be notified as - * remote Bluetooth devices are found. - *

Device discovery is a heavyweight procedure. New connections to - * remote Bluetooth devices should not be attempted while discovery is in - * progress, and existing connections will experience limited bandwidth - * and high latency. Use {@link #cancelDiscovery()} to cancel an ongoing - * discovery. - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothScanPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String - ACTION_DISCOVERY_STARTED = "android.bluetooth.adapter.action.DISCOVERY_STARTED"; - /** - * Broadcast Action: The local Bluetooth adapter has finished the device - * discovery process. - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothScanPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String - ACTION_DISCOVERY_FINISHED = "android.bluetooth.adapter.action.DISCOVERY_FINISHED"; - - /** - * Broadcast Action: The local Bluetooth adapter has changed its friendly - * Bluetooth name. - *

This name is visible to remote Bluetooth devices. - *

Always contains the extra field {@link #EXTRA_LOCAL_NAME} containing - * the name. - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String - ACTION_LOCAL_NAME_CHANGED = "android.bluetooth.adapter.action.LOCAL_NAME_CHANGED"; - /** - * Used as a String extra field in {@link #ACTION_LOCAL_NAME_CHANGED} - * intents to request the local Bluetooth name. - */ - public static final String EXTRA_LOCAL_NAME = "android.bluetooth.adapter.extra.LOCAL_NAME"; - - /** - * Intent used to broadcast the change in connection state of the local - * Bluetooth adapter to a profile of the remote device. When the adapter is - * not connected to any profiles of any remote devices and it attempts a - * connection to a profile this intent will be sent. Once connected, this intent - * will not be sent for any more connection attempts to any profiles of any - * remote device. When the adapter disconnects from the last profile its - * connected to of any remote device, this intent will be sent. - * - *

This intent is useful for applications that are only concerned about - * whether the local adapter is connected to any profile of any device and - * are not really concerned about which profile. For example, an application - * which displays an icon to display whether Bluetooth is connected or not - * can use this intent. - * - *

This intent will have 3 extras: - * {@link #EXTRA_CONNECTION_STATE} - The current connection state. - * {@link #EXTRA_PREVIOUS_CONNECTION_STATE}- The previous connection state. - * {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. - * - * {@link #EXTRA_CONNECTION_STATE} or {@link #EXTRA_PREVIOUS_CONNECTION_STATE} - * can be any of {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING}, - * {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}. - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String - ACTION_CONNECTION_STATE_CHANGED = - "android.bluetooth.adapter.action.CONNECTION_STATE_CHANGED"; - - /** - * Extra used by {@link #ACTION_CONNECTION_STATE_CHANGED} - * - * This extra represents the current connection state. - */ - public static final String EXTRA_CONNECTION_STATE = - "android.bluetooth.adapter.extra.CONNECTION_STATE"; - - /** - * Extra used by {@link #ACTION_CONNECTION_STATE_CHANGED} - * - * This extra represents the previous connection state. - */ - public static final String EXTRA_PREVIOUS_CONNECTION_STATE = - "android.bluetooth.adapter.extra.PREVIOUS_CONNECTION_STATE"; - - /** - * Broadcast Action: The Bluetooth adapter state has changed in LE only mode. - * - * @hide - */ - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - @SystemApi public static final String ACTION_BLE_STATE_CHANGED = - "android.bluetooth.adapter.action.BLE_STATE_CHANGED"; - - /** - * Intent used to broadcast the change in the Bluetooth address - * of the local Bluetooth adapter. - *

Always contains the extra field {@link - * #EXTRA_BLUETOOTH_ADDRESS} containing the Bluetooth address. - * - * Note: only system level processes are allowed to send this - * defined broadcast. - * - * @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"; - - /** - * Used as a String extra field in {@link - * #ACTION_BLUETOOTH_ADDRESS_CHANGED} intent to store the local - * Bluetooth address. - * - * @hide - */ - public static final String EXTRA_BLUETOOTH_ADDRESS = - "android.bluetooth.adapter.extra.BLUETOOTH_ADDRESS"; - - /** - * Broadcast Action: The notifys Bluetooth ACL connected event. This will be - * by BLE Always on enabled application to know the ACL_CONNECTED event - * when Bluetooth state in STATE_BLE_ON. This denotes GATT connection - * as Bluetooth LE is the only feature available in STATE_BLE_ON - * - * This is counterpart of {@link BluetoothDevice#ACTION_ACL_CONNECTED} which - * works in Bluetooth state STATE_ON - * - * @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"; - - /** - * Broadcast Action: The notifys Bluetooth ACL connected event. This will be - * by BLE Always on enabled application to know the ACL_DISCONNECTED event - * when Bluetooth state in STATE_BLE_ON. This denotes GATT disconnection as Bluetooth - * LE is the only feature available in STATE_BLE_ON - * - * This is counterpart of {@link BluetoothDevice#ACTION_ACL_DISCONNECTED} which - * works in Bluetooth state STATE_ON - * - * @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"; - - /** The profile is in disconnected state */ - public static final int STATE_DISCONNECTED = - 0; //BluetoothProtoEnums.CONNECTION_STATE_DISCONNECTED; - /** The profile is in connecting state */ - public static final int STATE_CONNECTING = 1; //BluetoothProtoEnums.CONNECTION_STATE_CONNECTING; - /** The profile is in connected state */ - public static final int STATE_CONNECTED = 2; //BluetoothProtoEnums.CONNECTION_STATE_CONNECTED; - /** The profile is in disconnecting state */ - public static final int STATE_DISCONNECTING = - 3; //BluetoothProtoEnums.CONNECTION_STATE_DISCONNECTING; - - /** @hide */ - public static final String BLUETOOTH_MANAGER_SERVICE = "bluetooth_manager"; - private final IBinder mToken; - - - /** - * When creating a ServerSocket using listenUsingRfcommOn() or - * listenUsingL2capOn() use SOCKET_CHANNEL_AUTO_STATIC to create - * a ServerSocket that auto assigns a channel number to the first - * bluetooth socket. - * The channel number assigned to this first Bluetooth Socket will - * be stored in the ServerSocket, and reused for subsequent Bluetooth - * sockets. - * - * @hide - */ - public static final int SOCKET_CHANNEL_AUTO_STATIC_NO_SDP = -2; - - - private static final int ADDRESS_LENGTH = 17; - - /** - * Lazily initialized singleton. Guaranteed final after first object - * constructed. - */ - private static BluetoothAdapter sAdapter; - - private BluetoothLeScanner mBluetoothLeScanner; - private BluetoothLeAdvertiser mBluetoothLeAdvertiser; - private PeriodicAdvertisingManager mPeriodicAdvertisingManager; - - private final IBluetoothManager mManagerService; - private final AttributionSource mAttributionSource; - - // Yeah, keeping both mService and sService isn't pretty, but it's too late - // in the current release for a major refactoring, so we leave them both - // intact until this can be cleaned up in a future release - - @UnsupportedAppUsage - @GuardedBy("mServiceLock") - private IBluetooth mService; - private final ReentrantReadWriteLock mServiceLock = new ReentrantReadWriteLock(); - - @GuardedBy("sServiceLock") - private static boolean sServiceRegistered; - @GuardedBy("sServiceLock") - private static IBluetooth sService; - private static final Object sServiceLock = new Object(); - - private final Object mLock = new Object(); - private final Map mLeScanClients; - private final Map>> - mMetadataListeners = new HashMap<>(); - private final Map - mBluetoothConnectionCallbackExecutorMap = new HashMap<>(); - - /** - * Bluetooth metadata listener. Overrides the default BluetoothMetadataListener - * implementation. - */ - @SuppressLint("AndroidFrameworkBluetoothPermission") - private final IBluetoothMetadataListener mBluetoothMetadataListener = - new IBluetoothMetadataListener.Stub() { - @Override - public void onMetadataChanged(BluetoothDevice device, int key, byte[] value) { - Attributable.setAttributionSource(device, mAttributionSource); - synchronized (mMetadataListeners) { - if (mMetadataListeners.containsKey(device)) { - List> list = - mMetadataListeners.get(device); - for (Pair pair : list) { - OnMetadataChangedListener listener = pair.first; - Executor executor = pair.second; - executor.execute(() -> { - listener.onMetadataChanged(device, key, value); - }); - } - } - } - return; - } - }; - - /** - * Get a handle to the default local Bluetooth adapter. - *

- * Currently Android only supports one Bluetooth adapter, but the API could - * be extended to support more. This will always return the default adapter. - *

- * - * @return the default local adapter, or null if Bluetooth is not supported - * on this hardware platform - * @deprecated this method will continue to work, but developers are - * strongly encouraged to migrate to using - * {@link BluetoothManager#getAdapter()}, since that approach - * enables support for {@link Context#createAttributionContext}. - */ - @Deprecated - @RequiresNoPermission - public static synchronized BluetoothAdapter getDefaultAdapter() { - if (sAdapter == null) { - sAdapter = createAdapter(AttributionSource.myAttributionSource()); - } - return sAdapter; - } - - /** {@hide} */ - public static BluetoothAdapter createAdapter(AttributionSource attributionSource) { - IBinder binder = ServiceManager.getService(BLUETOOTH_MANAGER_SERVICE); - if (binder != null) { - return new BluetoothAdapter(IBluetoothManager.Stub.asInterface(binder), - attributionSource); - } else { - Log.e(TAG, "Bluetooth binder is null"); - return null; - } - } - - /** - * Use {@link #getDefaultAdapter} to get the BluetoothAdapter instance. - */ - BluetoothAdapter(IBluetoothManager managerService, AttributionSource attributionSource) { - mManagerService = Objects.requireNonNull(managerService); - mAttributionSource = Objects.requireNonNull(attributionSource); - synchronized (mServiceLock.writeLock()) { - mService = getBluetoothService(mManagerCallback); - } - mLeScanClients = new HashMap(); - mToken = new Binder(DESCRIPTOR); - } - - /** - * Get a {@link BluetoothDevice} object for the given Bluetooth hardware - * address. - *

Valid Bluetooth hardware addresses must be upper case, in a format - * such as "00:11:22:33:AA:BB". The helper {@link #checkBluetoothAddress} is - * available to validate a Bluetooth address. - *

A {@link BluetoothDevice} will always be returned for a valid - * hardware address, even if this adapter has never seen that device. - * - * @param address valid Bluetooth MAC address - * @throws IllegalArgumentException if address is invalid - */ - @RequiresNoPermission - public BluetoothDevice getRemoteDevice(String address) { - final BluetoothDevice res = new BluetoothDevice(address); - res.setAttributionSource(mAttributionSource); - return res; - } - - /** - * Get a {@link BluetoothDevice} object for the given Bluetooth hardware - * address. - *

Valid Bluetooth hardware addresses must be 6 bytes. This method - * expects the address in network byte order (MSB first). - *

A {@link BluetoothDevice} will always be returned for a valid - * hardware address, even if this adapter has never seen that device. - * - * @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"); - } - final BluetoothDevice res = new BluetoothDevice( - String.format(Locale.US, "%02X:%02X:%02X:%02X:%02X:%02X", address[0], address[1], - address[2], address[3], address[4], address[5])); - res.setAttributionSource(mAttributionSource); - return res; - } - - /** - * Returns a {@link BluetoothLeAdvertiser} object for Bluetooth LE Advertising operations. - * Will return null if Bluetooth is turned off or if Bluetooth LE Advertising is not - * supported on this device. - *

- * 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; - } - synchronized (mLock) { - if (mBluetoothLeAdvertiser == null) { - mBluetoothLeAdvertiser = new BluetoothLeAdvertiser(this); - } - return mBluetoothLeAdvertiser; - } - } - - /** - * Returns a {@link PeriodicAdvertisingManager} object for Bluetooth LE Periodic Advertising - * operations. Will return null if Bluetooth is turned off or if Bluetooth LE Periodic - * Advertising is not supported on this device. - *

- * Use {@link #isLePeriodicAdvertisingSupported()} to check whether LE Periodic Advertising is - * supported on this device before calling this method. - * - * @hide - */ - @RequiresNoPermission - public PeriodicAdvertisingManager getPeriodicAdvertisingManager() { - if (!getLeAccess()) { - return null; - } - - if (!isLePeriodicAdvertisingSupported()) { - return null; - } - - synchronized (mLock) { - if (mPeriodicAdvertisingManager == null) { - mPeriodicAdvertisingManager = new PeriodicAdvertisingManager(this); - } - return mPeriodicAdvertisingManager; - } - } - - /** - * Returns a {@link BluetoothLeScanner} object for Bluetooth LE scan operations. - */ - @RequiresNoPermission - public BluetoothLeScanner getBluetoothLeScanner() { - if (!getLeAccess()) { - return null; - } - synchronized (mLock) { - if (mBluetoothLeScanner == null) { - mBluetoothLeScanner = new BluetoothLeScanner(this); - } - return mBluetoothLeScanner; - } - } - - /** - * Return true if Bluetooth is currently enabled and ready for use. - *

Equivalent to: - * getBluetoothState() == STATE_ON - * - * @return true if the local adapter is turned on - */ - @RequiresLegacyBluetoothPermission - @RequiresNoPermission - public boolean isEnabled() { - return getState() == BluetoothAdapter.STATE_ON; - } - - /** - * Return true if Bluetooth LE(Always BLE On feature) is currently - * enabled and ready for use - *

This returns true if current state is either STATE_ON or STATE_BLE_ON - * - * @return true if the local Bluetooth LE adapter is turned on - * @hide - */ - @SystemApi - @RequiresNoPermission - public boolean isLeEnabled() { - final int state = getLeState(); - if (DBG) { - Log.d(TAG, "isLeEnabled(): " + BluetoothAdapter.nameForState(state)); - } - return (state == BluetoothAdapter.STATE_ON - || state == BluetoothAdapter.STATE_BLE_ON - || state == BluetoothAdapter.STATE_TURNING_ON - || state == BluetoothAdapter.STATE_TURNING_OFF); - } - - /** - * Turns off Bluetooth LE which was earlier turned on by calling enableBLE(). - * - *

If the internal Adapter state is STATE_BLE_ON, this would trigger the transition - * to STATE_OFF and completely shut-down Bluetooth - * - *

If the Adapter state is STATE_ON, This would unregister the existance of - * special Bluetooth LE application and hence the further turning off of Bluetooth - * from UI would ensure the complete turn-off of Bluetooth rather than staying back - * BLE only state - * - *

This is an asynchronous call: it will return immediately, and - * clients should listen for {@link #ACTION_BLE_STATE_CHANGED} - * to be notified of subsequent adapter state changes If this call returns - * true, then the adapter state will immediately transition from {@link - * #STATE_ON} to {@link #STATE_TURNING_OFF}, and some time - * later transition to either {@link #STATE_BLE_ON} or {@link - * #STATE_OFF} based on the existance of the further Always BLE ON enabled applications - * If this call returns false then there was an - * immediate problem that will prevent the QAdapter from being turned off - - * such as the QAadapter already being turned off. - * - * @return true to indicate success, or false on immediate error - * @hide - */ - @SystemApi - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public boolean disableBLE() { - if (!isBleScanAlwaysAvailable()) { - return false; - } - try { - return mManagerService.disableBle(mAttributionSource, mToken); - } catch (RemoteException e) { - Log.e(TAG, "", e); - } - return false; - } - - /** - * Applications who want to only use Bluetooth Low Energy (BLE) can call enableBLE. - * - * enableBLE registers the existence of an app using only LE functions. - * - * enableBLE may enable Bluetooth to an LE only mode so that an app can use - * LE related features (BluetoothGatt or BluetoothGattServer classes) - * - * If the user disables Bluetooth while an app is registered to use LE only features, - * Bluetooth will remain on in LE only mode for the app. - * - * When Bluetooth is in LE only mode, it is not shown as ON to the UI. - * - *

This is an asynchronous call: it returns immediately, and - * clients should listen for {@link #ACTION_BLE_STATE_CHANGED} - * to be notified of adapter state changes. - * - * If this call returns * true, then the adapter state is either in a mode where - * LE is available, or will transition from {@link #STATE_OFF} to {@link #STATE_BLE_TURNING_ON}, - * and some time later transition to either {@link #STATE_OFF} or {@link #STATE_BLE_ON}. - * - * If this call returns false then there was an immediate problem that prevents the - * adapter from being turned on - such as Airplane mode. - * - * {@link #ACTION_BLE_STATE_CHANGED} returns the Bluetooth Adapter's various - * states, It includes all the classic Bluetooth Adapter states along with - * internal BLE only states - * - * @return true to indicate Bluetooth LE will be available, or false on immediate error - * @hide - */ - @SystemApi - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public boolean enableBLE() { - if (!isBleScanAlwaysAvailable()) { - return false; - } - try { - return mManagerService.enableBle(mAttributionSource, mToken); - } catch (RemoteException e) { - Log.e(TAG, "", e); - } - - return false; - } - - /* - private static final String BLUETOOTH_GET_STATE_CACHE_PROPERTY = "cache_key.bluetooth.get_state"; - - private final PropertyInvalidatedCache mBluetoothGetStateCache = - new PropertyInvalidatedCache( - 8, BLUETOOTH_GET_STATE_CACHE_PROPERTY) { - @Override - @SuppressLint("AndroidFrameworkRequiresPermission") - protected Integer recompute(Void query) { - try { - return mService.getState(); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - }; - */ - - /** @hide */ - /* - @RequiresNoPermission - public void disableBluetoothGetStateCache() { - mBluetoothGetStateCache.disableLocal(); - } - */ - - /** @hide */ - /* - public static void invalidateBluetoothGetStateCache() { - PropertyInvalidatedCache.invalidateCache(BLUETOOTH_GET_STATE_CACHE_PROPERTY); - } - */ - - /** - * Fetch the current bluetooth state. If the service is down, return - * OFF. - */ - @AdapterState - private int getStateInternal() { - int state = BluetoothAdapter.STATE_OFF; - try { - mServiceLock.readLock().lock(); - if (mService != null) { - //state = mBluetoothGetStateCache.query(null); - state = mService.getState(); - } - } catch (RemoteException e) { - Log.e(TAG, "", e); - e.rethrowFromSystemServer(); - } finally { - mServiceLock.readLock().unlock(); - } - return state; - } - - /** - * Get the current state of the local Bluetooth adapter. - *

Possible return values are - * {@link #STATE_OFF}, - * {@link #STATE_TURNING_ON}, - * {@link #STATE_ON}, - * {@link #STATE_TURNING_OFF}. - * - * @return current state of Bluetooth adapter - */ - @RequiresLegacyBluetoothPermission - @RequiresNoPermission - @AdapterState - public int getState() { - int state = getStateInternal(); - - // Consider all internal states as OFF - if (state == BluetoothAdapter.STATE_BLE_ON || state == BluetoothAdapter.STATE_BLE_TURNING_ON - || state == BluetoothAdapter.STATE_BLE_TURNING_OFF) { - if (VDBG) { - Log.d(TAG, "Consider " + BluetoothAdapter.nameForState(state) + " state as OFF"); - } - state = BluetoothAdapter.STATE_OFF; - } - if (VDBG) { - Log.d(TAG, "" + hashCode() + ": getState(). Returning " + BluetoothAdapter.nameForState( - state)); - } - return state; - } - - /** - * Get the current state of the local Bluetooth adapter - *

This returns current internal state of Adapter including LE ON/OFF - * - *

Possible return values are - * {@link #STATE_OFF}, - * {@link #STATE_BLE_TURNING_ON}, - * {@link #STATE_BLE_ON}, - * {@link #STATE_TURNING_ON}, - * {@link #STATE_ON}, - * {@link #STATE_TURNING_OFF}, - * {@link #STATE_BLE_TURNING_OFF}. - * - * @return current state of Bluetooth adapter - * @hide - */ - @RequiresLegacyBluetoothPermission - @RequiresNoPermission - @AdapterState - @UnsupportedAppUsage(publicAlternatives = "Use {@link #getState()} instead to determine " - + "whether you can use BLE & BT classic.") - public int getLeState() { - int state = getStateInternal(); - - if (VDBG) { - Log.d(TAG, "getLeState() returning " + BluetoothAdapter.nameForState(state)); - } - return state; - } - - boolean getLeAccess() { - if (getLeState() == STATE_ON) { - return true; - } else if (getLeState() == STATE_BLE_ON) { - return true; // TODO: FILTER SYSTEM APPS HERE <-- - } - - return false; - } - - /** - * Turn on the local Bluetooth adapter—do not use without explicit - * user action to turn on Bluetooth. - *

This powers on the underlying Bluetooth hardware, and starts all - * Bluetooth system services. - *

Bluetooth should never be enabled without - * direct user consent. If you want to turn on Bluetooth in order - * to create a wireless connection, you should use the {@link - * #ACTION_REQUEST_ENABLE} Intent, which will raise a dialog that requests - * user permission to turn on Bluetooth. The {@link #enable()} method is - * provided only for applications that include a user interface for changing - * system settings, such as a "power manager" app.

- *

This is an asynchronous call: it will return immediately, and - * clients should listen for {@link #ACTION_STATE_CHANGED} - * to be notified of subsequent adapter state changes. If this call returns - * true, then the adapter state will immediately transition from {@link - * #STATE_OFF} to {@link #STATE_TURNING_ON}, and some time - * later transition to either {@link #STATE_OFF} or {@link - * #STATE_ON}. If this call returns false then there was an - * immediate problem that will prevent the adapter from being turned on - - * such as Airplane mode, or the adapter is already turned on. - * - * @return true to indicate adapter startup has begun, or false on immediate error - */ - @RequiresLegacyBluetoothAdminPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public boolean enable() { - if (isEnabled()) { - if (DBG) { - Log.d(TAG, "enable(): BT already enabled!"); - } - return true; - } - try { - return mManagerService.enable(mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "", e); - } - return false; - } - - /** - * Turn off the local Bluetooth adapter—do not use without explicit - * user action to turn off Bluetooth. - *

This gracefully shuts down all Bluetooth connections, stops Bluetooth - * system services, and powers down the underlying Bluetooth hardware. - *

Bluetooth should never be disabled without - * direct user consent. The {@link #disable()} method is - * provided only for applications that include a user interface for changing - * system settings, such as a "power manager" app.

- *

This is an asynchronous call: it will return immediately, and - * clients should listen for {@link #ACTION_STATE_CHANGED} - * to be notified of subsequent adapter state changes. If this call returns - * true, then the adapter state will immediately transition from {@link - * #STATE_ON} to {@link #STATE_TURNING_OFF}, and some time - * later transition to either {@link #STATE_OFF} or {@link - * #STATE_ON}. If this call returns false then there was an - * immediate problem that will prevent the adapter from being turned off - - * such as the adapter already being turned off. - * - * @return true to indicate adapter shutdown has begun, or false on immediate error - */ - @RequiresLegacyBluetoothAdminPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public boolean disable() { - try { - return mManagerService.disable(mAttributionSource, true); - } catch (RemoteException e) { - Log.e(TAG, "", e); - } - return false; - } - - /** - * Turn off the local Bluetooth adapter and don't persist the setting. - * - * @param persist Indicate whether the off state should be persisted following the next reboot - * @return true to indicate adapter shutdown has begun, or false on immediate error - * @hide - */ - @SystemApi - @RequiresLegacyBluetoothAdminPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) - public boolean disable(boolean persist) { - - try { - return mManagerService.disable(mAttributionSource, persist); - } catch (RemoteException e) { - Log.e(TAG, "", e); - } - return false; - } - - /** - * Returns the hardware address of the local Bluetooth adapter. - *

For example, "00:11:22:AA:BB:CC". - * - * @return Bluetooth hardware address as string - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.LOCAL_MAC_ADDRESS, - }) - public String getAddress() { - try { - return mManagerService.getAddress(mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "", e); - } - return null; - } - - /** - * Get the friendly Bluetooth name of the local Bluetooth adapter. - *

This name is visible to remote Bluetooth devices. - * - * @return the Bluetooth name, or null on error - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public String getName() { - try { - return mManagerService.getName(mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "", e); - } - return null; - } - - /** {@hide} */ - @RequiresBluetoothAdvertisePermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE) - public int getNameLengthForAdvertise() { - try { - return mService.getNameLengthForAdvertise(mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "", e); - } - return -1; - } - - /** - * Factory reset bluetooth settings. - * - * @return true to indicate that the config file was successfully cleared - * @hide - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) - public boolean factoryReset() { - try { - mServiceLock.readLock().lock(); - if (mService != null && mService.factoryReset(mAttributionSource) - && mManagerService != null - && mManagerService.onFactoryReset(mAttributionSource)) { - return true; - } - Log.e(TAG, "factoryReset(): Setting persist.bluetooth.factoryreset to retry later"); - BluetoothProperties.factory_reset(true); - } catch (RemoteException e) { - Log.e(TAG, "", e); - } finally { - mServiceLock.readLock().unlock(); - } - return false; - } - - /** - * Get the UUIDs supported by the local Bluetooth adapter. - * - * @return the UUIDs supported by the local Bluetooth Adapter. - * @hide - */ - @UnsupportedAppUsage - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public @Nullable ParcelUuid[] getUuids() { - if (getState() != STATE_ON) { - return null; - } - try { - mServiceLock.readLock().lock(); - if (mService != null) { - return mService.getUuids(mAttributionSource); - } - } catch (RemoteException e) { - Log.e(TAG, "", e); - } finally { - mServiceLock.readLock().unlock(); - } - return null; - } - - /** - * Set the friendly Bluetooth name of the local Bluetooth adapter. - *

This name is visible to remote Bluetooth devices. - *

Valid Bluetooth names are a maximum of 248 bytes using UTF-8 - * encoding, although many remote devices can only display the first - * 40 characters, and some may be limited to just 20. - *

If Bluetooth state is not {@link #STATE_ON}, this API - * will return false. After turning on Bluetooth, - * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON} - * to get the updated value. - * - * @param name a valid Bluetooth name - * @return true if the name was set, false otherwise - */ - @RequiresLegacyBluetoothAdminPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public boolean setName(String name) { - if (getState() != STATE_ON) { - return false; - } - try { - mServiceLock.readLock().lock(); - if (mService != null) { - return mService.setName(name, mAttributionSource); - } - } catch (RemoteException e) { - Log.e(TAG, "", e); - } finally { - mServiceLock.readLock().unlock(); - } - return false; - } - - /** - * Returns the {@link BluetoothClass} Bluetooth Class of Device (CoD) of the local Bluetooth - * adapter. - * - * @return {@link BluetoothClass} Bluetooth CoD of local Bluetooth device. - * - * @hide - */ - @RequiresLegacyBluetoothAdminPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public BluetoothClass getBluetoothClass() { - if (getState() != STATE_ON) { - return null; - } - try { - mServiceLock.readLock().lock(); - if (mService != null) { - return mService.getBluetoothClass(mAttributionSource); - } - } catch (RemoteException e) { - Log.e(TAG, "", e); - } finally { - mServiceLock.readLock().unlock(); - } - return null; - } - - /** - * Sets the {@link BluetoothClass} Bluetooth Class of Device (CoD) of the local Bluetooth - * adapter. - * - *

Note: This value persists across system reboot. - * - * @param bluetoothClass {@link BluetoothClass} to set the local Bluetooth adapter to. - * @return true if successful, false if unsuccessful. - * - * @hide - */ - @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) - public boolean setBluetoothClass(BluetoothClass bluetoothClass) { - if (getState() != STATE_ON) { - return false; - } - try { - mServiceLock.readLock().lock(); - if (mService != null) { - return mService.setBluetoothClass(bluetoothClass, mAttributionSource); - } - } catch (RemoteException e) { - Log.e(TAG, "", e); - } finally { - mServiceLock.readLock().unlock(); - } - return false; - } - - /** - * Returns the Input/Output capability of the device for classic Bluetooth. - * - * @return Input/Output capability of the device. One of {@link #IO_CAPABILITY_OUT}, - * {@link #IO_CAPABILITY_IO}, {@link #IO_CAPABILITY_IN}, {@link #IO_CAPABILITY_NONE}, - * {@link #IO_CAPABILITY_KBDISP} or {@link #IO_CAPABILITY_UNKNOWN}. - * - * @hide - */ - @RequiresLegacyBluetoothAdminPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - @IoCapability - public int getIoCapability() { - if (getState() != STATE_ON) return BluetoothAdapter.IO_CAPABILITY_UNKNOWN; - try { - mServiceLock.readLock().lock(); - if (mService != null) return mService.getIoCapability(mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, e.getMessage(), e); - } finally { - mServiceLock.readLock().unlock(); - } - return BluetoothAdapter.IO_CAPABILITY_UNKNOWN; - } - - /** - * Sets the Input/Output capability of the device for classic Bluetooth. - * - *

Changing the Input/Output capability of a device only takes effect on restarting the - * Bluetooth stack. You would need to restart the stack using {@link BluetoothAdapter#disable()} - * and {@link BluetoothAdapter#enable()} to see the changes. - * - * @param capability Input/Output capability of the device. One of {@link #IO_CAPABILITY_OUT}, - * {@link #IO_CAPABILITY_IO}, {@link #IO_CAPABILITY_IN}, - * {@link #IO_CAPABILITY_NONE} or {@link #IO_CAPABILITY_KBDISP}. - * - * @hide - */ - @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) - public boolean setIoCapability(@IoCapability int capability) { - if (getState() != STATE_ON) return false; - try { - mServiceLock.readLock().lock(); - if (mService != null) return mService.setIoCapability(capability, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, e.getMessage(), e); - } finally { - mServiceLock.readLock().unlock(); - } - return false; - } - - /** - * Returns the Input/Output capability of the device for BLE operations. - * - * @return Input/Output capability of the device. One of {@link #IO_CAPABILITY_OUT}, - * {@link #IO_CAPABILITY_IO}, {@link #IO_CAPABILITY_IN}, {@link #IO_CAPABILITY_NONE}, - * {@link #IO_CAPABILITY_KBDISP} or {@link #IO_CAPABILITY_UNKNOWN}. - * - * @hide - */ - @RequiresLegacyBluetoothAdminPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - @IoCapability - public int getLeIoCapability() { - if (getState() != STATE_ON) return BluetoothAdapter.IO_CAPABILITY_UNKNOWN; - try { - mServiceLock.readLock().lock(); - if (mService != null) return mService.getLeIoCapability(mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, e.getMessage(), e); - } finally { - mServiceLock.readLock().unlock(); - } - return BluetoothAdapter.IO_CAPABILITY_UNKNOWN; - } - - /** - * Sets the Input/Output capability of the device for BLE operations. - * - *

Changing the Input/Output capability of a device only takes effect on restarting the - * Bluetooth stack. You would need to restart the stack using {@link BluetoothAdapter#disable()} - * and {@link BluetoothAdapter#enable()} to see the changes. - * - * @param capability Input/Output capability of the device. One of {@link #IO_CAPABILITY_OUT}, - * {@link #IO_CAPABILITY_IO}, {@link #IO_CAPABILITY_IN}, - * {@link #IO_CAPABILITY_NONE} or {@link #IO_CAPABILITY_KBDISP}. - * - * @hide - */ - @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) - public boolean setLeIoCapability(@IoCapability int capability) { - if (getState() != STATE_ON) return false; - try { - mServiceLock.readLock().lock(); - if (mService != null) return mService.setLeIoCapability(capability, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, e.getMessage(), e); - } finally { - mServiceLock.readLock().unlock(); - } - return false; - } - - /** - * Get the current Bluetooth scan mode of the local Bluetooth adapter. - *

The Bluetooth scan mode determines if the local adapter is - * connectable and/or discoverable from remote Bluetooth devices. - *

Possible values are: - * {@link #SCAN_MODE_NONE}, - * {@link #SCAN_MODE_CONNECTABLE}, - * {@link #SCAN_MODE_CONNECTABLE_DISCOVERABLE}. - *

If Bluetooth state is not {@link #STATE_ON}, this API - * will return {@link #SCAN_MODE_NONE}. After turning on Bluetooth, - * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON} - * to get the updated value. - * - * @return scan mode - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothScanPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) - @ScanMode - public int getScanMode() { - if (getState() != STATE_ON) { - return SCAN_MODE_NONE; - } - try { - mServiceLock.readLock().lock(); - if (mService != null) { - return mService.getScanMode(mAttributionSource); - } - } catch (RemoteException e) { - Log.e(TAG, "", e); - } finally { - mServiceLock.readLock().unlock(); - } - return SCAN_MODE_NONE; - } - - /** - * Set the Bluetooth scan mode of the local Bluetooth adapter. - *

The Bluetooth scan mode determines if the local adapter is - * connectable and/or discoverable from remote Bluetooth devices. - *

For privacy reasons, discoverable mode is automatically turned off - * after durationMillis milliseconds. For example, 120000 milliseconds should be - * enough for a remote device to initiate and complete its discovery process. - *

Valid scan mode values are: - * {@link #SCAN_MODE_NONE}, - * {@link #SCAN_MODE_CONNECTABLE}, - * {@link #SCAN_MODE_CONNECTABLE_DISCOVERABLE}. - *

If Bluetooth state is not {@link #STATE_ON}, this API - * will return false. After turning on Bluetooth, - * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON} - * to get the updated value. - *

Applications cannot set the scan mode. They should use - * startActivityForResult( - * BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE}) - * instead. - * - * @param mode valid scan mode - * @param durationMillis time in milliseconds to apply scan mode, only used for {@link - * #SCAN_MODE_CONNECTABLE_DISCOVERABLE} - * @return true if the scan mode was set, false otherwise - * @hide - */ - @UnsupportedAppUsage(publicAlternatives = "Use {@link #ACTION_REQUEST_DISCOVERABLE}, which " - + "shows UI that confirms the user wants to go into discoverable mode.") - @RequiresLegacyBluetoothPermission - @RequiresBluetoothScanPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) - public boolean setScanMode(@ScanMode int mode, long durationMillis) { - if (getState() != STATE_ON) { - return false; - } - try { - mServiceLock.readLock().lock(); - if (mService != null) { - int durationSeconds = Math.toIntExact(durationMillis / 1000); - return mService.setScanMode(mode, durationSeconds, mAttributionSource); - } - } catch (RemoteException e) { - Log.e(TAG, "", e); - } catch (ArithmeticException ex) { - Log.e(TAG, "setScanMode: Duration in seconds outside of the bounds of an int"); - throw new IllegalArgumentException("Duration not in bounds. In seconds, the " - + "durationMillis must be in the range of an int"); - } finally { - mServiceLock.readLock().unlock(); - } - return false; - } - - /** - * Set the Bluetooth scan mode of the local Bluetooth adapter. - *

The Bluetooth scan mode determines if the local adapter is - * connectable and/or discoverable from remote Bluetooth devices. - *

For privacy reasons, discoverable mode is automatically turned off - * after duration seconds. For example, 120 seconds should be - * enough for a remote device to initiate and complete its discovery - * process. - *

Valid scan mode values are: - * {@link #SCAN_MODE_NONE}, - * {@link #SCAN_MODE_CONNECTABLE}, - * {@link #SCAN_MODE_CONNECTABLE_DISCOVERABLE}. - *

If Bluetooth state is not {@link #STATE_ON}, this API - * will return false. After turning on Bluetooth, - * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON} - * to get the updated value. - *

Applications cannot set the scan mode. They should use - * startActivityForResult( - * BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE}) - * instead. - * - * @param mode valid scan mode - * @return true if the scan mode was set, false otherwise - * @hide - */ - @UnsupportedAppUsage - @RequiresLegacyBluetoothPermission - @RequiresBluetoothScanPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) - public boolean setScanMode(@ScanMode int mode) { - if (getState() != STATE_ON) { - return false; - } - try { - mServiceLock.readLock().lock(); - if (mService != null) { - return mService.setScanMode(mode, getDiscoverableTimeout(), mAttributionSource); - } - } catch (RemoteException e) { - Log.e(TAG, "", e); - } finally { - mServiceLock.readLock().unlock(); - } - return false; - } - - /** @hide */ - @UnsupportedAppUsage - @RequiresBluetoothScanPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) - public int getDiscoverableTimeout() { - if (getState() != STATE_ON) { - return -1; - } - try { - mServiceLock.readLock().lock(); - if (mService != null) { - return mService.getDiscoverableTimeout(mAttributionSource); - } - } catch (RemoteException e) { - Log.e(TAG, "", e); - } finally { - mServiceLock.readLock().unlock(); - } - return -1; - } - - /** @hide */ - @UnsupportedAppUsage - @RequiresBluetoothScanPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) - public void setDiscoverableTimeout(int timeout) { - if (getState() != STATE_ON) { - return; - } - try { - mServiceLock.readLock().lock(); - if (mService != null) { - mService.setDiscoverableTimeout(timeout, mAttributionSource); - } - } catch (RemoteException e) { - Log.e(TAG, "", e); - } finally { - mServiceLock.readLock().unlock(); - } - } - - /** - * Get the end time of the latest remote device discovery process. - * - * @return the latest time that the bluetooth adapter was/will be in discovery mode, in - * milliseconds since the epoch. This time can be in the future if {@link #startDiscovery()} has - * been called recently. - * @hide - */ - @SystemApi - @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) - public long getDiscoveryEndMillis() { - try { - mServiceLock.readLock().lock(); - if (mService != null) { - return mService.getDiscoveryEndMillis(mAttributionSource); - } - } catch (RemoteException e) { - Log.e(TAG, "", e); - } finally { - mServiceLock.readLock().unlock(); - } - return -1; - } - - /** - * Start the remote device discovery process. - *

The discovery process usually involves an inquiry scan of about 12 - * seconds, followed by a page scan of each new device to retrieve its - * Bluetooth name. - *

This is an asynchronous call, it will return immediately. Register - * for {@link #ACTION_DISCOVERY_STARTED} and {@link - * #ACTION_DISCOVERY_FINISHED} intents to determine exactly when the - * discovery starts and completes. Register for {@link - * BluetoothDevice#ACTION_FOUND} to be notified as remote Bluetooth devices - * are found. - *

Device discovery is a heavyweight procedure. New connections to - * remote Bluetooth devices should not be attempted while discovery is in - * progress, and existing connections will experience limited bandwidth - * and high latency. Use {@link #cancelDiscovery()} to cancel an ongoing - * discovery. Discovery is not managed by the Activity, - * but is run as a system service, so an application should always call - * {@link BluetoothAdapter#cancelDiscovery()} even if it - * did not directly request a discovery, just to be sure. - *

Device discovery will only find remote devices that are currently - * discoverable (inquiry scan enabled). Many Bluetooth devices are - * not discoverable by default, and need to be entered into a special mode. - *

If Bluetooth state is not {@link #STATE_ON}, this API - * will return false. After turning on Bluetooth, wait for {@link #ACTION_STATE_CHANGED} - * with {@link #STATE_ON} to get the updated value. - *

If a device is currently bonding, this request will be queued and executed once that - * device has finished bonding. If a request is already queued, this request will be ignored. - * - * @return true on success, false on error - */ - @RequiresLegacyBluetoothAdminPermission - @RequiresBluetoothScanPermission - @RequiresBluetoothLocationPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) - public boolean startDiscovery() { - if (getState() != STATE_ON) { - return false; - } - try { - mServiceLock.readLock().lock(); - if (mService != null) { - return mService.startDiscovery(mAttributionSource); - } - } catch (RemoteException e) { - Log.e(TAG, "", e); - } finally { - mServiceLock.readLock().unlock(); - } - return false; - } - - /** - * Cancel the current device discovery process. - *

Because discovery is a heavyweight procedure for the Bluetooth - * adapter, this method should always be called before attempting to connect - * to a remote device with {@link - * android.bluetooth.BluetoothSocket#connect()}. Discovery is not managed by - * the Activity, but is run as a system service, so an application should - * always call cancel discovery even if it did not directly request a - * discovery, just to be sure. - *

If Bluetooth state is not {@link #STATE_ON}, this API - * will return false. After turning on Bluetooth, - * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON} - * to get the updated value. - * - * @return true on success, false on error - */ - @RequiresLegacyBluetoothAdminPermission - @RequiresBluetoothScanPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) - public boolean cancelDiscovery() { - if (getState() != STATE_ON) { - return false; - } - try { - mServiceLock.readLock().lock(); - if (mService != null) { - return mService.cancelDiscovery(mAttributionSource); - } - } catch (RemoteException e) { - Log.e(TAG, "", e); - } finally { - mServiceLock.readLock().unlock(); - } - return false; - } - - /** - * Return true if the local Bluetooth adapter is currently in the device - * discovery process. - *

Device discovery is a heavyweight procedure. New connections to - * remote Bluetooth devices should not be attempted while discovery is in - * progress, and existing connections will experience limited bandwidth - * and high latency. Use {@link #cancelDiscovery()} to cancel an ongoing - * discovery. - *

Applications can also register for {@link #ACTION_DISCOVERY_STARTED} - * or {@link #ACTION_DISCOVERY_FINISHED} to be notified when discovery - * starts or completes. - *

If Bluetooth state is not {@link #STATE_ON}, this API - * will return false. After turning on Bluetooth, - * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON} - * to get the updated value. - * - * @return true if discovering - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothScanPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) - public boolean isDiscovering() { - if (getState() != STATE_ON) { - return false; - } - try { - mServiceLock.readLock().lock(); - if (mService != null) { - return mService.isDiscovering(mAttributionSource); - } - } catch (RemoteException e) { - Log.e(TAG, "", e); - } finally { - mServiceLock.readLock().unlock(); - } - return false; - } - - /** - * Removes the active device for the grouping of @ActiveDeviceUse specified - * - * @param profiles represents the purpose for which we are setting this as the active device. - * Possible values are: - * {@link BluetoothAdapter#ACTIVE_DEVICE_AUDIO}, - * {@link BluetoothAdapter#ACTIVE_DEVICE_PHONE_CALL}, - * {@link BluetoothAdapter#ACTIVE_DEVICE_ALL} - * @return false on immediate error, true otherwise - * @throws IllegalArgumentException if device is null or profiles is not one of - * {@link ActiveDeviceUse} - * @hide - */ - @SystemApi - @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - android.Manifest.permission.MODIFY_PHONE_STATE, - }) - public boolean removeActiveDevice(@ActiveDeviceUse int profiles) { - if (profiles != ACTIVE_DEVICE_AUDIO && profiles != ACTIVE_DEVICE_PHONE_CALL - && profiles != ACTIVE_DEVICE_ALL) { - Log.e(TAG, "Invalid profiles param value in removeActiveDevice"); - throw new IllegalArgumentException("Profiles must be one of " - + "BluetoothAdapter.ACTIVE_DEVICE_AUDIO, " - + "BluetoothAdapter.ACTIVE_DEVICE_PHONE_CALL, or " - + "BluetoothAdapter.ACTIVE_DEVICE_ALL"); - } - try { - mServiceLock.readLock().lock(); - if (mService != null) { - if (DBG) Log.d(TAG, "removeActiveDevice, profiles: " + profiles); - return mService.removeActiveDevice(profiles, mAttributionSource); - } - } catch (RemoteException e) { - Log.e(TAG, "", e); - } finally { - mServiceLock.readLock().unlock(); - } - - return false; - } - - /** - * Sets device as the active devices for the profiles passed into the function - * - * @param device is the remote bluetooth device - * @param profiles represents the purpose for which we are setting this as the active device. - * Possible values are: - * {@link BluetoothAdapter#ACTIVE_DEVICE_AUDIO}, - * {@link BluetoothAdapter#ACTIVE_DEVICE_PHONE_CALL}, - * {@link BluetoothAdapter#ACTIVE_DEVICE_ALL} - * @return false on immediate error, true otherwise - * @throws IllegalArgumentException if device is null or profiles is not one of - * {@link ActiveDeviceUse} - * @hide - */ - @SystemApi - @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - android.Manifest.permission.MODIFY_PHONE_STATE, - }) - public boolean setActiveDevice(@NonNull BluetoothDevice device, - @ActiveDeviceUse int profiles) { - if (device == null) { - Log.e(TAG, "setActiveDevice: Null device passed as parameter"); - throw new IllegalArgumentException("device cannot be null"); - } - if (profiles != ACTIVE_DEVICE_AUDIO && profiles != ACTIVE_DEVICE_PHONE_CALL - && profiles != ACTIVE_DEVICE_ALL) { - Log.e(TAG, "Invalid profiles param value in setActiveDevice"); - throw new IllegalArgumentException("Profiles must be one of " - + "BluetoothAdapter.ACTIVE_DEVICE_AUDIO, " - + "BluetoothAdapter.ACTIVE_DEVICE_PHONE_CALL, or " - + "BluetoothAdapter.ACTIVE_DEVICE_ALL"); - } - try { - mServiceLock.readLock().lock(); - if (mService != null) { - if (DBG) { - Log.d(TAG, "setActiveDevice, device: " + device + ", profiles: " + profiles); - } - return mService.setActiveDevice(device, profiles, mAttributionSource); - } - } catch (RemoteException e) { - Log.e(TAG, "", e); - } finally { - mServiceLock.readLock().unlock(); - } - - return false; - } - - /** - * Get the active devices for the BluetoothProfile specified - * - * @param profile is the profile from which we want the active devices. - * Possible values are: - * {@link BluetoothProfile#HEADSET}, - * {@link BluetoothProfile#A2DP}, - * {@link BluetoothProfile#HEARING_AID} - * {@link BluetoothProfile#LE_AUDIO} - * @return A list of active bluetooth devices - * @throws IllegalArgumentException If profile is not one of {@link ActiveDeviceProfile} - * @hide - */ - @SystemApi - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) - public @NonNull List getActiveDevices(@ActiveDeviceProfile int profile) { - if (profile != BluetoothProfile.HEADSET - && profile != BluetoothProfile.A2DP - && profile != BluetoothProfile.HEARING_AID - && profile != BluetoothProfile.LE_AUDIO) { - Log.e(TAG, "Invalid profile param value in getActiveDevices"); - throw new IllegalArgumentException("Profiles must be one of " - + "BluetoothProfile.A2DP, " - + "BluetoothProfile.HEARING_AID, or" - + "BluetoothProfile.HEARING_AID" - + "BluetoothProfile.LE_AUDIO"); - } - try { - mServiceLock.readLock().lock(); - if (mService != null) { - if (DBG) { - Log.d(TAG, "getActiveDevices(profile= " - + BluetoothProfile.getProfileName(profile) + ")"); - } - return mService.getActiveDevices(profile, mAttributionSource); - } - } catch (RemoteException e) { - Log.e(TAG, "", e); - } finally { - mServiceLock.readLock().unlock(); - } - - return new ArrayList<>(); - } - - /** - * Return true if the multi advertisement is supported by the chipset - * - * @return true if Multiple Advertisement feature is supported - */ - @RequiresLegacyBluetoothPermission - @RequiresNoPermission - public boolean isMultipleAdvertisementSupported() { - if (getState() != STATE_ON) { - return false; - } - try { - mServiceLock.readLock().lock(); - if (mService != null) { - return mService.isMultiAdvertisementSupported(); - } - } catch (RemoteException e) { - Log.e(TAG, "failed to get isMultipleAdvertisementSupported, error: ", e); - } finally { - mServiceLock.readLock().unlock(); - } - return false; - } - - /** - * Returns {@code true} if BLE scan is always available, {@code false} otherwise.

- * - * If this returns {@code true}, application can issue {@link BluetoothLeScanner#startScan} and - * fetch scan results even when Bluetooth is turned off.

- * - * To change this setting, use {@link #ACTION_REQUEST_BLE_SCAN_ALWAYS_AVAILABLE}. - * - * @hide - */ - @SystemApi - @RequiresNoPermission - public boolean isBleScanAlwaysAvailable() { - try { - return mManagerService.isBleScanAlwaysAvailable(); - } catch (RemoteException e) { - Log.e(TAG, "remote exception when calling isBleScanAlwaysAvailable", e); - return false; - } - } - - /* - private static final String BLUETOOTH_FILTERING_CACHE_PROPERTY = - "cache_key.bluetooth.is_offloaded_filtering_supported"; - private final PropertyInvalidatedCache mBluetoothFilteringCache = - new PropertyInvalidatedCache( - 8, BLUETOOTH_FILTERING_CACHE_PROPERTY) { - @Override - @SuppressLint("AndroidFrameworkRequiresPermission") - protected Boolean recompute(Void query) { - try { - mServiceLock.readLock().lock(); - if (mService != null) { - return mService.isOffloadedFilteringSupported(); - } - } catch (RemoteException e) { - Log.e(TAG, "failed to get isOffloadedFilteringSupported, error: ", e); - } finally { - mServiceLock.readLock().unlock(); - } - return false; - - } - }; - */ - - /** @hide */ - /* - @RequiresNoPermission - public void disableIsOffloadedFilteringSupportedCache() { - mBluetoothFilteringCache.disableLocal(); - } - */ - - /** @hide */ - /* - public static void invalidateIsOffloadedFilteringSupportedCache() { - PropertyInvalidatedCache.invalidateCache(BLUETOOTH_FILTERING_CACHE_PROPERTY); - } - */ - - /** - * Return true if offloaded filters are supported - * - * @return true if chipset supports on-chip filtering - */ - @RequiresLegacyBluetoothPermission - @RequiresNoPermission - public boolean isOffloadedFilteringSupported() { - if (!getLeAccess()) { - return false; - } - //return mBluetoothFilteringCache.query(null); - try { - mServiceLock.readLock().lock(); - if (mService != null) { - return mService.isOffloadedFilteringSupported(); - } - } catch (RemoteException e) { - Log.e(TAG, "failed to get isOffloadedFilteringSupported, error: ", e); - } finally { - mServiceLock.readLock().unlock(); - } - return false; - } - - /** - * Return true if offloaded scan batching is supported - * - * @return true if chipset supports on-chip scan batching - */ - @RequiresLegacyBluetoothPermission - @RequiresNoPermission - public boolean isOffloadedScanBatchingSupported() { - if (!getLeAccess()) { - return false; - } - try { - mServiceLock.readLock().lock(); - if (mService != null) { - return mService.isOffloadedScanBatchingSupported(); - } - } catch (RemoteException e) { - Log.e(TAG, "failed to get isOffloadedScanBatchingSupported, error: ", e); - } finally { - mServiceLock.readLock().unlock(); - } - return false; - } - - /** - * Return true if LE 2M PHY feature is supported. - * - * @return true if chipset supports LE 2M PHY feature - */ - @RequiresLegacyBluetoothPermission - @RequiresNoPermission - public boolean isLe2MPhySupported() { - if (!getLeAccess()) { - return false; - } - try { - mServiceLock.readLock().lock(); - if (mService != null) { - return mService.isLe2MPhySupported(); - } - } catch (RemoteException e) { - Log.e(TAG, "failed to get isExtendedAdvertisingSupported, error: ", e); - } finally { - mServiceLock.readLock().unlock(); - } - return false; - } - - /** - * Return true if LE Coded PHY feature is supported. - * - * @return true if chipset supports LE Coded PHY feature - */ - @RequiresLegacyBluetoothPermission - @RequiresNoPermission - public boolean isLeCodedPhySupported() { - if (!getLeAccess()) { - return false; - } - try { - mServiceLock.readLock().lock(); - if (mService != null) { - return mService.isLeCodedPhySupported(); - } - } catch (RemoteException e) { - Log.e(TAG, "failed to get isLeCodedPhySupported, error: ", e); - } finally { - mServiceLock.readLock().unlock(); - } - return false; - } - - /** - * Return true if LE Extended Advertising feature is supported. - * - * @return true if chipset supports LE Extended Advertising feature - */ - @RequiresLegacyBluetoothPermission - @RequiresNoPermission - public boolean isLeExtendedAdvertisingSupported() { - if (!getLeAccess()) { - return false; - } - try { - mServiceLock.readLock().lock(); - if (mService != null) { - return mService.isLeExtendedAdvertisingSupported(); - } - } catch (RemoteException e) { - Log.e(TAG, "failed to get isLeExtendedAdvertisingSupported, error: ", e); - } finally { - mServiceLock.readLock().unlock(); - } - return false; - } - - /** - * Return true if LE Periodic Advertising feature is supported. - * - * @return true if chipset supports LE Periodic Advertising feature - */ - @RequiresLegacyBluetoothPermission - @RequiresNoPermission - public boolean isLePeriodicAdvertisingSupported() { - if (!getLeAccess()) { - return false; - } - try { - mServiceLock.readLock().lock(); - if (mService != null) { - return mService.isLePeriodicAdvertisingSupported(); - } - } catch (RemoteException e) { - Log.e(TAG, "failed to get isLePeriodicAdvertisingSupported, error: ", e); - } finally { - mServiceLock.readLock().unlock(); - } - return false; - } - - /** @hide */ - @Retention(RetentionPolicy.SOURCE) - @IntDef(value = { - BluetoothStatusCodes.SUCCESS, - BluetoothStatusCodes.ERROR_UNKNOWN, - BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED, - BluetoothStatusCodes.ERROR_FEATURE_NOT_SUPPORTED, - }) - public @interface LeFeatureReturnValues {} - - /** - * Returns {@link BluetoothStatusCodes#SUCCESS} if the LE audio feature is - * supported, returns {@link BluetoothStatusCodes#ERROR_FEATURE_NOT_SUPPORTED} if - * the feature is not supported or an error code. - * - * @return whether the LE audio is supported - */ - @RequiresNoPermission - public @LeFeatureReturnValues int isLeAudioSupported() { - if (!getLeAccess()) { - return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED; - } - try { - mServiceLock.readLock().lock(); - if (mService != null) { - return mService.isLeAudioSupported(); - } - } catch (RemoteException e) { - e.rethrowFromSystemServer(); - } finally { - mServiceLock.readLock().unlock(); - } - return BluetoothStatusCodes.ERROR_UNKNOWN; - } - - /** - * Returns {@link BluetoothStatusCodes#SUCCESS} if LE Periodic Advertising Sync Transfer Sender - * feature is supported, returns {@link BluetoothStatusCodes#ERROR_FEATURE_NOT_SUPPORTED} if the - * feature is not supported or an error code - * - * @return whether the chipset supports the LE Periodic Advertising Sync Transfer Sender feature - */ - @RequiresNoPermission - public @LeFeatureReturnValues int isLePeriodicAdvertisingSyncTransferSenderSupported() { - if (!getLeAccess()) { - return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED; - } - try { - mServiceLock.readLock().lock(); - if (mService != null) { - return mService.isLePeriodicAdvertisingSyncTransferSenderSupported(); - } - } catch (RemoteException e) { - e.rethrowFromSystemServer(); - } finally { - mServiceLock.readLock().unlock(); - } - return BluetoothStatusCodes.ERROR_UNKNOWN; - } - - /** - * Return the maximum LE advertising data length in bytes, - * if LE Extended Advertising feature is supported, 0 otherwise. - * - * @return the maximum LE advertising data length. - */ - @RequiresLegacyBluetoothPermission - @RequiresNoPermission - public int getLeMaximumAdvertisingDataLength() { - if (!getLeAccess()) { - return 0; - } - try { - mServiceLock.readLock().lock(); - if (mService != null) { - return mService.getLeMaximumAdvertisingDataLength(); - } - } catch (RemoteException e) { - Log.e(TAG, "failed to get getLeMaximumAdvertisingDataLength, error: ", e); - } finally { - mServiceLock.readLock().unlock(); - } - return 0; - } - - /** - * Return true if Hearing Aid Profile is supported. - * - * @return true if phone supports Hearing Aid Profile - */ - @RequiresNoPermission - private boolean isHearingAidProfileSupported() { - try { - return mManagerService.isHearingAidProfileSupported(); - } catch (RemoteException e) { - Log.e(TAG, "remote exception when calling isHearingAidProfileSupported", e); - return false; - } - } - - /** - * Get the maximum number of connected audio devices. - * - * @return the maximum number of connected audio devices - * @hide - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public int getMaxConnectedAudioDevices() { - try { - mServiceLock.readLock().lock(); - if (mService != null) { - return mService.getMaxConnectedAudioDevices(mAttributionSource); - } - } catch (RemoteException e) { - Log.e(TAG, "failed to get getMaxConnectedAudioDevices, error: ", e); - } finally { - mServiceLock.readLock().unlock(); - } - return 1; - } - - /** - * Return true if hardware has entries available for matching beacons - * - * @return true if there are hw entries available for matching beacons - * @hide - */ - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public boolean isHardwareTrackingFiltersAvailable() { - if (!getLeAccess()) { - return false; - } - try { - IBluetoothGatt iGatt = mManagerService.getBluetoothGatt(); - if (iGatt == null) { - // BLE is not supported - return false; - } - return (iGatt.numHwTrackFiltersAvailable(mAttributionSource) != 0); - } catch (RemoteException e) { - Log.e(TAG, "", e); - } - return false; - } - - /** - * Request the record of {@link BluetoothActivityEnergyInfo} object that - * has the activity and energy info. This can be used to ascertain what - * the controller has been up to, since the last sample. - * - * A null value for the activity info object may be sent if the bluetooth service is - * unreachable or the device does not support reporting such information. - * - * @param result The callback to which to send the activity info. - * @hide - */ - @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) - public void requestControllerActivityEnergyInfo(ResultReceiver result) { - try { - mServiceLock.readLock().lock(); - if (mService != null) { - mService.requestActivityInfo(result, mAttributionSource); - result = null; - } - } catch (RemoteException e) { - Log.e(TAG, "getControllerActivityEnergyInfoCallback: " + e); - } finally { - mServiceLock.readLock().unlock(); - if (result != null) { - // Only send an immediate result if we failed. - result.send(0, null); - } - } - } - - /** - * Fetches a list of the most recently connected bluetooth devices ordered by how recently they - * were connected with most recently first and least recently last - * - * @return {@link List} of bonded {@link BluetoothDevice} ordered by how recently they were - * connected - * - * @hide - */ - @RequiresLegacyBluetoothAdminPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public @NonNull List getMostRecentlyConnectedDevices() { - if (getState() != STATE_ON) { - return new ArrayList<>(); - } - try { - mServiceLock.readLock().lock(); - if (mService != null) { - return Attributable.setAttributionSource( - mService.getMostRecentlyConnectedDevices(mAttributionSource), - mAttributionSource); - } - } catch (RemoteException e) { - Log.e(TAG, "", e); - } finally { - mServiceLock.readLock().unlock(); - } - return new ArrayList<>(); - } - - /** - * Return the set of {@link BluetoothDevice} objects that are bonded - * (paired) to the local adapter. - *

If Bluetooth state is not {@link #STATE_ON}, this API - * will return an empty set. After turning on Bluetooth, - * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON} - * to get the updated value. - * - * @return unmodifiable set of {@link BluetoothDevice}, or null on error - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public Set getBondedDevices() { - if (getState() != STATE_ON) { - return toDeviceSet(Arrays.asList()); - } - try { - mServiceLock.readLock().lock(); - if (mService != null) { - return toDeviceSet(Attributable.setAttributionSource( - Arrays.asList(mService.getBondedDevices(mAttributionSource)), - mAttributionSource)); - } - return toDeviceSet(Arrays.asList()); - } catch (RemoteException e) { - Log.e(TAG, "", e); - } finally { - mServiceLock.readLock().unlock(); - } - return null; - } - - /** - * Gets the currently supported profiles by the adapter. - * - *

This can be used to check whether a profile is supported before attempting - * to connect to its respective proxy. - * - * @return a list of integers indicating the ids of supported profiles as defined in {@link - * BluetoothProfile}. - * @hide - */ - @RequiresNoPermission - public @NonNull List getSupportedProfiles() { - final ArrayList supportedProfiles = new ArrayList(); - - try { - synchronized (mManagerCallback) { - if (mService != null) { - final long supportedProfilesBitMask = mService.getSupportedProfiles(); - - for (int i = 0; i <= BluetoothProfile.MAX_PROFILE_ID; i++) { - if ((supportedProfilesBitMask & (1 << i)) != 0) { - supportedProfiles.add(i); - } - } - } else { - // Bluetooth is disabled. Just fill in known supported Profiles - if (isHearingAidProfileSupported()) { - supportedProfiles.add(BluetoothProfile.HEARING_AID); - } - } - } - } catch (RemoteException e) { - Log.e(TAG, "getSupportedProfiles:", e); - } - return supportedProfiles; - } - - /* - private static final String BLUETOOTH_GET_ADAPTER_CONNECTION_STATE_CACHE_PROPERTY = - "cache_key.bluetooth.get_adapter_connection_state"; - private final PropertyInvalidatedCache - mBluetoothGetAdapterConnectionStateCache = - new PropertyInvalidatedCache ( - 8, BLUETOOTH_GET_ADAPTER_CONNECTION_STATE_CACHE_PROPERTY) { - @Override - @SuppressLint("AndroidFrameworkRequiresPermission") - protected Integer recompute(Void query) { - try { - return mService.getAdapterConnectionState(); - } catch (RemoteException e) { - throw e.rethrowAsRuntimeException(); - } - } - }; - */ - - /** @hide */ - /* - @RequiresNoPermission - public void disableGetAdapterConnectionStateCache() { - mBluetoothGetAdapterConnectionStateCache.disableLocal(); - } - */ - - /** @hide */ - /* - public static void invalidateGetAdapterConnectionStateCache() { - PropertyInvalidatedCache.invalidateCache( - BLUETOOTH_GET_ADAPTER_CONNECTION_STATE_CACHE_PROPERTY); - } - */ - - /** - * Get the current connection state of the local Bluetooth adapter. - * This can be used to check whether the local Bluetooth adapter is connected - * to any profile of any other remote Bluetooth Device. - * - *

Use this function along with {@link #ACTION_CONNECTION_STATE_CHANGED} - * intent to get the connection state of the adapter. - * - * @return One of {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTED}, {@link - * #STATE_CONNECTING} or {@link #STATE_DISCONNECTED} - * @hide - */ - @UnsupportedAppUsage - @RequiresLegacyBluetoothPermission - @RequiresNoPermission - public int getConnectionState() { - if (getState() != STATE_ON) { - return BluetoothAdapter.STATE_DISCONNECTED; - } - try { - mServiceLock.readLock().lock(); - if (mService != null) { - return mService.getAdapterConnectionState(); - } - //return mBluetoothGetAdapterConnectionStateCache.query(null); - } catch (RemoteException e) { - Log.e(TAG, "failed to getConnectionState, error: ", e); - } finally { - mServiceLock.readLock().unlock(); - } - return BluetoothAdapter.STATE_DISCONNECTED; - } - - /* - private static final String BLUETOOTH_PROFILE_CACHE_PROPERTY = - "cache_key.bluetooth.get_profile_connection_state"; - private final PropertyInvalidatedCache - mGetProfileConnectionStateCache = - new PropertyInvalidatedCache( - 8, BLUETOOTH_PROFILE_CACHE_PROPERTY) { - @Override - @SuppressLint("AndroidFrameworkRequiresPermission") - protected Integer recompute(Integer query) { - try { - mServiceLock.readLock().lock(); - if (mService != null) { - return mService.getProfileConnectionState(query); - } - } catch (RemoteException e) { - Log.e(TAG, "getProfileConnectionState:", e); - } finally { - mServiceLock.readLock().unlock(); - } - return BluetoothProfile.STATE_DISCONNECTED; - } - @Override - public String queryToString(Integer query) { - return String.format("getProfileConnectionState(profile=\"%d\")", - query); - } - }; - */ - - /** @hide */ - /* - @RequiresNoPermission - public void disableGetProfileConnectionStateCache() { - mGetProfileConnectionStateCache.disableLocal(); - } - */ - - /** @hide */ - /* - public static void invalidateGetProfileConnectionStateCache() { - PropertyInvalidatedCache.invalidateCache(BLUETOOTH_PROFILE_CACHE_PROPERTY); - } - */ - - /** - * Get the current connection state of a profile. - * This function can be used to check whether the local Bluetooth adapter - * is connected to any remote device for a specific profile. - * Profile can be one of {@link BluetoothProfile#HEADSET}, {@link BluetoothProfile#A2DP}. - * - *

Return value can be one of - * {@link BluetoothProfile#STATE_DISCONNECTED}, - * {@link BluetoothProfile#STATE_CONNECTING}, - * {@link BluetoothProfile#STATE_CONNECTED}, - * {@link BluetoothProfile#STATE_DISCONNECTING} - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - @SuppressLint("AndroidFrameworkRequiresPermission") - public int getProfileConnectionState(int profile) { - if (getState() != STATE_ON) { - return BluetoothProfile.STATE_DISCONNECTED; - } - try { - mServiceLock.readLock().lock(); - if (mService != null) { - mService.getProfileConnectionState(profile); - } - //return mGetProfileConnectionStateCache.query(new Integer(profile)); - } catch (RemoteException e) { - Log.e(TAG, "failed to getProfileConnectionState, error: ", e); - } finally { - mServiceLock.readLock().unlock(); - } - return BluetoothProfile.STATE_DISCONNECTED; - } - - /** - * Create a listening, secure RFCOMM Bluetooth socket. - *

A remote device connecting to this socket will be authenticated and - * communication on this socket will be encrypted. - *

Use {@link BluetoothServerSocket#accept} to retrieve incoming - * connections from a listening {@link BluetoothServerSocket}. - *

Valid RFCOMM channels are in range 1 to 30. - * - * @param channel RFCOMM channel to listen on - * @return a listening RFCOMM BluetoothServerSocket - * @throws IOException on error, for example Bluetooth not available, or insufficient - * permissions, or channel in use. - * @hide - */ - @RequiresLegacyBluetoothAdminPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public BluetoothServerSocket listenUsingRfcommOn(int channel) throws IOException { - return listenUsingRfcommOn(channel, false, false); - } - - /** - * Create a listening, secure RFCOMM Bluetooth socket. - *

A remote device connecting to this socket will be authenticated and - * communication on this socket will be encrypted. - *

Use {@link BluetoothServerSocket#accept} to retrieve incoming - * connections from a listening {@link BluetoothServerSocket}. - *

Valid RFCOMM channels are in range 1 to 30. - *

To auto assign a channel without creating a SDP record use - * {@link #SOCKET_CHANNEL_AUTO_STATIC_NO_SDP} as channel number. - * - * @param channel RFCOMM channel to listen on - * @param mitm enforce person-in-the-middle protection for authentication. - * @param min16DigitPin enforce a pin key length og minimum 16 digit for sec mode 2 - * connections. - * @return a listening RFCOMM BluetoothServerSocket - * @throws IOException on error, for example Bluetooth not available, or insufficient - * permissions, or channel in use. - * @hide - */ - @UnsupportedAppUsage - @RequiresLegacyBluetoothAdminPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public BluetoothServerSocket listenUsingRfcommOn(int channel, boolean mitm, - boolean min16DigitPin) throws IOException { - BluetoothServerSocket socket = - new BluetoothServerSocket(BluetoothSocket.TYPE_RFCOMM, true, true, channel, mitm, - min16DigitPin); - int errno = socket.mSocket.bindListen(); - if (channel == SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) { - socket.setChannel(socket.mSocket.getPort()); - } - if (errno != 0) { - //TODO(BT): Throw the same exception error code - // that the previous code was using. - //socket.mSocket.throwErrnoNative(errno); - throw new IOException("Error: " + errno); - } - return socket; - } - - /** - * Create a listening, secure RFCOMM Bluetooth socket with Service Record. - *

A remote device connecting to this socket will be authenticated and - * communication on this socket will be encrypted. - *

Use {@link BluetoothServerSocket#accept} to retrieve incoming - * connections from a listening {@link BluetoothServerSocket}. - *

The system will assign an unused RFCOMM channel to listen on. - *

The system will also register a Service Discovery - * Protocol (SDP) record with the local SDP server containing the specified - * UUID, service name, and auto-assigned channel. Remote Bluetooth devices - * can use the same UUID to query our SDP server and discover which channel - * to connect to. This SDP record will be removed when this socket is - * closed, or if this application closes unexpectedly. - *

Use {@link BluetoothDevice#createRfcommSocketToServiceRecord} to - * connect to this socket from another device using the same {@link UUID}. - * - * @param name service name for SDP record - * @param uuid uuid for SDP record - * @return a listening RFCOMM BluetoothServerSocket - * @throws IOException on error, for example Bluetooth not available, or insufficient - * permissions, or channel in use. - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public BluetoothServerSocket listenUsingRfcommWithServiceRecord(String name, UUID uuid) - throws IOException { - return createNewRfcommSocketAndRecord(name, uuid, true, true); - } - - /** - * Create a listening, insecure RFCOMM Bluetooth socket with Service Record. - *

The link key is not required to be authenticated, i.e the communication may be - * vulnerable to Person In the Middle attacks. For Bluetooth 2.1 devices, - * the link will be encrypted, as encryption is mandatory. - * For legacy devices (pre Bluetooth 2.1 devices) the link will not - * be encrypted. Use {@link #listenUsingRfcommWithServiceRecord}, if an - * encrypted and authenticated communication channel is desired. - *

Use {@link BluetoothServerSocket#accept} to retrieve incoming - * connections from a listening {@link BluetoothServerSocket}. - *

The system will assign an unused RFCOMM channel to listen on. - *

The system will also register a Service Discovery - * Protocol (SDP) record with the local SDP server containing the specified - * UUID, service name, and auto-assigned channel. Remote Bluetooth devices - * can use the same UUID to query our SDP server and discover which channel - * to connect to. This SDP record will be removed when this socket is - * closed, or if this application closes unexpectedly. - *

Use {@link BluetoothDevice#createRfcommSocketToServiceRecord} to - * connect to this socket from another device using the same {@link UUID}. - * - * @param name service name for SDP record - * @param uuid uuid for SDP record - * @return a listening RFCOMM BluetoothServerSocket - * @throws IOException on error, for example Bluetooth not available, or insufficient - * permissions, or channel in use. - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public BluetoothServerSocket listenUsingInsecureRfcommWithServiceRecord(String name, UUID uuid) - throws IOException { - return createNewRfcommSocketAndRecord(name, uuid, false, false); - } - - /** - * Create a listening, encrypted, - * RFCOMM Bluetooth socket with Service Record. - *

The link will be encrypted, but the link key is not required to be authenticated - * i.e the communication is vulnerable to Person In the Middle attacks. Use - * {@link #listenUsingRfcommWithServiceRecord}, to ensure an authenticated link key. - *

Use this socket if authentication of link key is not possible. - * For example, for Bluetooth 2.1 devices, if any of the devices does not have - * an input and output capability or just has the ability to display a numeric key, - * a secure socket connection is not possible and this socket can be used. - * Use {@link #listenUsingInsecureRfcommWithServiceRecord}, if encryption is not required. - * For Bluetooth 2.1 devices, the link will be encrypted, as encryption is mandatory. - * For more details, refer to the Security Model section 5.2 (vol 3) of - * Bluetooth Core Specification version 2.1 + EDR. - *

Use {@link BluetoothServerSocket#accept} to retrieve incoming - * connections from a listening {@link BluetoothServerSocket}. - *

The system will assign an unused RFCOMM channel to listen on. - *

The system will also register a Service Discovery - * Protocol (SDP) record with the local SDP server containing the specified - * UUID, service name, and auto-assigned channel. Remote Bluetooth devices - * can use the same UUID to query our SDP server and discover which channel - * to connect to. This SDP record will be removed when this socket is - * closed, or if this application closes unexpectedly. - *

Use {@link BluetoothDevice#createRfcommSocketToServiceRecord} to - * connect to this socket from another device using the same {@link UUID}. - * - * @param name service name for SDP record - * @param uuid uuid for SDP record - * @return a listening RFCOMM BluetoothServerSocket - * @throws IOException on error, for example Bluetooth not available, or insufficient - * permissions, or channel in use. - * @hide - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public BluetoothServerSocket listenUsingEncryptedRfcommWithServiceRecord(String name, UUID uuid) - throws IOException { - 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 { - BluetoothServerSocket socket; - socket = new BluetoothServerSocket(BluetoothSocket.TYPE_RFCOMM, auth, encrypt, - new ParcelUuid(uuid)); - socket.setServiceName(name); - int errno = socket.mSocket.bindListen(); - if (errno != 0) { - //TODO(BT): Throw the same exception error code - // that the previous code was using. - //socket.mSocket.throwErrnoNative(errno); - throw new IOException("Error: " + errno); - } - return socket; - } - - /** - * Construct an unencrypted, unauthenticated, RFCOMM server socket. - * Call #accept to retrieve connections to this socket. - * - * @return An RFCOMM BluetoothServerSocket - * @throws IOException On error, for example Bluetooth not available, or insufficient - * permissions. - * @hide - */ - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public BluetoothServerSocket listenUsingInsecureRfcommOn(int port) throws IOException { - BluetoothServerSocket socket = - new BluetoothServerSocket(BluetoothSocket.TYPE_RFCOMM, false, false, port); - int errno = socket.mSocket.bindListen(); - if (port == SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) { - socket.setChannel(socket.mSocket.getPort()); - } - if (errno != 0) { - //TODO(BT): Throw the same exception error code - // that the previous code was using. - //socket.mSocket.throwErrnoNative(errno); - throw new IOException("Error: " + errno); - } - return socket; - } - - /** - * Construct an encrypted, authenticated, L2CAP server socket. - * Call #accept to retrieve connections to this socket. - *

To auto assign a port without creating a SDP record use - * {@link #SOCKET_CHANNEL_AUTO_STATIC_NO_SDP} as port number. - * - * @param port the PSM to listen on - * @param mitm enforce person-in-the-middle protection for authentication. - * @param min16DigitPin enforce a pin key length og minimum 16 digit for sec mode 2 - * connections. - * @return An L2CAP BluetoothServerSocket - * @throws IOException On error, for example Bluetooth not available, or insufficient - * permissions. - * @hide - */ - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public BluetoothServerSocket listenUsingL2capOn(int port, boolean mitm, boolean min16DigitPin) - throws IOException { - BluetoothServerSocket socket = - new BluetoothServerSocket(BluetoothSocket.TYPE_L2CAP, true, true, port, mitm, - min16DigitPin); - int errno = socket.mSocket.bindListen(); - if (port == SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) { - int assignedChannel = socket.mSocket.getPort(); - if (DBG) Log.d(TAG, "listenUsingL2capOn: set assigned channel to " + assignedChannel); - socket.setChannel(assignedChannel); - } - if (errno != 0) { - //TODO(BT): Throw the same exception error code - // that the previous code was using. - //socket.mSocket.throwErrnoNative(errno); - throw new IOException("Error: " + errno); - } - return socket; - } - - /** - * Construct an encrypted, authenticated, L2CAP server socket. - * Call #accept to retrieve connections to this socket. - *

To auto assign a port without creating a SDP record use - * {@link #SOCKET_CHANNEL_AUTO_STATIC_NO_SDP} as port number. - * - * @param port the PSM to listen on - * @return An L2CAP BluetoothServerSocket - * @throws IOException On error, for example Bluetooth not available, or insufficient - * permissions. - * @hide - */ - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public BluetoothServerSocket listenUsingL2capOn(int port) throws IOException { - return listenUsingL2capOn(port, false, false); - } - - /** - * Construct an insecure L2CAP server socket. - * Call #accept to retrieve connections to this socket. - *

To auto assign a port without creating a SDP record use - * {@link #SOCKET_CHANNEL_AUTO_STATIC_NO_SDP} as port number. - * - * @param port the PSM to listen on - * @return An L2CAP BluetoothServerSocket - * @throws IOException On error, for example Bluetooth not available, or insufficient - * permissions. - * @hide - */ - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public BluetoothServerSocket listenUsingInsecureL2capOn(int port) throws IOException { - Log.d(TAG, "listenUsingInsecureL2capOn: port=" + port); - BluetoothServerSocket socket = - new BluetoothServerSocket(BluetoothSocket.TYPE_L2CAP, false, false, port, false, - false); - int errno = socket.mSocket.bindListen(); - if (port == SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) { - int assignedChannel = socket.mSocket.getPort(); - if (DBG) { - Log.d(TAG, "listenUsingInsecureL2capOn: set assigned channel to " - + assignedChannel); - } - socket.setChannel(assignedChannel); - } - if (errno != 0) { - //TODO(BT): Throw the same exception error code - // that the previous code was using. - //socket.mSocket.throwErrnoNative(errno); - throw new IOException("Error: " + errno); - } - return socket; - - } - - /** - * Read the local Out of Band Pairing Data - * - * @return Pair of Hash and Randomizer - * @hide - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - @SuppressLint("AndroidFrameworkRequiresPermission") - public Pair readOutOfBandData() { - return null; - } - - /** - * Get the profile proxy object associated with the profile. - * - *

Profile can be one of {@link BluetoothProfile#HEADSET}, {@link BluetoothProfile#A2DP}, - * {@link BluetoothProfile#GATT}, {@link BluetoothProfile#HEARING_AID}, or {@link - * BluetoothProfile#GATT_SERVER}. Clients must implement {@link - * BluetoothProfile.ServiceListener} to get notified of the connection status and to get the - * proxy object. - * - * @param context Context of the application - * @param listener The service Listener for connection callbacks. - * @param profile The Bluetooth profile; either {@link BluetoothProfile#HEADSET}, - * {@link BluetoothProfile#A2DP}, {@link BluetoothProfile#GATT}, {@link - * 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) { - return false; - } - - if (profile == BluetoothProfile.HEADSET) { - BluetoothHeadset headset = new BluetoothHeadset(context, listener, this); - return true; - } else if (profile == BluetoothProfile.A2DP) { - BluetoothA2dp a2dp = new BluetoothA2dp(context, listener, this); - return true; - } else if (profile == BluetoothProfile.A2DP_SINK) { - BluetoothA2dpSink a2dpSink = new BluetoothA2dpSink(context, listener, this); - return true; - } else if (profile == BluetoothProfile.AVRCP_CONTROLLER) { - BluetoothAvrcpController avrcp = new BluetoothAvrcpController(context, listener, this); - return true; - } else if (profile == BluetoothProfile.HID_HOST) { - BluetoothHidHost iDev = new BluetoothHidHost(context, listener, this); - return true; - } else if (profile == BluetoothProfile.PAN) { - BluetoothPan pan = new BluetoothPan(context, listener, this); - return true; - } else if (profile == BluetoothProfile.PBAP) { - BluetoothPbap pbap = new BluetoothPbap(context, listener, this); - return true; - } else if (profile == BluetoothProfile.HEALTH) { - Log.e(TAG, "getProfileProxy(): BluetoothHealth is deprecated"); - return false; - } else if (profile == BluetoothProfile.MAP) { - BluetoothMap map = new BluetoothMap(context, listener, this); - return true; - } else if (profile == BluetoothProfile.HEADSET_CLIENT) { - BluetoothHeadsetClient headsetClient = - new BluetoothHeadsetClient(context, listener, this); - return true; - } else if (profile == BluetoothProfile.SAP) { - BluetoothSap sap = new BluetoothSap(context, listener, this); - return true; - } else if (profile == BluetoothProfile.PBAP_CLIENT) { - BluetoothPbapClient pbapClient = new BluetoothPbapClient(context, listener, this); - return true; - } else if (profile == BluetoothProfile.MAP_CLIENT) { - BluetoothMapClient mapClient = new BluetoothMapClient(context, listener, this); - return true; - } else if (profile == BluetoothProfile.HID_DEVICE) { - BluetoothHidDevice hidDevice = new BluetoothHidDevice(context, listener, this); - return true; - } else if (profile == BluetoothProfile.HEARING_AID) { - if (isHearingAidProfileSupported()) { - BluetoothHearingAid hearingAid = new BluetoothHearingAid(context, listener, this); - return true; - } - return false; - } else if (profile == BluetoothProfile.LE_AUDIO) { - BluetoothLeAudio leAudio = new BluetoothLeAudio(context, listener, this); - return true; - } else if (profile == BluetoothProfile.VOLUME_CONTROL) { - BluetoothVolumeControl vcs = new BluetoothVolumeControl(context, listener, this); - return true; - } else if (profile == BluetoothProfile.CSIP_SET_COORDINATOR) { - BluetoothCsipSetCoordinator csipSetCoordinator = - new BluetoothCsipSetCoordinator(context, listener, this); - return true; - } else if (profile == BluetoothProfile.LE_CALL_CONTROL) { - BluetoothLeCallControl tbs = new BluetoothLeCallControl(context, listener); - return true; - } else { - return false; - } - } - - /** - * Close the connection of the profile proxy to the Service. - * - *

Clients should call this when they are no longer using - * the proxy obtained from {@link #getProfileProxy}. - * Profile can be one of {@link BluetoothProfile#HEADSET} or {@link BluetoothProfile#A2DP} - * - * @param profile - * @param proxy Profile proxy object - */ - @SuppressLint({ - "AndroidFrameworkRequiresPermission", - "AndroidFrameworkBluetoothPermission" - }) - public void closeProfileProxy(int profile, BluetoothProfile proxy) { - if (proxy == null) { - return; - } - - switch (profile) { - case BluetoothProfile.HEADSET: - BluetoothHeadset headset = (BluetoothHeadset) proxy; - headset.close(); - break; - case BluetoothProfile.A2DP: - BluetoothA2dp a2dp = (BluetoothA2dp) proxy; - a2dp.close(); - break; - case BluetoothProfile.A2DP_SINK: - BluetoothA2dpSink a2dpSink = (BluetoothA2dpSink) proxy; - a2dpSink.close(); - break; - case BluetoothProfile.AVRCP_CONTROLLER: - BluetoothAvrcpController avrcp = (BluetoothAvrcpController) proxy; - avrcp.close(); - break; - case BluetoothProfile.HID_HOST: - BluetoothHidHost iDev = (BluetoothHidHost) proxy; - iDev.close(); - break; - case BluetoothProfile.PAN: - BluetoothPan pan = (BluetoothPan) proxy; - pan.close(); - break; - case BluetoothProfile.PBAP: - BluetoothPbap pbap = (BluetoothPbap) proxy; - pbap.close(); - break; - case BluetoothProfile.GATT: - BluetoothGatt gatt = (BluetoothGatt) proxy; - gatt.close(); - break; - case BluetoothProfile.GATT_SERVER: - BluetoothGattServer gattServer = (BluetoothGattServer) proxy; - gattServer.close(); - break; - case BluetoothProfile.MAP: - BluetoothMap map = (BluetoothMap) proxy; - map.close(); - break; - case BluetoothProfile.HEADSET_CLIENT: - BluetoothHeadsetClient headsetClient = (BluetoothHeadsetClient) proxy; - headsetClient.close(); - break; - case BluetoothProfile.SAP: - BluetoothSap sap = (BluetoothSap) proxy; - sap.close(); - break; - case BluetoothProfile.PBAP_CLIENT: - BluetoothPbapClient pbapClient = (BluetoothPbapClient) proxy; - pbapClient.close(); - break; - case BluetoothProfile.MAP_CLIENT: - BluetoothMapClient mapClient = (BluetoothMapClient) proxy; - mapClient.close(); - break; - case BluetoothProfile.HID_DEVICE: - BluetoothHidDevice hidDevice = (BluetoothHidDevice) proxy; - hidDevice.close(); - break; - case BluetoothProfile.HEARING_AID: - BluetoothHearingAid hearingAid = (BluetoothHearingAid) proxy; - hearingAid.close(); - break; - case BluetoothProfile.LE_AUDIO: - BluetoothLeAudio leAudio = (BluetoothLeAudio) proxy; - leAudio.close(); - break; - case BluetoothProfile.VOLUME_CONTROL: - BluetoothVolumeControl vcs = (BluetoothVolumeControl) proxy; - vcs.close(); - break; - case BluetoothProfile.CSIP_SET_COORDINATOR: - BluetoothCsipSetCoordinator csipSetCoordinator = - (BluetoothCsipSetCoordinator) proxy; - csipSetCoordinator.close(); - break; - case BluetoothProfile.LE_CALL_CONTROL: - BluetoothLeCallControl tbs = (BluetoothLeCallControl) proxy; - tbs.close(); - break; - } - } - - private static final IBluetoothManagerCallback sManagerCallback = - new IBluetoothManagerCallback.Stub() { - public void onBluetoothServiceUp(IBluetooth bluetoothService) { - if (DBG) { - Log.d(TAG, "onBluetoothServiceUp: " + bluetoothService); - } - - synchronized (sServiceLock) { - sService = bluetoothService; - for (IBluetoothManagerCallback cb : sProxyServiceStateCallbacks.keySet()) { - try { - if (cb != null) { - cb.onBluetoothServiceUp(bluetoothService); - } else { - Log.d(TAG, "onBluetoothServiceUp: cb is null!"); - } - } catch (Exception e) { - Log.e(TAG, "", e); - } - } - } - } - - public void onBluetoothServiceDown() { - if (DBG) { - Log.d(TAG, "onBluetoothServiceDown"); - } - - synchronized (sServiceLock) { - sService = null; - for (IBluetoothManagerCallback cb : sProxyServiceStateCallbacks.keySet()) { - try { - if (cb != null) { - cb.onBluetoothServiceDown(); - } else { - Log.d(TAG, "onBluetoothServiceDown: cb is null!"); - } - } catch (Exception e) { - Log.e(TAG, "", e); - } - } - } - } - - public void onBrEdrDown() { - if (VDBG) { - Log.i(TAG, "onBrEdrDown"); - } - - synchronized (sServiceLock) { - for (IBluetoothManagerCallback cb : sProxyServiceStateCallbacks.keySet()) { - try { - if (cb != null) { - cb.onBrEdrDown(); - } else { - Log.d(TAG, "onBrEdrDown: cb is null!"); - } - } catch (Exception e) { - Log.e(TAG, "", e); - } - } - } - } - }; - - private final IBluetoothManagerCallback mManagerCallback = - new IBluetoothManagerCallback.Stub() { - public void onBluetoothServiceUp(IBluetooth bluetoothService) { - synchronized (mServiceLock.writeLock()) { - mService = bluetoothService; - } - synchronized (mMetadataListeners) { - mMetadataListeners.forEach((device, pair) -> { - try { - mService.registerMetadataListener(mBluetoothMetadataListener, - device, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "Failed to register metadata listener", e); - } - }); - } - synchronized (mBluetoothConnectionCallbackExecutorMap) { - if (!mBluetoothConnectionCallbackExecutorMap.isEmpty()) { - try { - mService.registerBluetoothConnectionCallback(mConnectionCallback, - mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "onBluetoothServiceUp: Failed to register bluetooth" - + "connection callback", e); - } - } - } - } - - public void onBluetoothServiceDown() { - synchronized (mServiceLock.writeLock()) { - mService = null; - if (mLeScanClients != null) { - mLeScanClients.clear(); - } - if (mBluetoothLeAdvertiser != null) { - mBluetoothLeAdvertiser.cleanup(); - } - if (mBluetoothLeScanner != null) { - mBluetoothLeScanner.cleanup(); - } - } - } - - public void onBrEdrDown() { - } - }; - - /** - * Enable the Bluetooth Adapter, but don't auto-connect devices - * and don't persist state. Only for use by system applications. - * - * @hide - */ - @SystemApi - @RequiresLegacyBluetoothAdminPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public boolean enableNoAutoConnect() { - if (isEnabled()) { - if (DBG) { - Log.d(TAG, "enableNoAutoConnect(): BT already enabled!"); - } - return true; - } - try { - return mManagerService.enableNoAutoConnect(mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "", e); - } - return false; - } - - /** @hide */ - @Retention(RetentionPolicy.SOURCE) - @IntDef(value = { - BluetoothStatusCodes.ERROR_UNKNOWN, - BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED, - BluetoothStatusCodes.ERROR_ANOTHER_ACTIVE_OOB_REQUEST, - }) - public @interface OobError {} - - /** - * Provides callback methods for receiving {@link OobData} from the host stack, as well as an - * error interface in order to allow the caller to determine next steps based on the {@code - * ErrorCode}. - * - * @hide - */ - @SystemApi - public interface OobDataCallback { - /** - * Handles the {@link OobData} received from the host stack. - * - * @param transport - whether the {@link OobData} is generated for LE or Classic. - * @param oobData - data generated in the host stack(LE) or controller (Classic) - */ - void onOobData(@Transport int transport, @NonNull OobData oobData); - - /** - * Provides feedback when things don't go as expected. - * - * @param errorCode - the code describing the type of error that occurred. - */ - void onError(@OobError int errorCode); - } - - /** - * Wraps an AIDL interface around an {@link OobDataCallback} interface. - * - * @see {@link IBluetoothOobDataCallback} for interface definition. - * - * @hide - */ - public class WrappedOobDataCallback extends IBluetoothOobDataCallback.Stub { - private final OobDataCallback mCallback; - private final Executor mExecutor; - - /** - * @param callback - object to receive {@link OobData} must be a non null argument - * - * @throws NullPointerException if the callback is null. - */ - WrappedOobDataCallback(@NonNull OobDataCallback callback, - @NonNull @CallbackExecutor Executor executor) { - requireNonNull(callback); - requireNonNull(executor); - mCallback = callback; - mExecutor = executor; - } - /** - * Wrapper function to relay to the {@link OobDataCallback#onOobData} - * - * @param transport - whether the {@link OobData} is generated for LE or Classic. - * @param oobData - data generated in the host stack(LE) or controller (Classic) - * - * @hide - */ - public void onOobData(@Transport int transport, @NonNull OobData oobData) { - mExecutor.execute(new Runnable() { - public void run() { - mCallback.onOobData(transport, oobData); - } - }); - } - /** - * Wrapper function to relay to the {@link OobDataCallback#onError} - * - * @param errorCode - the code descibing the type of error that occurred. - * - * @hide - */ - public void onError(@OobError int errorCode) { - mExecutor.execute(new Runnable() { - public void run() { - mCallback.onError(errorCode); - } - }); - } - } - - /** - * Fetches a secret data value that can be used for a secure and simple pairing experience. - * - *

This is the Local Out of Band data the comes from the - * - *

This secret is the local Out of Band data. This data is used to securely and quickly - * pair two devices with minimal user interaction. - * - *

For example, this secret can be transferred to a remote device out of band (meaning any - * other way besides using bluetooth). Once the remote device finds this device using the - * information given in the data, such as the PUBLIC ADDRESS, the remote device could then - * connect to this device using this secret when the pairing sequenece asks for the secret. - * This device will respond by automatically accepting the pairing due to the secret being so - * trustworthy. - * - * @param transport - provide type of transport (e.g. LE or Classic). - * @param callback - target object to receive the {@link OobData} value. - * - * @throws NullPointerException if callback is null. - * @throws IllegalArgumentException if the transport is not valid. - * - * @hide - */ - @SystemApi - @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) - public void generateLocalOobData(@Transport int transport, - @NonNull @CallbackExecutor Executor executor, @NonNull OobDataCallback callback) { - if (transport != BluetoothDevice.TRANSPORT_BREDR && transport - != BluetoothDevice.TRANSPORT_LE) { - throw new IllegalArgumentException("Invalid transport '" + transport + "'!"); - } - requireNonNull(callback); - if (!isEnabled()) { - Log.w(TAG, "generateLocalOobData(): Adapter isn't enabled!"); - callback.onError(BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED); - } else { - try { - mService.generateLocalOobData(transport, new WrappedOobDataCallback(callback, - executor), mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "", e); - } - } - } - - /** - * Enable control of the Bluetooth Adapter for a single application. - * - *

Some applications need to use Bluetooth for short periods of time to - * transfer data but don't want all the associated implications like - * automatic connection to headsets etc. - * - *

Multiple applications can call this. This is reference counted and - * Bluetooth disabled only when no one else is using it. There will be no UI - * shown to the user while bluetooth is being enabled. Any user action will - * override this call. For example, if user wants Bluetooth on and the last - * user of this API wanted to disable Bluetooth, Bluetooth will not be - * turned off. - * - *

This API is only meant to be used by internal applications. Third - * party applications but use {@link #enable} and {@link #disable} APIs. - * - *

If this API returns true, it means the callback will be called. - * The callback will be called with the current state of Bluetooth. - * If the state is not what was requested, an internal error would be the - * reason. If Bluetooth is already on and if this function is called to turn - * it on, the api will return true and a callback will be called. - * - * @param on True for on, false for off. - * @param callback The callback to notify changes to the state. - * @hide - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - @SuppressLint("AndroidFrameworkRequiresPermission") - public boolean changeApplicationBluetoothState(boolean on, - BluetoothStateChangeCallback callback) { - return false; - } - - /** - * @hide - */ - public interface BluetoothStateChangeCallback { - /** - * @hide - */ - void onBluetoothStateChange(boolean on); - } - - /** - * @hide - */ - public class StateChangeCallbackWrapper extends IBluetoothStateChangeCallback.Stub { - private BluetoothStateChangeCallback mCallback; - - StateChangeCallbackWrapper(BluetoothStateChangeCallback callback) { - mCallback = callback; - } - - @Override - public void onBluetoothStateChange(boolean on) { - mCallback.onBluetoothStateChange(on); - } - } - - private Set toDeviceSet(List devices) { - Set deviceSet = new HashSet(devices); - return Collections.unmodifiableSet(deviceSet); - } - - protected void finalize() throws Throwable { - try { - removeServiceStateCallback(mManagerCallback); - } finally { - super.finalize(); - } - } - - /** - * Validate a String Bluetooth address, such as "00:43:A8:23:10:F0" - *

Alphabetic characters must be uppercase to be valid. - * - * @param address Bluetooth address as string - * @return true if the address is valid, false otherwise - */ - public static boolean checkBluetoothAddress(String address) { - if (address == null || address.length() != ADDRESS_LENGTH) { - return false; - } - for (int i = 0; i < ADDRESS_LENGTH; i++) { - char c = address.charAt(i); - switch (i % 3) { - case 0: - case 1: - if ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F')) { - // hex character, OK - break; - } - return false; - case 2: - if (c == ':') { - break; // OK - } - return false; - } - } - return true; - } - - /** - * Determines whether a String Bluetooth address, such as "F0:43:A8:23:10:00" - * is a RANDOM STATIC address. - * - * RANDOM STATIC: (addr & 0xC0) == 0xC0 - * RANDOM RESOLVABLE: (addr & 0xC0) == 0x40 - * RANDOM non-RESOLVABLE: (addr & 0xC0) == 0x00 - * - * @param address Bluetooth address as string - * @return true if the 2 Most Significant Bits of the address equals 0xC0. - * - * @hide - */ - public static boolean isAddressRandomStatic(@NonNull String address) { - requireNonNull(address); - return checkBluetoothAddress(address) - && (Integer.parseInt(address.split(":")[0], 16) & 0xC0) == 0xC0; - } - - /** {@hide} */ - @UnsupportedAppUsage - @RequiresNoPermission - public IBluetoothManager getBluetoothManager() { - return mManagerService; - } - - /** {@hide} */ - @RequiresNoPermission - public AttributionSource getAttributionSource() { - return mAttributionSource; - } - - @GuardedBy("sServiceLock") - private static final WeakHashMap sProxyServiceStateCallbacks = - new WeakHashMap<>(); - - /*package*/ IBluetooth getBluetoothService() { - synchronized (sServiceLock) { - if (sProxyServiceStateCallbacks.isEmpty()) { - throw new IllegalStateException( - "Anonymous service access requires at least one lifecycle in process"); - } - return sService; - } - } - - @UnsupportedAppUsage - /*package*/ IBluetooth getBluetoothService(IBluetoothManagerCallback cb) { - Objects.requireNonNull(cb); - synchronized (sServiceLock) { - sProxyServiceStateCallbacks.put(cb, null); - registerOrUnregisterAdapterLocked(); - return sService; - } - } - - /*package*/ void removeServiceStateCallback(IBluetoothManagerCallback cb) { - Objects.requireNonNull(cb); - synchronized (sServiceLock) { - sProxyServiceStateCallbacks.remove(cb); - registerOrUnregisterAdapterLocked(); - } - } - - /** - * Handle registering (or unregistering) a single process-wide - * {@link IBluetoothManagerCallback} based on the presence of local - * {@link #sProxyServiceStateCallbacks} clients. - */ - @GuardedBy("sServiceLock") - private void registerOrUnregisterAdapterLocked() { - final boolean isRegistered = sServiceRegistered; - final boolean wantRegistered = !sProxyServiceStateCallbacks.isEmpty(); - - if (isRegistered != wantRegistered) { - if (wantRegistered) { - try { - sService = mManagerService.registerAdapter(sManagerCallback); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } else { - try { - mManagerService.unregisterAdapter(sManagerCallback); - sService = null; - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - sServiceRegistered = wantRegistered; - } - } - - /** - * Callback interface used to deliver LE scan results. - * - * @see #startLeScan(LeScanCallback) - * @see #startLeScan(UUID[], LeScanCallback) - */ - public interface LeScanCallback { - /** - * Callback reporting an LE device found during a device scan initiated - * by the {@link BluetoothAdapter#startLeScan} function. - * - * @param device Identifies the remote device - * @param rssi The RSSI value for the remote device as reported by the Bluetooth hardware. 0 - * if no RSSI value is available. - * @param scanRecord The content of the advertisement record offered by the remote device. - */ - void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord); - } - - /** - * Register a callback to receive events whenever the bluetooth stack goes down and back up, - * e.g. in the event the bluetooth is turned off/on via settings. - * - * If the bluetooth stack is currently up, there will not be an initial callback call. - * You can use the return value as an indication of this being the case. - * - * Callbacks will be delivered on a binder thread. - * - * @return whether bluetooth is already up currently - * - * @hide - */ - public boolean registerServiceLifecycleCallback(ServiceLifecycleCallback callback) { - return getBluetoothService(callback.mRemote) != null; - } - - /** - * Unregister a callback registered via {@link #registerServiceLifecycleCallback} - * - * @hide - */ - public void unregisterServiceLifecycleCallback(ServiceLifecycleCallback callback) { - removeServiceStateCallback(callback.mRemote); - } - - /** - * A callback for {@link #registerServiceLifecycleCallback} - * - * @hide - */ - public abstract static class ServiceLifecycleCallback { - - /** Called when the bluetooth stack is up */ - public abstract void onBluetoothServiceUp(); - - /** Called when the bluetooth stack is down */ - public abstract void onBluetoothServiceDown(); - - IBluetoothManagerCallback mRemote = new IBluetoothManagerCallback.Stub() { - @Override - public void onBluetoothServiceUp(IBluetooth bluetoothService) { - ServiceLifecycleCallback.this.onBluetoothServiceUp(); - } - - @Override - public void onBluetoothServiceDown() { - ServiceLifecycleCallback.this.onBluetoothServiceDown(); - } - - @Override - public void onBrEdrDown() {} - }; - } - - /** - * Starts a scan for Bluetooth LE devices. - * - *

Results of the scan are reported using the - * {@link LeScanCallback#onLeScan} callback. - * - * @param callback the callback LE scan results are delivered - * @return true, if the scan was started successfully - * @deprecated use {@link BluetoothLeScanner#startScan(List, ScanSettings, ScanCallback)} - * instead. - */ - @Deprecated - @RequiresLegacyBluetoothAdminPermission - @RequiresBluetoothScanPermission - @RequiresBluetoothLocationPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) - public boolean startLeScan(LeScanCallback callback) { - return startLeScan(null, callback); - } - - /** - * Starts a scan for Bluetooth LE devices, looking for devices that - * advertise given services. - * - *

Devices which advertise all specified services are reported using the - * {@link LeScanCallback#onLeScan} callback. - * - * @param serviceUuids Array of services to look for - * @param callback the callback LE scan results are delivered - * @return true, if the scan was started successfully - * @deprecated use {@link BluetoothLeScanner#startScan(List, ScanSettings, ScanCallback)} - * instead. - */ - @Deprecated - @RequiresLegacyBluetoothAdminPermission - @RequiresBluetoothScanPermission - @RequiresBluetoothLocationPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) - public boolean startLeScan(final UUID[] serviceUuids, final LeScanCallback callback) { - if (DBG) { - Log.d(TAG, "startLeScan(): " + Arrays.toString(serviceUuids)); - } - if (callback == null) { - if (DBG) { - Log.e(TAG, "startLeScan: null callback"); - } - return false; - } - BluetoothLeScanner scanner = getBluetoothLeScanner(); - if (scanner == null) { - if (DBG) { - Log.e(TAG, "startLeScan: cannot get BluetoothLeScanner"); - } - return false; - } - - synchronized (mLeScanClients) { - if (mLeScanClients.containsKey(callback)) { - if (DBG) { - Log.e(TAG, "LE Scan has already started"); - } - return false; - } - - try { - IBluetoothGatt iGatt = mManagerService.getBluetoothGatt(); - if (iGatt == null) { - // BLE is not supported - return false; - } - - @SuppressLint("AndroidFrameworkBluetoothPermission") - ScanCallback scanCallback = new ScanCallback() { - @Override - public void onScanResult(int callbackType, ScanResult result) { - if (callbackType != ScanSettings.CALLBACK_TYPE_ALL_MATCHES) { - // Should not happen. - Log.e(TAG, "LE Scan has already started"); - return; - } - ScanRecord scanRecord = result.getScanRecord(); - if (scanRecord == null) { - return; - } - if (serviceUuids != null) { - List uuids = new ArrayList(); - for (UUID uuid : serviceUuids) { - uuids.add(new ParcelUuid(uuid)); - } - List scanServiceUuids = scanRecord.getServiceUuids(); - if (scanServiceUuids == null || !scanServiceUuids.containsAll(uuids)) { - if (DBG) { - Log.d(TAG, "uuids does not match"); - } - return; - } - } - callback.onLeScan(result.getDevice(), result.getRssi(), - scanRecord.getBytes()); - } - }; - ScanSettings settings = new ScanSettings.Builder().setCallbackType( - ScanSettings.CALLBACK_TYPE_ALL_MATCHES) - .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY) - .build(); - - List filters = new ArrayList(); - if (serviceUuids != null && serviceUuids.length > 0) { - // Note scan filter does not support matching an UUID array so we put one - // UUID to hardware and match the whole array in callback. - ScanFilter filter = - new ScanFilter.Builder().setServiceUuid(new ParcelUuid(serviceUuids[0])) - .build(); - filters.add(filter); - } - scanner.startScan(filters, settings, scanCallback); - - mLeScanClients.put(callback, scanCallback); - return true; - - } catch (RemoteException e) { - Log.e(TAG, "", e); - } - } - return false; - } - - /** - * Stops an ongoing Bluetooth LE device scan. - * - * @param callback used to identify which scan to stop must be the same handle used to start the - * scan - * @deprecated Use {@link BluetoothLeScanner#stopScan(ScanCallback)} instead. - */ - @Deprecated - @RequiresLegacyBluetoothAdminPermission - @RequiresBluetoothScanPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) - public void stopLeScan(LeScanCallback callback) { - if (DBG) { - Log.d(TAG, "stopLeScan()"); - } - BluetoothLeScanner scanner = getBluetoothLeScanner(); - if (scanner == null) { - return; - } - synchronized (mLeScanClients) { - ScanCallback scanCallback = mLeScanClients.remove(callback); - if (scanCallback == null) { - if (DBG) { - Log.d(TAG, "scan not started yet"); - } - return; - } - scanner.stopScan(scanCallback); - } - } - - /** - * Create a secure L2CAP Connection-oriented Channel (CoC) {@link BluetoothServerSocket} and - * assign a dynamic protocol/service multiplexer (PSM) value. This socket can be used to listen - * for incoming connections. The supported Bluetooth transport is LE only. - *

A remote device connecting to this socket will be authenticated and communication on this - * socket will be encrypted. - *

Use {@link BluetoothServerSocket#accept} to retrieve incoming connections from a listening - * {@link BluetoothServerSocket}. - *

The system will assign a dynamic PSM value. This PSM value can be read from the {@link - * BluetoothServerSocket#getPsm()} and this value will be released when this server socket is - * closed, Bluetooth is turned off, or the application exits unexpectedly. - *

The mechanism of disclosing the assigned dynamic PSM value to the initiating peer is - * defined and performed by the application. - *

Use {@link BluetoothDevice#createL2capChannel(int)} to connect to this server - * socket from another Android device that is given the PSM value. - * - * @return an L2CAP CoC BluetoothServerSocket - * @throws IOException on error, for example Bluetooth not available, or insufficient - * permissions, or unable to start this CoC - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public @NonNull BluetoothServerSocket listenUsingL2capChannel() - throws IOException { - BluetoothServerSocket socket = - new BluetoothServerSocket(BluetoothSocket.TYPE_L2CAP_LE, true, true, - SOCKET_CHANNEL_AUTO_STATIC_NO_SDP, false, false); - int errno = socket.mSocket.bindListen(); - if (errno != 0) { - throw new IOException("Error: " + errno); - } - - int assignedPsm = socket.mSocket.getPort(); - if (assignedPsm == 0) { - throw new IOException("Error: Unable to assign PSM value"); - } - if (DBG) { - Log.d(TAG, "listenUsingL2capChannel: set assigned PSM to " - + assignedPsm); - } - socket.setChannel(assignedPsm); - - return socket; - } - - /** - * Create an insecure L2CAP Connection-oriented Channel (CoC) {@link BluetoothServerSocket} and - * assign a dynamic PSM value. This socket can be used to listen for incoming connections. The - * supported Bluetooth transport is LE only. - *

The link key is not required to be authenticated, i.e the communication may be vulnerable - * to person-in-the-middle attacks. Use {@link #listenUsingL2capChannel}, if an encrypted and - * authenticated communication channel is desired. - *

Use {@link BluetoothServerSocket#accept} to retrieve incoming connections from a listening - * {@link BluetoothServerSocket}. - *

The system will assign a dynamic protocol/service multiplexer (PSM) value. This PSM value - * can be read from the {@link BluetoothServerSocket#getPsm()} and this value will be released - * when this server socket is closed, Bluetooth is turned off, or the application exits - * unexpectedly. - *

The mechanism of disclosing the assigned dynamic PSM value to the initiating peer is - * defined and performed by the application. - *

Use {@link BluetoothDevice#createInsecureL2capChannel(int)} to connect to this server - * socket from another Android device that is given the PSM value. - * - * @return an L2CAP CoC BluetoothServerSocket - * @throws IOException on error, for example Bluetooth not available, or insufficient - * permissions, or unable to start this CoC - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public @NonNull BluetoothServerSocket listenUsingInsecureL2capChannel() - throws IOException { - BluetoothServerSocket socket = - new BluetoothServerSocket(BluetoothSocket.TYPE_L2CAP_LE, false, false, - SOCKET_CHANNEL_AUTO_STATIC_NO_SDP, false, false); - int errno = socket.mSocket.bindListen(); - if (errno != 0) { - throw new IOException("Error: " + errno); - } - - int assignedPsm = socket.mSocket.getPort(); - if (assignedPsm == 0) { - throw new IOException("Error: Unable to assign PSM value"); - } - if (DBG) { - Log.d(TAG, "listenUsingInsecureL2capChannel: set assigned PSM to " - + assignedPsm); - } - socket.setChannel(assignedPsm); - - return socket; - } - - /** - * Register a {@link #OnMetadataChangedListener} to receive update about metadata - * changes for this {@link BluetoothDevice}. - * Registration must be done when Bluetooth is ON and will last until - * {@link #removeOnMetadataChangedListener(BluetoothDevice)} is called, even when Bluetooth - * restarted in the middle. - * All input parameters should not be null or {@link NullPointerException} will be triggered. - * The same {@link BluetoothDevice} and {@link #OnMetadataChangedListener} pair can only be - * registered once, double registration would cause {@link IllegalArgumentException}. - * - * @param device {@link BluetoothDevice} that will be registered - * @param executor the executor for listener callback - * @param listener {@link #OnMetadataChangedListener} that will receive asynchronous callbacks - * @return true on success, false on error - * @throws NullPointerException If one of {@code listener}, {@code device} or {@code executor} - * is null. - * @throws IllegalArgumentException The same {@link #OnMetadataChangedListener} and - * {@link BluetoothDevice} are registered twice. - * @hide - */ - @SystemApi - @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) - public boolean addOnMetadataChangedListener(@NonNull BluetoothDevice device, - @NonNull Executor executor, @NonNull OnMetadataChangedListener listener) { - if (DBG) Log.d(TAG, "addOnMetadataChangedListener()"); - - final IBluetooth service = mService; - if (service == null) { - Log.e(TAG, "Bluetooth is not enabled. Cannot register metadata listener"); - return false; - } - if (listener == null) { - throw new NullPointerException("listener is null"); - } - if (device == null) { - throw new NullPointerException("device is null"); - } - if (executor == null) { - throw new NullPointerException("executor is null"); - } - - synchronized (mMetadataListeners) { - List> listenerList = - mMetadataListeners.get(device); - if (listenerList == null) { - // Create new listener/executor list for registeration - listenerList = new ArrayList<>(); - mMetadataListeners.put(device, listenerList); - } else { - // Check whether this device was already registed by the lisenter - if (listenerList.stream().anyMatch((pair) -> (pair.first.equals(listener)))) { - throw new IllegalArgumentException("listener was already regestered" - + " for the device"); - } - } - - Pair listenerPair = new Pair(listener, executor); - listenerList.add(listenerPair); - - boolean ret = false; - try { - ret = service.registerMetadataListener(mBluetoothMetadataListener, device, - mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "registerMetadataListener fail", e); - } finally { - if (!ret) { - // Remove listener registered earlier when fail. - listenerList.remove(listenerPair); - if (listenerList.isEmpty()) { - // Remove the device if its listener list is empty - mMetadataListeners.remove(device); - } - } - } - return ret; - } - } - - /** - * Unregister a {@link #OnMetadataChangedListener} from a registered {@link BluetoothDevice}. - * Unregistration can be done when Bluetooth is either ON or OFF. - * {@link #addOnMetadataChangedListener(OnMetadataChangedListener, BluetoothDevice, Executor)} - * must be called before unregisteration. - * - * @param device {@link BluetoothDevice} that will be unregistered. It - * should not be null or {@link NullPointerException} will be triggered. - * @param listener {@link OnMetadataChangedListener} that will be unregistered. It - * should not be null or {@link NullPointerException} will be triggered. - * @return true on success, false on error - * @throws NullPointerException If {@code listener} or {@code device} is null. - * @throws IllegalArgumentException If {@code device} has not been registered before. - * @hide - */ - @SystemApi - @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) - public boolean removeOnMetadataChangedListener(@NonNull BluetoothDevice device, - @NonNull OnMetadataChangedListener listener) { - if (DBG) Log.d(TAG, "removeOnMetadataChangedListener()"); - if (device == null) { - throw new NullPointerException("device is null"); - } - if (listener == null) { - throw new NullPointerException("listener is null"); - } - - synchronized (mMetadataListeners) { - if (!mMetadataListeners.containsKey(device)) { - throw new IllegalArgumentException("device was not registered"); - } - // Remove issued listener from the registered device - mMetadataListeners.get(device).removeIf((pair) -> (pair.first.equals(listener))); - - if (mMetadataListeners.get(device).isEmpty()) { - // Unregister to Bluetooth service if all listeners are removed from - // the registered device - mMetadataListeners.remove(device); - final IBluetooth service = mService; - if (service == null) { - // Bluetooth is OFF, do nothing to Bluetooth service. - return true; - } - try { - return service.unregisterMetadataListener(device, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "unregisterMetadataListener fail", e); - return false; - } - } - } - return true; - } - - /** - * This interface is used to implement {@link BluetoothAdapter} metadata listener. - * @hide - */ - @SystemApi - public interface OnMetadataChangedListener { - /** - * Callback triggered if the metadata of {@link BluetoothDevice} registered in - * {@link #addOnMetadataChangedListener}. - * - * @param device changed {@link BluetoothDevice}. - * @param key changed metadata key, one of BluetoothDevice.METADATA_*. - * @param value the new value of metadata as byte array. - */ - void onMetadataChanged(@NonNull BluetoothDevice device, int key, - @Nullable byte[] value); - } - - @SuppressLint("AndroidFrameworkBluetoothPermission") - private final IBluetoothConnectionCallback mConnectionCallback = - new IBluetoothConnectionCallback.Stub() { - @Override - public void onDeviceConnected(BluetoothDevice device) { - Attributable.setAttributionSource(device, mAttributionSource); - for (Map.Entry callbackExecutorEntry: - mBluetoothConnectionCallbackExecutorMap.entrySet()) { - BluetoothConnectionCallback callback = callbackExecutorEntry.getKey(); - Executor executor = callbackExecutorEntry.getValue(); - executor.execute(() -> callback.onDeviceConnected(device)); - } - } - - @Override - public void onDeviceDisconnected(BluetoothDevice device, int hciReason) { - Attributable.setAttributionSource(device, mAttributionSource); - for (Map.Entry callbackExecutorEntry: - mBluetoothConnectionCallbackExecutorMap.entrySet()) { - BluetoothConnectionCallback callback = callbackExecutorEntry.getKey(); - Executor executor = callbackExecutorEntry.getValue(); - executor.execute(() -> callback.onDeviceDisconnected(device, hciReason)); - } - } - }; - - /** - * Registers the BluetoothConnectionCallback to receive callback events when a bluetooth device - * (classic or low energy) is connected or disconnected. - * - * @param executor is the callback executor - * @param callback is the connection callback you wish to register - * @return true if the callback was registered successfully, false otherwise - * @throws IllegalArgumentException if the callback is already registered - * @hide - */ - @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) - public boolean registerBluetoothConnectionCallback(@NonNull @CallbackExecutor Executor executor, - @NonNull BluetoothConnectionCallback callback) { - if (DBG) Log.d(TAG, "registerBluetoothConnectionCallback()"); - if (callback == null) { - return false; - } - - synchronized (mBluetoothConnectionCallbackExecutorMap) { - // If the callback map is empty, we register the service-to-app callback - if (mBluetoothConnectionCallbackExecutorMap.isEmpty()) { - try { - mServiceLock.readLock().lock(); - if (mService != null) { - if (!mService.registerBluetoothConnectionCallback(mConnectionCallback, - mAttributionSource)) { - return false; - } - } - } catch (RemoteException e) { - Log.e(TAG, "", e); - mBluetoothConnectionCallbackExecutorMap.remove(callback); - } finally { - mServiceLock.readLock().unlock(); - } - } - - // Adds the passed in callback to our map of callbacks to executors - if (mBluetoothConnectionCallbackExecutorMap.containsKey(callback)) { - throw new IllegalArgumentException("This callback has already been registered"); - } - mBluetoothConnectionCallbackExecutorMap.put(callback, executor); - } - - return true; - } - - /** - * Unregisters the BluetoothConnectionCallback that was previously registered by the application - * - * @param callback is the connection callback you wish to unregister - * @return true if the callback was unregistered successfully, false otherwise - * @hide - */ - @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) - public boolean unregisterBluetoothConnectionCallback( - @NonNull BluetoothConnectionCallback callback) { - if (DBG) Log.d(TAG, "unregisterBluetoothConnectionCallback()"); - if (callback == null) { - return false; - } - - synchronized (mBluetoothConnectionCallbackExecutorMap) { - if (mBluetoothConnectionCallbackExecutorMap.remove(callback) != null) { - return false; - } - } - - if (!mBluetoothConnectionCallbackExecutorMap.isEmpty()) { - return true; - } - - // If the callback map is empty, we unregister the service-to-app callback - try { - mServiceLock.readLock().lock(); - if (mService != null) { - return mService.unregisterBluetoothConnectionCallback(mConnectionCallback, - mAttributionSource); - } - } catch (RemoteException e) { - Log.e(TAG, "", e); - } finally { - mServiceLock.readLock().unlock(); - } - - return false; - } - - /** - * This abstract class is used to implement callbacks for when a bluetooth classic or Bluetooth - * Low Energy (BLE) device is either connected or disconnected. - * - * @hide - */ - public abstract static class BluetoothConnectionCallback { - /** - * Callback triggered when a bluetooth device (classic or BLE) is connected - * @param device is the connected bluetooth device - */ - public void onDeviceConnected(BluetoothDevice device) {} - - /** - * Callback triggered when a bluetooth device (classic or BLE) is disconnected - * @param device is the disconnected bluetooth device - * @param reason is the disconnect reason - */ - public void onDeviceDisconnected(BluetoothDevice device, @DisconnectReason int reason) {} - - /** - * @hide - */ - @Retention(RetentionPolicy.SOURCE) - @IntDef(prefix = { "REASON_" }, value = { - BluetoothStatusCodes.ERROR_UNKNOWN, - BluetoothStatusCodes.ERROR_DISCONNECT_REASON_LOCAL_REQUEST, - BluetoothStatusCodes.ERROR_DISCONNECT_REASON_REMOTE_REQUEST, - BluetoothStatusCodes.ERROR_DISCONNECT_REASON_LOCAL, - BluetoothStatusCodes.ERROR_DISCONNECT_REASON_REMOTE, - BluetoothStatusCodes.ERROR_DISCONNECT_REASON_TIMEOUT, - BluetoothStatusCodes.ERROR_DISCONNECT_REASON_SECURITY, - BluetoothStatusCodes.ERROR_DISCONNECT_REASON_SYSTEM_POLICY, - BluetoothStatusCodes.ERROR_DISCONNECT_REASON_RESOURCE_LIMIT_REACHED, - BluetoothStatusCodes.ERROR_DISCONNECT_REASON_CONNECTION_ALREADY_EXISTS, - BluetoothStatusCodes.ERROR_DISCONNECT_REASON_BAD_PARAMETERS}) - public @interface DisconnectReason {} - - /** - * Returns human-readable strings corresponding to {@link DisconnectReason}. - */ - public static String disconnectReasonText(@DisconnectReason int reason) { - switch (reason) { - case BluetoothStatusCodes.ERROR_UNKNOWN: - return "Reason unknown"; - case BluetoothStatusCodes.ERROR_DISCONNECT_REASON_LOCAL_REQUEST: - return "Local request"; - case BluetoothStatusCodes.ERROR_DISCONNECT_REASON_REMOTE_REQUEST: - return "Remote request"; - case BluetoothStatusCodes.ERROR_DISCONNECT_REASON_LOCAL: - return "Local error"; - case BluetoothStatusCodes.ERROR_DISCONNECT_REASON_REMOTE: - return "Remote error"; - case BluetoothStatusCodes.ERROR_DISCONNECT_REASON_TIMEOUT: - return "Timeout"; - case BluetoothStatusCodes.ERROR_DISCONNECT_REASON_SECURITY: - return "Security"; - case BluetoothStatusCodes.ERROR_DISCONNECT_REASON_SYSTEM_POLICY: - return "System policy"; - case BluetoothStatusCodes.ERROR_DISCONNECT_REASON_RESOURCE_LIMIT_REACHED: - return "Resource constrained"; - case BluetoothStatusCodes.ERROR_DISCONNECT_REASON_CONNECTION_ALREADY_EXISTS: - return "Connection already exists"; - case BluetoothStatusCodes.ERROR_DISCONNECT_REASON_BAD_PARAMETERS: - return "Bad parameters"; - default: - return "Unrecognized disconnect reason: " + reason; - } - } - } - - /** - * Converts old constant of priority to the new for connection policy - * - * @param priority is the priority to convert to connection policy - * @return the equivalent connection policy constant to the priority - * - * @hide - */ - public static @ConnectionPolicy int priorityToConnectionPolicy(int priority) { - switch(priority) { - case BluetoothProfile.PRIORITY_AUTO_CONNECT: - return BluetoothProfile.CONNECTION_POLICY_ALLOWED; - case BluetoothProfile.PRIORITY_ON: - return BluetoothProfile.CONNECTION_POLICY_ALLOWED; - case BluetoothProfile.PRIORITY_OFF: - return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; - case BluetoothProfile.PRIORITY_UNDEFINED: - return BluetoothProfile.CONNECTION_POLICY_UNKNOWN; - default: - Log.e(TAG, "setPriority: Invalid priority: " + priority); - return BluetoothProfile.CONNECTION_POLICY_UNKNOWN; - } - } - - /** - * Converts new constant of connection policy to the old for priority - * - * @param connectionPolicy is the connection policy to convert to priority - * @return the equivalent priority constant to the connectionPolicy - * - * @hide - */ - public static int connectionPolicyToPriority(@ConnectionPolicy int connectionPolicy) { - switch(connectionPolicy) { - case BluetoothProfile.CONNECTION_POLICY_ALLOWED: - return BluetoothProfile.PRIORITY_ON; - case BluetoothProfile.CONNECTION_POLICY_FORBIDDEN: - return BluetoothProfile.PRIORITY_OFF; - case BluetoothProfile.CONNECTION_POLICY_UNKNOWN: - return BluetoothProfile.PRIORITY_UNDEFINED; - } - return BluetoothProfile.PRIORITY_UNDEFINED; - } -} diff --git a/core/java/android/bluetooth/BluetoothAssignedNumbers.java b/core/java/android/bluetooth/BluetoothAssignedNumbers.java deleted file mode 100644 index 41a34e061845f430f5a234bc81758fc6c4d0c20c..0000000000000000000000000000000000000000 --- a/core/java/android/bluetooth/BluetoothAssignedNumbers.java +++ /dev/null @@ -1,1171 +0,0 @@ -/* - * Copyright (C) 2010 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.bluetooth; - -/** - * Bluetooth Assigned Numbers. - *

- * For now we only include Company ID values. - * - * @see The Official - * Bluetooth SIG Member Website | Company Identifiers - */ -public class BluetoothAssignedNumbers { - - // Bluetooth SIG Company ID values - /* - * Ericsson Technology Licensing. - */ - public static final int ERICSSON_TECHNOLOGY = 0x0000; - - /* - * Nokia Mobile Phones. - */ - public static final int NOKIA_MOBILE_PHONES = 0x0001; - - /* - * Intel Corp. - */ - public static final int INTEL = 0x0002; - - /* - * IBM Corp. - */ - public static final int IBM = 0x0003; - - /* - * Toshiba Corp. - */ - public static final int TOSHIBA = 0x0004; - - /* - * 3Com. - */ - public static final int THREECOM = 0x0005; - - /* - * Microsoft. - */ - public static final int MICROSOFT = 0x0006; - - /* - * Lucent. - */ - public static final int LUCENT = 0x0007; - - /* - * Motorola. - */ - public static final int MOTOROLA = 0x0008; - - /* - * Infineon Technologies AG. - */ - public static final int INFINEON_TECHNOLOGIES = 0x0009; - - /* - * Cambridge Silicon Radio. - */ - public static final int CAMBRIDGE_SILICON_RADIO = 0x000A; - - /* - * Silicon Wave. - */ - public static final int SILICON_WAVE = 0x000B; - - /* - * Digianswer A/S. - */ - public static final int DIGIANSWER = 0x000C; - - /* - * Texas Instruments Inc. - */ - public static final int TEXAS_INSTRUMENTS = 0x000D; - - /* - * Parthus Technologies Inc. - */ - public static final int PARTHUS_TECHNOLOGIES = 0x000E; - - /* - * Broadcom Corporation. - */ - public static final int BROADCOM = 0x000F; - - /* - * Mitel Semiconductor. - */ - public static final int MITEL_SEMICONDUCTOR = 0x0010; - - /* - * Widcomm, Inc. - */ - public static final int WIDCOMM = 0x0011; - - /* - * Zeevo, Inc. - */ - public static final int ZEEVO = 0x0012; - - /* - * Atmel Corporation. - */ - public static final int ATMEL = 0x0013; - - /* - * Mitsubishi Electric Corporation. - */ - public static final int MITSUBISHI_ELECTRIC = 0x0014; - - /* - * RTX Telecom A/S. - */ - public static final int RTX_TELECOM = 0x0015; - - /* - * KC Technology Inc. - */ - public static final int KC_TECHNOLOGY = 0x0016; - - /* - * Newlogic. - */ - public static final int NEWLOGIC = 0x0017; - - /* - * Transilica, Inc. - */ - public static final int TRANSILICA = 0x0018; - - /* - * Rohde & Schwarz GmbH & Co. KG. - */ - public static final int ROHDE_AND_SCHWARZ = 0x0019; - - /* - * TTPCom Limited. - */ - public static final int TTPCOM = 0x001A; - - /* - * Signia Technologies, Inc. - */ - public static final int SIGNIA_TECHNOLOGIES = 0x001B; - - /* - * Conexant Systems Inc. - */ - public static final int CONEXANT_SYSTEMS = 0x001C; - - /* - * Qualcomm. - */ - public static final int QUALCOMM = 0x001D; - - /* - * Inventel. - */ - public static final int INVENTEL = 0x001E; - - /* - * AVM Berlin. - */ - public static final int AVM_BERLIN = 0x001F; - - /* - * BandSpeed, Inc. - */ - public static final int BANDSPEED = 0x0020; - - /* - * Mansella Ltd. - */ - public static final int MANSELLA = 0x0021; - - /* - * NEC Corporation. - */ - public static final int NEC = 0x0022; - - /* - * WavePlus Technology Co., Ltd. - */ - public static final int WAVEPLUS_TECHNOLOGY = 0x0023; - - /* - * Alcatel. - */ - public static final int ALCATEL = 0x0024; - - /* - * Philips Semiconductors. - */ - public static final int PHILIPS_SEMICONDUCTORS = 0x0025; - - /* - * C Technologies. - */ - public static final int C_TECHNOLOGIES = 0x0026; - - /* - * Open Interface. - */ - public static final int OPEN_INTERFACE = 0x0027; - - /* - * R F Micro Devices. - */ - public static final int RF_MICRO_DEVICES = 0x0028; - - /* - * Hitachi Ltd. - */ - public static final int HITACHI = 0x0029; - - /* - * Symbol Technologies, Inc. - */ - public static final int SYMBOL_TECHNOLOGIES = 0x002A; - - /* - * Tenovis. - */ - public static final int TENOVIS = 0x002B; - - /* - * Macronix International Co. Ltd. - */ - public static final int MACRONIX = 0x002C; - - /* - * GCT Semiconductor. - */ - public static final int GCT_SEMICONDUCTOR = 0x002D; - - /* - * Norwood Systems. - */ - public static final int NORWOOD_SYSTEMS = 0x002E; - - /* - * MewTel Technology Inc. - */ - public static final int MEWTEL_TECHNOLOGY = 0x002F; - - /* - * ST Microelectronics. - */ - public static final int ST_MICROELECTRONICS = 0x0030; - - /* - * Synopsys. - */ - public static final int SYNOPSYS = 0x0031; - - /* - * Red-M (Communications) Ltd. - */ - public static final int RED_M = 0x0032; - - /* - * Commil Ltd. - */ - public static final int COMMIL = 0x0033; - - /* - * Computer Access Technology Corporation (CATC). - */ - public static final int CATC = 0x0034; - - /* - * Eclipse (HQ Espana) S.L. - */ - public static final int ECLIPSE = 0x0035; - - /* - * Renesas Technology Corp. - */ - public static final int RENESAS_TECHNOLOGY = 0x0036; - - /* - * Mobilian Corporation. - */ - public static final int MOBILIAN_CORPORATION = 0x0037; - - /* - * Terax. - */ - public static final int TERAX = 0x0038; - - /* - * Integrated System Solution Corp. - */ - public static final int INTEGRATED_SYSTEM_SOLUTION = 0x0039; - - /* - * Matsushita Electric Industrial Co., Ltd. - */ - public static final int MATSUSHITA_ELECTRIC = 0x003A; - - /* - * Gennum Corporation. - */ - public static final int GENNUM = 0x003B; - - /* - * Research In Motion. - */ - public static final int RESEARCH_IN_MOTION = 0x003C; - - /* - * IPextreme, Inc. - */ - public static final int IPEXTREME = 0x003D; - - /* - * Systems and Chips, Inc. - */ - public static final int SYSTEMS_AND_CHIPS = 0x003E; - - /* - * Bluetooth SIG, Inc. - */ - public static final int BLUETOOTH_SIG = 0x003F; - - /* - * Seiko Epson Corporation. - */ - public static final int SEIKO_EPSON = 0x0040; - - /* - * Integrated Silicon Solution Taiwan, Inc. - */ - public static final int INTEGRATED_SILICON_SOLUTION = 0x0041; - - /* - * CONWISE Technology Corporation Ltd. - */ - public static final int CONWISE_TECHNOLOGY = 0x0042; - - /* - * PARROT SA. - */ - public static final int PARROT = 0x0043; - - /* - * Socket Mobile. - */ - public static final int SOCKET_MOBILE = 0x0044; - - /* - * Atheros Communications, Inc. - */ - public static final int ATHEROS_COMMUNICATIONS = 0x0045; - - /* - * MediaTek, Inc. - */ - public static final int MEDIATEK = 0x0046; - - /* - * Bluegiga. - */ - public static final int BLUEGIGA = 0x0047; - - /* - * Marvell Technology Group Ltd. - */ - public static final int MARVELL = 0x0048; - - /* - * 3DSP Corporation. - */ - public static final int THREE_DSP = 0x0049; - - /* - * Accel Semiconductor Ltd. - */ - public static final int ACCEL_SEMICONDUCTOR = 0x004A; - - /* - * Continental Automotive Systems. - */ - public static final int CONTINENTAL_AUTOMOTIVE = 0x004B; - - /* - * Apple, Inc. - */ - public static final int APPLE = 0x004C; - - /* - * Staccato Communications, Inc. - */ - public static final int STACCATO_COMMUNICATIONS = 0x004D; - - /* - * Avago Technologies. - */ - public static final int AVAGO = 0x004E; - - /* - * APT Licensing Ltd. - */ - public static final int APT_LICENSING = 0x004F; - - /* - * SiRF Technology, Inc. - */ - public static final int SIRF_TECHNOLOGY = 0x0050; - - /* - * Tzero Technologies, Inc. - */ - public static final int TZERO_TECHNOLOGIES = 0x0051; - - /* - * J&M Corporation. - */ - public static final int J_AND_M = 0x0052; - - /* - * Free2move AB. - */ - public static final int FREE2MOVE = 0x0053; - - /* - * 3DiJoy Corporation. - */ - public static final int THREE_DIJOY = 0x0054; - - /* - * Plantronics, Inc. - */ - public static final int PLANTRONICS = 0x0055; - - /* - * Sony Ericsson Mobile Communications. - */ - public static final int SONY_ERICSSON = 0x0056; - - /* - * Harman International Industries, Inc. - */ - public static final int HARMAN_INTERNATIONAL = 0x0057; - - /* - * Vizio, Inc. - */ - public static final int VIZIO = 0x0058; - - /* - * Nordic Semiconductor ASA. - */ - public static final int NORDIC_SEMICONDUCTOR = 0x0059; - - /* - * EM Microelectronic-Marin SA. - */ - public static final int EM_MICROELECTRONIC_MARIN = 0x005A; - - /* - * Ralink Technology Corporation. - */ - public static final int RALINK_TECHNOLOGY = 0x005B; - - /* - * Belkin International, Inc. - */ - public static final int BELKIN_INTERNATIONAL = 0x005C; - - /* - * Realtek Semiconductor Corporation. - */ - public static final int REALTEK_SEMICONDUCTOR = 0x005D; - - /* - * Stonestreet One, LLC. - */ - public static final int STONESTREET_ONE = 0x005E; - - /* - * Wicentric, Inc. - */ - public static final int WICENTRIC = 0x005F; - - /* - * RivieraWaves S.A.S. - */ - public static final int RIVIERAWAVES = 0x0060; - - /* - * RDA Microelectronics. - */ - public static final int RDA_MICROELECTRONICS = 0x0061; - - /* - * Gibson Guitars. - */ - public static final int GIBSON_GUITARS = 0x0062; - - /* - * MiCommand Inc. - */ - public static final int MICOMMAND = 0x0063; - - /* - * Band XI International, LLC. - */ - public static final int BAND_XI_INTERNATIONAL = 0x0064; - - /* - * Hewlett-Packard Company. - */ - public static final int HEWLETT_PACKARD = 0x0065; - - /* - * 9Solutions Oy. - */ - public static final int NINE_SOLUTIONS = 0x0066; - - /* - * GN Netcom A/S. - */ - public static final int GN_NETCOM = 0x0067; - - /* - * General Motors. - */ - public static final int GENERAL_MOTORS = 0x0068; - - /* - * A&D Engineering, Inc. - */ - public static final int A_AND_D_ENGINEERING = 0x0069; - - /* - * MindTree Ltd. - */ - public static final int MINDTREE = 0x006A; - - /* - * Polar Electro OY. - */ - public static final int POLAR_ELECTRO = 0x006B; - - /* - * Beautiful Enterprise Co., Ltd. - */ - public static final int BEAUTIFUL_ENTERPRISE = 0x006C; - - /* - * BriarTek, Inc. - */ - public static final int BRIARTEK = 0x006D; - - /* - * Summit Data Communications, Inc. - */ - public static final int SUMMIT_DATA_COMMUNICATIONS = 0x006E; - - /* - * Sound ID. - */ - public static final int SOUND_ID = 0x006F; - - /* - * Monster, LLC. - */ - public static final int MONSTER = 0x0070; - - /* - * connectBlue AB. - */ - public static final int CONNECTBLUE = 0x0071; - - /* - * ShangHai Super Smart Electronics Co. Ltd. - */ - public static final int SHANGHAI_SUPER_SMART_ELECTRONICS = 0x0072; - - /* - * Group Sense Ltd. - */ - public static final int GROUP_SENSE = 0x0073; - - /* - * Zomm, LLC. - */ - public static final int ZOMM = 0x0074; - - /* - * Samsung Electronics Co. Ltd. - */ - public static final int SAMSUNG_ELECTRONICS = 0x0075; - - /* - * Creative Technology Ltd. - */ - public static final int CREATIVE_TECHNOLOGY = 0x0076; - - /* - * Laird Technologies. - */ - public static final int LAIRD_TECHNOLOGIES = 0x0077; - - /* - * Nike, Inc. - */ - public static final int NIKE = 0x0078; - - /* - * lesswire AG. - */ - public static final int LESSWIRE = 0x0079; - - /* - * MStar Semiconductor, Inc. - */ - public static final int MSTAR_SEMICONDUCTOR = 0x007A; - - /* - * Hanlynn Technologies. - */ - public static final int HANLYNN_TECHNOLOGIES = 0x007B; - - /* - * A & R Cambridge. - */ - public static final int A_AND_R_CAMBRIDGE = 0x007C; - - /* - * Seers Technology Co. Ltd. - */ - public static final int SEERS_TECHNOLOGY = 0x007D; - - /* - * Sports Tracking Technologies Ltd. - */ - public static final int SPORTS_TRACKING_TECHNOLOGIES = 0x007E; - - /* - * Autonet Mobile. - */ - public static final int AUTONET_MOBILE = 0x007F; - - /* - * DeLorme Publishing Company, Inc. - */ - public static final int DELORME_PUBLISHING_COMPANY = 0x0080; - - /* - * WuXi Vimicro. - */ - public static final int WUXI_VIMICRO = 0x0081; - - /* - * Sennheiser Communications A/S. - */ - public static final int SENNHEISER_COMMUNICATIONS = 0x0082; - - /* - * TimeKeeping Systems, Inc. - */ - public static final int TIMEKEEPING_SYSTEMS = 0x0083; - - /* - * Ludus Helsinki Ltd. - */ - public static final int LUDUS_HELSINKI = 0x0084; - - /* - * BlueRadios, Inc. - */ - public static final int BLUERADIOS = 0x0085; - - /* - * equinox AG. - */ - public static final int EQUINOX_AG = 0x0086; - - /* - * Garmin International, Inc. - */ - public static final int GARMIN_INTERNATIONAL = 0x0087; - - /* - * Ecotest. - */ - public static final int ECOTEST = 0x0088; - - /* - * GN ReSound A/S. - */ - public static final int GN_RESOUND = 0x0089; - - /* - * Jawbone. - */ - public static final int JAWBONE = 0x008A; - - /* - * Topcorn Positioning Systems, LLC. - */ - public static final int TOPCORN_POSITIONING_SYSTEMS = 0x008B; - - /* - * Qualcomm Labs, Inc. - */ - public static final int QUALCOMM_LABS = 0x008C; - - /* - * Zscan Software. - */ - public static final int ZSCAN_SOFTWARE = 0x008D; - - /* - * Quintic Corp. - */ - public static final int QUINTIC = 0x008E; - - /* - * Stollman E+V GmbH. - */ - public static final int STOLLMAN_E_PLUS_V = 0x008F; - - /* - * Funai Electric Co., Ltd. - */ - public static final int FUNAI_ELECTRIC = 0x0090; - - /* - * Advanced PANMOBIL Systems GmbH & Co. KG. - */ - public static final int ADVANCED_PANMOBIL_SYSTEMS = 0x0091; - - /* - * ThinkOptics, Inc. - */ - public static final int THINKOPTICS = 0x0092; - - /* - * Universal Electronics, Inc. - */ - public static final int UNIVERSAL_ELECTRONICS = 0x0093; - - /* - * Airoha Technology Corp. - */ - public static final int AIROHA_TECHNOLOGY = 0x0094; - - /* - * NEC Lighting, Ltd. - */ - public static final int NEC_LIGHTING = 0x0095; - - /* - * ODM Technology, Inc. - */ - public static final int ODM_TECHNOLOGY = 0x0096; - - /* - * Bluetrek Technologies Limited. - */ - public static final int BLUETREK_TECHNOLOGIES = 0x0097; - - /* - * zer01.tv GmbH. - */ - public static final int ZER01_TV = 0x0098; - - /* - * i.Tech Dynamic Global Distribution Ltd. - */ - public static final int I_TECH_DYNAMIC_GLOBAL_DISTRIBUTION = 0x0099; - - /* - * Alpwise. - */ - public static final int ALPWISE = 0x009A; - - /* - * Jiangsu Toppower Automotive Electronics Co., Ltd. - */ - public static final int JIANGSU_TOPPOWER_AUTOMOTIVE_ELECTRONICS = 0x009B; - - /* - * Colorfy, Inc. - */ - public static final int COLORFY = 0x009C; - - /* - * Geoforce Inc. - */ - public static final int GEOFORCE = 0x009D; - - /* - * Bose Corporation. - */ - public static final int BOSE = 0x009E; - - /* - * Suunto Oy. - */ - public static final int SUUNTO = 0x009F; - - /* - * Kensington Computer Products Group. - */ - public static final int KENSINGTON_COMPUTER_PRODUCTS_GROUP = 0x00A0; - - /* - * SR-Medizinelektronik. - */ - public static final int SR_MEDIZINELEKTRONIK = 0x00A1; - - /* - * Vertu Corporation Limited. - */ - public static final int VERTU = 0x00A2; - - /* - * Meta Watch Ltd. - */ - public static final int META_WATCH = 0x00A3; - - /* - * LINAK A/S. - */ - public static final int LINAK = 0x00A4; - - /* - * OTL Dynamics LLC. - */ - public static final int OTL_DYNAMICS = 0x00A5; - - /* - * Panda Ocean Inc. - */ - public static final int PANDA_OCEAN = 0x00A6; - - /* - * Visteon Corporation. - */ - public static final int VISTEON = 0x00A7; - - /* - * ARP Devices Limited. - */ - public static final int ARP_DEVICES = 0x00A8; - - /* - * Magneti Marelli S.p.A. - */ - public static final int MAGNETI_MARELLI = 0x00A9; - - /* - * CAEN RFID srl. - */ - public static final int CAEN_RFID = 0x00AA; - - /* - * Ingenieur-Systemgruppe Zahn GmbH. - */ - public static final int INGENIEUR_SYSTEMGRUPPE_ZAHN = 0x00AB; - - /* - * Green Throttle Games. - */ - public static final int GREEN_THROTTLE_GAMES = 0x00AC; - - /* - * Peter Systemtechnik GmbH. - */ - public static final int PETER_SYSTEMTECHNIK = 0x00AD; - - /* - * Omegawave Oy. - */ - public static final int OMEGAWAVE = 0x00AE; - - /* - * Cinetix. - */ - public static final int CINETIX = 0x00AF; - - /* - * Passif Semiconductor Corp. - */ - public static final int PASSIF_SEMICONDUCTOR = 0x00B0; - - /* - * Saris Cycling Group, Inc. - */ - public static final int SARIS_CYCLING_GROUP = 0x00B1; - - /* - * Bekey A/S. - */ - public static final int BEKEY = 0x00B2; - - /* - * Clarinox Technologies Pty. Ltd. - */ - public static final int CLARINOX_TECHNOLOGIES = 0x00B3; - - /* - * BDE Technology Co., Ltd. - */ - public static final int BDE_TECHNOLOGY = 0x00B4; - - /* - * Swirl Networks. - */ - public static final int SWIRL_NETWORKS = 0x00B5; - - /* - * Meso international. - */ - public static final int MESO_INTERNATIONAL = 0x00B6; - - /* - * TreLab Ltd. - */ - public static final int TRELAB = 0x00B7; - - /* - * Qualcomm Innovation Center, Inc. (QuIC). - */ - public static final int QUALCOMM_INNOVATION_CENTER = 0x00B8; - - /* - * Johnson Controls, Inc. - */ - public static final int JOHNSON_CONTROLS = 0x00B9; - - /* - * Starkey Laboratories Inc. - */ - public static final int STARKEY_LABORATORIES = 0x00BA; - - /* - * S-Power Electronics Limited. - */ - public static final int S_POWER_ELECTRONICS = 0x00BB; - - /* - * Ace Sensor Inc. - */ - public static final int ACE_SENSOR = 0x00BC; - - /* - * Aplix Corporation. - */ - public static final int APLIX = 0x00BD; - - /* - * AAMP of America. - */ - public static final int AAMP_OF_AMERICA = 0x00BE; - - /* - * Stalmart Technology Limited. - */ - public static final int STALMART_TECHNOLOGY = 0x00BF; - - /* - * AMICCOM Electronics Corporation. - */ - public static final int AMICCOM_ELECTRONICS = 0x00C0; - - /* - * Shenzhen Excelsecu Data Technology Co.,Ltd. - */ - public static final int SHENZHEN_EXCELSECU_DATA_TECHNOLOGY = 0x00C1; - - /* - * Geneq Inc. - */ - public static final int GENEQ = 0x00C2; - - /* - * adidas AG. - */ - public static final int ADIDAS = 0x00C3; - - /* - * LG Electronics. - */ - public static final int LG_ELECTRONICS = 0x00C4; - - /* - * Onset Computer Corporation. - */ - public static final int ONSET_COMPUTER = 0x00C5; - - /* - * Selfly BV. - */ - public static final int SELFLY = 0x00C6; - - /* - * Quuppa Oy. - */ - public static final int QUUPPA = 0x00C7; - - /* - * GeLo Inc. - */ - public static final int GELO = 0x00C8; - - /* - * Evluma. - */ - public static final int EVLUMA = 0x00C9; - - /* - * MC10. - */ - public static final int MC10 = 0x00CA; - - /* - * Binauric SE. - */ - public static final int BINAURIC = 0x00CB; - - /* - * Beats Electronics. - */ - public static final int BEATS_ELECTRONICS = 0x00CC; - - /* - * Microchip Technology Inc. - */ - public static final int MICROCHIP_TECHNOLOGY = 0x00CD; - - /* - * Elgato Systems GmbH. - */ - public static final int ELGATO_SYSTEMS = 0x00CE; - - /* - * ARCHOS SA. - */ - public static final int ARCHOS = 0x00CF; - - /* - * Dexcom, Inc. - */ - public static final int DEXCOM = 0x00D0; - - /* - * Polar Electro Europe B.V. - */ - public static final int POLAR_ELECTRO_EUROPE = 0x00D1; - - /* - * Dialog Semiconductor B.V. - */ - public static final int DIALOG_SEMICONDUCTOR = 0x00D2; - - /* - * Taixingbang Technology (HK) Co,. LTD. - */ - public static final int TAIXINGBANG_TECHNOLOGY = 0x00D3; - - /* - * Kawantech. - */ - public static final int KAWANTECH = 0x00D4; - - /* - * Austco Communication Systems. - */ - public static final int AUSTCO_COMMUNICATION_SYSTEMS = 0x00D5; - - /* - * Timex Group USA, Inc. - */ - public static final int TIMEX_GROUP_USA = 0x00D6; - - /* - * Qualcomm Technologies, Inc. - */ - public static final int QUALCOMM_TECHNOLOGIES = 0x00D7; - - /* - * Qualcomm Connected Experiences, Inc. - */ - public static final int QUALCOMM_CONNECTED_EXPERIENCES = 0x00D8; - - /* - * Voyetra Turtle Beach. - */ - public static final int VOYETRA_TURTLE_BEACH = 0x00D9; - - /* - * txtr GmbH. - */ - public static final int TXTR = 0x00DA; - - /* - * Biosentronics. - */ - public static final int BIOSENTRONICS = 0x00DB; - - /* - * Procter & Gamble. - */ - public static final int PROCTER_AND_GAMBLE = 0x00DC; - - /* - * Hosiden Corporation. - */ - public static final int HOSIDEN = 0x00DD; - - /* - * Muzik LLC. - */ - public static final int MUZIK = 0x00DE; - - /* - * Misfit Wearables Corp. - */ - public static final int MISFIT_WEARABLES = 0x00DF; - - /* - * Google. - */ - public static final int GOOGLE = 0x00E0; - - /* - * Danlers Ltd. - */ - public static final int DANLERS = 0x00E1; - - /* - * Semilink Inc. - */ - public static final int SEMILINK = 0x00E2; - - /* - * You can't instantiate one of these. - */ - private BluetoothAssignedNumbers() { - } - -} diff --git a/core/java/android/bluetooth/BluetoothAudioConfig.java b/core/java/android/bluetooth/BluetoothAudioConfig.java deleted file mode 100644 index 4c8b8c11fbc25cc14a4634763d8abfa86d24125b..0000000000000000000000000000000000000000 --- a/core/java/android/bluetooth/BluetoothAudioConfig.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright (C) 2009 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.bluetooth; - -import android.annotation.Nullable; -import android.os.Parcel; -import android.os.Parcelable; - -/** - * Represents the audio configuration for a Bluetooth A2DP source device. - * - * {@see BluetoothA2dpSink} - * - * {@hide} - */ -public final class BluetoothAudioConfig implements Parcelable { - - private final int mSampleRate; - private final int mChannelConfig; - private final int mAudioFormat; - - public BluetoothAudioConfig(int sampleRate, int channelConfig, int audioFormat) { - mSampleRate = sampleRate; - mChannelConfig = channelConfig; - mAudioFormat = audioFormat; - } - - @Override - public boolean equals(@Nullable Object o) { - if (o instanceof BluetoothAudioConfig) { - BluetoothAudioConfig bac = (BluetoothAudioConfig) o; - return (bac.mSampleRate == mSampleRate && bac.mChannelConfig == mChannelConfig - && bac.mAudioFormat == mAudioFormat); - } - return false; - } - - @Override - public int hashCode() { - return mSampleRate | (mChannelConfig << 24) | (mAudioFormat << 28); - } - - @Override - public String toString() { - return "{mSampleRate:" + mSampleRate + ",mChannelConfig:" + mChannelConfig - + ",mAudioFormat:" + mAudioFormat + "}"; - } - - @Override - public int describeContents() { - return 0; - } - - public static final @android.annotation.NonNull Parcelable.Creator CREATOR = - new Parcelable.Creator() { - public BluetoothAudioConfig createFromParcel(Parcel in) { - int sampleRate = in.readInt(); - int channelConfig = in.readInt(); - int audioFormat = in.readInt(); - return new BluetoothAudioConfig(sampleRate, channelConfig, audioFormat); - } - - public BluetoothAudioConfig[] newArray(int size) { - return new BluetoothAudioConfig[size]; - } - }; - - @Override - public void writeToParcel(Parcel out, int flags) { - out.writeInt(mSampleRate); - out.writeInt(mChannelConfig); - out.writeInt(mAudioFormat); - } - - /** - * Returns the sample rate in samples per second - * - * @return sample rate - */ - public int getSampleRate() { - return mSampleRate; - } - - /** - * Returns the channel configuration (either {@link android.media.AudioFormat#CHANNEL_IN_MONO} - * or {@link android.media.AudioFormat#CHANNEL_IN_STEREO}) - * - * @return channel configuration - */ - public int getChannelConfig() { - return mChannelConfig; - } - - /** - * Returns the channel audio format (either {@link android.media.AudioFormat#ENCODING_PCM_16BIT} - * or {@link android.media.AudioFormat#ENCODING_PCM_8BIT} - * - * @return audio format - */ - public int getAudioFormat() { - return mAudioFormat; - } -} diff --git a/core/java/android/bluetooth/BluetoothAvrcp.java b/core/java/android/bluetooth/BluetoothAvrcp.java deleted file mode 100644 index 1a4c759064829a64345fd60ce6c974fc99a94382..0000000000000000000000000000000000000000 --- a/core/java/android/bluetooth/BluetoothAvrcp.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright (C) 2014 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.bluetooth; - -/** - * This class contains constants for Bluetooth AVRCP profile. - * - * {@hide} - */ -public final class BluetoothAvrcp { - - /* - * State flags for Passthrough commands - */ - public static final int PASSTHROUGH_STATE_PRESS = 0; - public static final int PASSTHROUGH_STATE_RELEASE = 1; - - /* - * Operation IDs for Passthrough commands - */ - public static final int PASSTHROUGH_ID_SELECT = 0x00; /* select */ - public static final int PASSTHROUGH_ID_UP = 0x01; /* up */ - public static final int PASSTHROUGH_ID_DOWN = 0x02; /* down */ - public static final int PASSTHROUGH_ID_LEFT = 0x03; /* left */ - public static final int PASSTHROUGH_ID_RIGHT = 0x04; /* right */ - public static final int PASSTHROUGH_ID_RIGHT_UP = 0x05; /* right-up */ - public static final int PASSTHROUGH_ID_RIGHT_DOWN = 0x06; /* right-down */ - public static final int PASSTHROUGH_ID_LEFT_UP = 0x07; /* left-up */ - public static final int PASSTHROUGH_ID_LEFT_DOWN = 0x08; /* left-down */ - public static final int PASSTHROUGH_ID_ROOT_MENU = 0x09; /* root menu */ - public static final int PASSTHROUGH_ID_SETUP_MENU = 0x0A; /* setup menu */ - public static final int PASSTHROUGH_ID_CONT_MENU = 0x0B; /* contents menu */ - public static final int PASSTHROUGH_ID_FAV_MENU = 0x0C; /* favorite menu */ - public static final int PASSTHROUGH_ID_EXIT = 0x0D; /* exit */ - public static final int PASSTHROUGH_ID_0 = 0x20; /* 0 */ - public static final int PASSTHROUGH_ID_1 = 0x21; /* 1 */ - public static final int PASSTHROUGH_ID_2 = 0x22; /* 2 */ - public static final int PASSTHROUGH_ID_3 = 0x23; /* 3 */ - public static final int PASSTHROUGH_ID_4 = 0x24; /* 4 */ - public static final int PASSTHROUGH_ID_5 = 0x25; /* 5 */ - public static final int PASSTHROUGH_ID_6 = 0x26; /* 6 */ - public static final int PASSTHROUGH_ID_7 = 0x27; /* 7 */ - public static final int PASSTHROUGH_ID_8 = 0x28; /* 8 */ - public static final int PASSTHROUGH_ID_9 = 0x29; /* 9 */ - public static final int PASSTHROUGH_ID_DOT = 0x2A; /* dot */ - public static final int PASSTHROUGH_ID_ENTER = 0x2B; /* enter */ - public static final int PASSTHROUGH_ID_CLEAR = 0x2C; /* clear */ - public static final int PASSTHROUGH_ID_CHAN_UP = 0x30; /* channel up */ - public static final int PASSTHROUGH_ID_CHAN_DOWN = 0x31; /* channel down */ - public static final int PASSTHROUGH_ID_PREV_CHAN = 0x32; /* previous channel */ - public static final int PASSTHROUGH_ID_SOUND_SEL = 0x33; /* sound select */ - public static final int PASSTHROUGH_ID_INPUT_SEL = 0x34; /* input select */ - public static final int PASSTHROUGH_ID_DISP_INFO = 0x35; /* display information */ - public static final int PASSTHROUGH_ID_HELP = 0x36; /* help */ - public static final int PASSTHROUGH_ID_PAGE_UP = 0x37; /* page up */ - public static final int PASSTHROUGH_ID_PAGE_DOWN = 0x38; /* page down */ - public static final int PASSTHROUGH_ID_POWER = 0x40; /* power */ - public static final int PASSTHROUGH_ID_VOL_UP = 0x41; /* volume up */ - public static final int PASSTHROUGH_ID_VOL_DOWN = 0x42; /* volume down */ - public static final int PASSTHROUGH_ID_MUTE = 0x43; /* mute */ - public static final int PASSTHROUGH_ID_PLAY = 0x44; /* play */ - public static final int PASSTHROUGH_ID_STOP = 0x45; /* stop */ - public static final int PASSTHROUGH_ID_PAUSE = 0x46; /* pause */ - public static final int PASSTHROUGH_ID_RECORD = 0x47; /* record */ - public static final int PASSTHROUGH_ID_REWIND = 0x48; /* rewind */ - public static final int PASSTHROUGH_ID_FAST_FOR = 0x49; /* fast forward */ - public static final int PASSTHROUGH_ID_EJECT = 0x4A; /* eject */ - public static final int PASSTHROUGH_ID_FORWARD = 0x4B; /* forward */ - public static final int PASSTHROUGH_ID_BACKWARD = 0x4C; /* backward */ - public static final int PASSTHROUGH_ID_ANGLE = 0x50; /* angle */ - public static final int PASSTHROUGH_ID_SUBPICT = 0x51; /* subpicture */ - public static final int PASSTHROUGH_ID_F1 = 0x71; /* F1 */ - public static final int PASSTHROUGH_ID_F2 = 0x72; /* F2 */ - public static final int PASSTHROUGH_ID_F3 = 0x73; /* F3 */ - public static final int PASSTHROUGH_ID_F4 = 0x74; /* F4 */ - public static final int PASSTHROUGH_ID_F5 = 0x75; /* F5 */ - public static final int PASSTHROUGH_ID_VENDOR = 0x7E; /* vendor unique */ - public static final int PASSTHROUGH_KEYPRESSED_RELEASE = 0x80; -} diff --git a/core/java/android/bluetooth/BluetoothAvrcpController.java b/core/java/android/bluetooth/BluetoothAvrcpController.java deleted file mode 100644 index 81fc3e11e9e123c985cc2eefcfe13baf0b414d9c..0000000000000000000000000000000000000000 --- a/core/java/android/bluetooth/BluetoothAvrcpController.java +++ /dev/null @@ -1,298 +0,0 @@ -/* - * Copyright (C) 2014 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.bluetooth; - -import static android.bluetooth.BluetoothUtils.getSyncTimeout; - -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.content.AttributionSource; -import android.content.Context; -import android.os.IBinder; -import android.os.RemoteException; -import android.util.Log; - -import com.android.modules.utils.SynchronousResultReceiver; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.TimeoutException; - -/** - * This class provides the public APIs to control the Bluetooth AVRCP Controller. It currently - * supports player information, playback support and track metadata. - * - *

BluetoothAvrcpController is a proxy object for controlling the Bluetooth AVRCP - * Service via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get - * the BluetoothAvrcpController proxy object. - * - * {@hide} - */ -public final class BluetoothAvrcpController implements BluetoothProfile { - private static final String TAG = "BluetoothAvrcpController"; - private static final boolean DBG = false; - private static final boolean VDBG = false; - - /** - * Intent used to broadcast the change in connection state of the AVRCP Controller - * profile. - * - *

This intent will have 3 extras: - *

    - *
  • {@link #EXTRA_STATE} - The current state of the profile.
  • - *
  • {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile.
  • - *
  • {@link BluetoothDevice#EXTRA_DEVICE} - The remote device.
  • - *
- * - *

{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of - * {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING}, - * {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}. - */ - @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"; - - /** - * Intent used to broadcast the change in player application setting state on AVRCP AG. - * - *

This intent will have the following extras: - *

    - *
  • {@link #EXTRA_PLAYER_SETTING} - {@link BluetoothAvrcpPlayerSettings} containing the - * most recent player setting.
  • - *
- */ - @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"; - - public static final String EXTRA_PLAYER_SETTING = - "android.bluetooth.avrcp-controller.profile.extra.PLAYER_SETTING"; - - private final BluetoothAdapter mAdapter; - private final AttributionSource mAttributionSource; - private final BluetoothProfileConnector mProfileConnector = - new BluetoothProfileConnector(this, BluetoothProfile.AVRCP_CONTROLLER, - "BluetoothAvrcpController", IBluetoothAvrcpController.class.getName()) { - @Override - public IBluetoothAvrcpController getServiceInterface(IBinder service) { - return IBluetoothAvrcpController.Stub.asInterface(service); - } - }; - - /** - * Create a BluetoothAvrcpController proxy object for interacting with the local - * Bluetooth AVRCP service. - */ - /* package */ BluetoothAvrcpController(Context context, ServiceListener listener, - BluetoothAdapter adapter) { - mAdapter = adapter; - mAttributionSource = adapter.getAttributionSource(); - mProfileConnector.connect(context, listener); - } - - /*package*/ void close() { - mProfileConnector.disconnect(); - } - - private IBluetoothAvrcpController getService() { - return mProfileConnector.getService(); - } - - @Override - public void finalize() { - close(); - } - - /** - * {@inheritDoc} - */ - @Override - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public List getConnectedDevices() { - if (VDBG) log("getConnectedDevices()"); - final IBluetoothAvrcpController service = getService(); - final List defaultValue = new ArrayList(); - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled()) { - try { - final SynchronousResultReceiver> recv = - new SynchronousResultReceiver(); - service.getConnectedDevices(mAttributionSource, recv); - return Attributable.setAttributionSource( - recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue), - mAttributionSource); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * {@inheritDoc} - */ - @Override - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public List getDevicesMatchingConnectionStates(int[] states) { - if (VDBG) log("getDevicesMatchingStates()"); - final IBluetoothAvrcpController service = getService(); - final List defaultValue = new ArrayList(); - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled()) { - try { - final SynchronousResultReceiver> recv = - new SynchronousResultReceiver(); - service.getDevicesMatchingConnectionStates(states, mAttributionSource, recv); - return Attributable.setAttributionSource( - recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue), - mAttributionSource); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * {@inheritDoc} - */ - @Override - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public int getConnectionState(BluetoothDevice device) { - if (VDBG) log("getState(" + device + ")"); - final IBluetoothAvrcpController service = getService(); - final int defaultValue = BluetoothProfile.STATE_DISCONNECTED; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device)) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.getConnectionState(device, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Gets the player application settings. - * - * @return the {@link BluetoothAvrcpPlayerSettings} or {@link null} if there is an error. - */ - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public BluetoothAvrcpPlayerSettings getPlayerSettings(BluetoothDevice device) { - if (DBG) Log.d(TAG, "getPlayerSettings"); - BluetoothAvrcpPlayerSettings settings = null; - final IBluetoothAvrcpController service = getService(); - final BluetoothAvrcpPlayerSettings defaultValue = null; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled()) { - try { - final SynchronousResultReceiver recv = - new SynchronousResultReceiver(); - service.getPlayerSettings(device, mAttributionSource, recv); - settings = recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Sets the player app setting for current player. - * returns true in case setting is supported by remote, false otherwise - */ - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public boolean setPlayerApplicationSetting(BluetoothAvrcpPlayerSettings plAppSetting) { - if (DBG) Log.d(TAG, "setPlayerApplicationSetting"); - final IBluetoothAvrcpController service = getService(); - final boolean defaultValue = false; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled()) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.setPlayerApplicationSetting(plAppSetting, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Send Group Navigation Command to Remote. - * possible keycode values: next_grp, previous_grp defined above - */ - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public void sendGroupNavigationCmd(BluetoothDevice device, int keyCode, int keyState) { - Log.d(TAG, "sendGroupNavigationCmd dev = " + device + " key " + keyCode + " State = " - + keyState); - final IBluetoothAvrcpController service = getService(); - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled()) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.sendGroupNavigationCmd(device, keyCode, keyState, mAttributionSource, recv); - recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(null); - return; - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - } - - private boolean isEnabled() { - return mAdapter.getState() == BluetoothAdapter.STATE_ON; - } - - private static boolean isValidDevice(BluetoothDevice device) { - return device != null && BluetoothAdapter.checkBluetoothAddress(device.getAddress()); - } - - private static void log(String msg) { - Log.d(TAG, msg); - } -} diff --git a/core/java/android/bluetooth/BluetoothAvrcpPlayerSettings.java b/core/java/android/bluetooth/BluetoothAvrcpPlayerSettings.java deleted file mode 100644 index 30aea1abf73ce4bc316510efcb5bdc5b4fdd7a42..0000000000000000000000000000000000000000 --- a/core/java/android/bluetooth/BluetoothAvrcpPlayerSettings.java +++ /dev/null @@ -1,193 +0,0 @@ -/* - * 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.bluetooth; - -import android.os.Parcel; -import android.os.Parcelable; -import android.util.Log; - -import java.util.HashMap; -import java.util.Map; - -/** - * Class used to identify settings associated with the player on AG. - * - * {@hide} - */ -public final class BluetoothAvrcpPlayerSettings implements Parcelable { - public static final String TAG = "BluetoothAvrcpPlayerSettings"; - - /** - * Equalizer setting. - */ - public static final int SETTING_EQUALIZER = 0x01; - - /** - * Repeat setting. - */ - public static final int SETTING_REPEAT = 0x02; - - /** - * Shuffle setting. - */ - public static final int SETTING_SHUFFLE = 0x04; - - /** - * Scan mode setting. - */ - public static final int SETTING_SCAN = 0x08; - - /** - * Invalid state. - * - * Used for returning error codes. - */ - public static final int STATE_INVALID = -1; - - /** - * OFF state. - * - * Denotes a general OFF state. Applies to all settings. - */ - public static final int STATE_OFF = 0x00; - - /** - * ON state. - * - * Applies to {@link SETTING_EQUALIZER}. - */ - public static final int STATE_ON = 0x01; - - /** - * Single track repeat. - * - * Applies only to {@link SETTING_REPEAT}. - */ - public static final int STATE_SINGLE_TRACK = 0x02; - - /** - * All track repeat/shuffle. - * - * Applies to {@link #SETTING_REPEAT}, {@link #SETTING_SHUFFLE} and {@link #SETTING_SCAN}. - */ - public static final int STATE_ALL_TRACK = 0x03; - - /** - * Group repeat/shuffle. - * - * Applies to {@link #SETTING_REPEAT}, {@link #SETTING_SHUFFLE} and {@link #SETTING_SCAN}. - */ - public static final int STATE_GROUP = 0x04; - - /** - * List of supported settings ORed. - */ - private int mSettings; - - /** - * Hash map of current capability values. - */ - private Map mSettingsValue = new HashMap(); - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel out, int flags) { - out.writeInt(mSettings); - out.writeInt(mSettingsValue.size()); - for (int k : mSettingsValue.keySet()) { - out.writeInt(k); - out.writeInt(mSettingsValue.get(k)); - } - } - - public static final @android.annotation.NonNull Parcelable.Creator CREATOR = - new Parcelable.Creator() { - public BluetoothAvrcpPlayerSettings createFromParcel(Parcel in) { - return new BluetoothAvrcpPlayerSettings(in); - } - - public BluetoothAvrcpPlayerSettings[] newArray(int size) { - return new BluetoothAvrcpPlayerSettings[size]; - } - }; - - private BluetoothAvrcpPlayerSettings(Parcel in) { - mSettings = in.readInt(); - int numSettings = in.readInt(); - for (int i = 0; i < numSettings; i++) { - mSettingsValue.put(in.readInt(), in.readInt()); - } - } - - /** - * Create a new player settings object. - * - * @param settings a ORed value of SETTINGS_* defined above. - */ - public BluetoothAvrcpPlayerSettings(int settings) { - mSettings = settings; - } - - /** - * Get the supported settings. - * - * @return int ORed value of supported settings. - */ - public int getSettings() { - return mSettings; - } - - /** - * Add a setting value. - * - * The setting must be part of possible settings in {@link getSettings()}. - * - * @param setting setting config. - * @param value value for the setting. - * @throws IllegalStateException if the setting is not supported. - */ - public void addSettingValue(int setting, int value) { - if ((setting & mSettings) == 0) { - Log.e(TAG, "Setting not supported: " + setting + " " + mSettings); - throw new IllegalStateException("Setting not supported: " + setting); - } - mSettingsValue.put(setting, value); - } - - /** - * Get a setting value. - * - * The setting must be part of possible settings in {@link getSettings()}. - * - * @param setting setting config. - * @return value value for the setting. - * @throws IllegalStateException if the setting is not supported. - */ - public int getSettingValue(int setting) { - if ((setting & mSettings) == 0) { - Log.e(TAG, "Setting not supported: " + setting + " " + mSettings); - throw new IllegalStateException("Setting not supported: " + setting); - } - Integer i = mSettingsValue.get(setting); - if (i == null) return -1; - return i; - } -} diff --git a/core/java/android/bluetooth/BluetoothClass.java b/core/java/android/bluetooth/BluetoothClass.java deleted file mode 100755 index 8535b4fd2839b35e43b6043156452f0ff28832f0..0000000000000000000000000000000000000000 --- a/core/java/android/bluetooth/BluetoothClass.java +++ /dev/null @@ -1,441 +0,0 @@ -/* - * 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.bluetooth; - -import android.annotation.Nullable; -import android.annotation.TestApi; -import android.compat.annotation.UnsupportedAppUsage; -import android.os.Build; -import android.os.Parcel; -import android.os.Parcelable; - -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.util.Arrays; - -/** - * Represents a Bluetooth class, which describes general characteristics - * and capabilities of a device. For example, a Bluetooth class will - * specify the general device type such as a phone, a computer, or - * headset, and whether it's capable of services such as audio or telephony. - * - *

Every Bluetooth class is composed of zero or more service classes, and - * exactly one device class. The device class is further broken down into major - * and minor device class components. - * - *

{@link BluetoothClass} is useful as a hint to roughly describe a device - * (for example to show an icon in the UI), but does not reliably describe which - * Bluetooth profiles or services are actually supported by a device. Accurate - * service discovery is done through SDP requests, which are automatically - * performed when creating an RFCOMM socket with {@link - * BluetoothDevice#createRfcommSocketToServiceRecord} and {@link - * BluetoothAdapter#listenUsingRfcommWithServiceRecord}

- * - *

Use {@link BluetoothDevice#getBluetoothClass} to retrieve the class for - * a remote device. - * - * - */ -public final class BluetoothClass implements Parcelable { - /** - * Legacy error value. Applications should use null instead. - * - * @hide - */ - public static final int ERROR = 0xFF000000; - - private final int mClass; - - /** @hide */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) - public BluetoothClass(int classInt) { - mClass = classInt; - } - - @Override - public boolean equals(@Nullable Object o) { - if (o instanceof BluetoothClass) { - return mClass == ((BluetoothClass) o).mClass; - } - return false; - } - - @Override - public int hashCode() { - return mClass; - } - - @Override - public String toString() { - return Integer.toHexString(mClass); - } - - @Override - public int describeContents() { - return 0; - } - - public static final @android.annotation.NonNull Parcelable.Creator CREATOR = - new Parcelable.Creator() { - public BluetoothClass createFromParcel(Parcel in) { - return new BluetoothClass(in.readInt()); - } - - public BluetoothClass[] newArray(int size) { - return new BluetoothClass[size]; - } - }; - - @Override - public void writeToParcel(Parcel out, int flags) { - out.writeInt(mClass); - } - - /** - * Defines all service class constants. - *

Each {@link BluetoothClass} encodes zero or more service classes. - */ - public static final class Service { - private static final int BITMASK = 0xFFE000; - - public static final int LIMITED_DISCOVERABILITY = 0x002000; - public static final int LE_AUDIO = 0x004000; - public static final int POSITIONING = 0x010000; - public static final int NETWORKING = 0x020000; - public static final int RENDER = 0x040000; - public static final int CAPTURE = 0x080000; - public static final int OBJECT_TRANSFER = 0x100000; - public static final int AUDIO = 0x200000; - public static final int TELEPHONY = 0x400000; - public static final int INFORMATION = 0x800000; - } - - /** - * Return true if the specified service class is supported by this - * {@link BluetoothClass}. - *

Valid service classes are the public constants in - * {@link BluetoothClass.Service}. For example, {@link - * BluetoothClass.Service#AUDIO}. - * - * @param service valid service class - * @return true if the service class is supported - */ - public boolean hasService(int service) { - return ((mClass & Service.BITMASK & service) != 0); - } - - /** - * Defines all device class constants. - *

Each {@link BluetoothClass} encodes exactly one device class, with - * major and minor components. - *

The constants in {@link - * BluetoothClass.Device} represent a combination of major and minor - * device components (the complete device class). The constants in {@link - * BluetoothClass.Device.Major} represent only major device classes. - *

See {@link BluetoothClass.Service} for service class constants. - */ - public static class Device { - private static final int BITMASK = 0x1FFC; - - /** - * Defines all major device class constants. - *

See {@link BluetoothClass.Device} for minor classes. - */ - public static class Major { - private static final int BITMASK = 0x1F00; - - public static final int MISC = 0x0000; - public static final int COMPUTER = 0x0100; - public static final int PHONE = 0x0200; - public static final int NETWORKING = 0x0300; - public static final int AUDIO_VIDEO = 0x0400; - public static final int PERIPHERAL = 0x0500; - public static final int IMAGING = 0x0600; - public static final int WEARABLE = 0x0700; - public static final int TOY = 0x0800; - public static final int HEALTH = 0x0900; - public static final int UNCATEGORIZED = 0x1F00; - } - - // Devices in the COMPUTER major class - public static final int COMPUTER_UNCATEGORIZED = 0x0100; - public static final int COMPUTER_DESKTOP = 0x0104; - public static final int COMPUTER_SERVER = 0x0108; - public static final int COMPUTER_LAPTOP = 0x010C; - public static final int COMPUTER_HANDHELD_PC_PDA = 0x0110; - public static final int COMPUTER_PALM_SIZE_PC_PDA = 0x0114; - public static final int COMPUTER_WEARABLE = 0x0118; - - // Devices in the PHONE major class - public static final int PHONE_UNCATEGORIZED = 0x0200; - public static final int PHONE_CELLULAR = 0x0204; - public static final int PHONE_CORDLESS = 0x0208; - public static final int PHONE_SMART = 0x020C; - public static final int PHONE_MODEM_OR_GATEWAY = 0x0210; - public static final int PHONE_ISDN = 0x0214; - - // Minor classes for the AUDIO_VIDEO major class - public static final int AUDIO_VIDEO_UNCATEGORIZED = 0x0400; - public static final int AUDIO_VIDEO_WEARABLE_HEADSET = 0x0404; - public static final int AUDIO_VIDEO_HANDSFREE = 0x0408; - //public static final int AUDIO_VIDEO_RESERVED = 0x040C; - public static final int AUDIO_VIDEO_MICROPHONE = 0x0410; - public static final int AUDIO_VIDEO_LOUDSPEAKER = 0x0414; - public static final int AUDIO_VIDEO_HEADPHONES = 0x0418; - public static final int AUDIO_VIDEO_PORTABLE_AUDIO = 0x041C; - public static final int AUDIO_VIDEO_CAR_AUDIO = 0x0420; - public static final int AUDIO_VIDEO_SET_TOP_BOX = 0x0424; - public static final int AUDIO_VIDEO_HIFI_AUDIO = 0x0428; - public static final int AUDIO_VIDEO_VCR = 0x042C; - public static final int AUDIO_VIDEO_VIDEO_CAMERA = 0x0430; - public static final int AUDIO_VIDEO_CAMCORDER = 0x0434; - public static final int AUDIO_VIDEO_VIDEO_MONITOR = 0x0438; - public static final int AUDIO_VIDEO_VIDEO_DISPLAY_AND_LOUDSPEAKER = 0x043C; - public static final int AUDIO_VIDEO_VIDEO_CONFERENCING = 0x0440; - //public static final int AUDIO_VIDEO_RESERVED = 0x0444; - public static final int AUDIO_VIDEO_VIDEO_GAMING_TOY = 0x0448; - - // Devices in the WEARABLE major class - public static final int WEARABLE_UNCATEGORIZED = 0x0700; - public static final int WEARABLE_WRIST_WATCH = 0x0704; - public static final int WEARABLE_PAGER = 0x0708; - public static final int WEARABLE_JACKET = 0x070C; - public static final int WEARABLE_HELMET = 0x0710; - public static final int WEARABLE_GLASSES = 0x0714; - - // Devices in the TOY major class - public static final int TOY_UNCATEGORIZED = 0x0800; - public static final int TOY_ROBOT = 0x0804; - public static final int TOY_VEHICLE = 0x0808; - public static final int TOY_DOLL_ACTION_FIGURE = 0x080C; - public static final int TOY_CONTROLLER = 0x0810; - public static final int TOY_GAME = 0x0814; - - // Devices in the HEALTH major class - public static final int HEALTH_UNCATEGORIZED = 0x0900; - public static final int HEALTH_BLOOD_PRESSURE = 0x0904; - public static final int HEALTH_THERMOMETER = 0x0908; - public static final int HEALTH_WEIGHING = 0x090C; - public static final int HEALTH_GLUCOSE = 0x0910; - public static final int HEALTH_PULSE_OXIMETER = 0x0914; - public static final int HEALTH_PULSE_RATE = 0x0918; - public static final int HEALTH_DATA_DISPLAY = 0x091C; - - // Devices in PERIPHERAL major class - /** - * @hide - */ - public static final int PERIPHERAL_NON_KEYBOARD_NON_POINTING = 0x0500; - /** - * @hide - */ - public static final int PERIPHERAL_KEYBOARD = 0x0540; - /** - * @hide - */ - public static final int PERIPHERAL_POINTING = 0x0580; - /** - * @hide - */ - public static final int PERIPHERAL_KEYBOARD_POINTING = 0x05C0; - } - - /** - * Return the major device class component of this {@link BluetoothClass}. - *

Values returned from this function can be compared with the - * public constants in {@link BluetoothClass.Device.Major} to determine - * which major class is encoded in this Bluetooth class. - * - * @return major device class component - */ - public int getMajorDeviceClass() { - return (mClass & Device.Major.BITMASK); - } - - /** - * Return the (major and minor) device class component of this - * {@link BluetoothClass}. - *

Values returned from this function can be compared with the - * public constants in {@link BluetoothClass.Device} to determine which - * device class is encoded in this Bluetooth class. - * - * @return device class component - */ - public int getDeviceClass() { - return (mClass & Device.BITMASK); - } - - /** - * Return the Bluetooth Class of Device (CoD) value including the - * {@link BluetoothClass.Service}, {@link BluetoothClass.Device.Major} and - * minor device fields. - * - *

This value is an integer representation of Bluetooth CoD as in - * Bluetooth specification. - * - * @see https://www.bluetooth.com/specifications/assigned-numbers/baseband - * - * @hide - */ - @TestApi - public int getClassOfDevice() { - return mClass; - } - - /** - * Return the Bluetooth Class of Device (CoD) value including the - * {@link BluetoothClass.Service}, {@link BluetoothClass.Device.Major} and - * minor device fields. - * - *

This value is a byte array representation of Bluetooth CoD as in - * Bluetooth specification. - * - *

Bluetooth COD information is 3 bytes, but stored as an int. Hence the - * MSB is useless and needs to be thrown away. The lower 3 bytes are - * converted into a byte array MSB to LSB. Hence, using BIG_ENDIAN. - * - * @see https://www.bluetooth.com/specifications/assigned-numbers/baseband - * - * @hide - */ - public byte[] getClassOfDeviceBytes() { - byte[] bytes = ByteBuffer.allocate(4) - .order(ByteOrder.BIG_ENDIAN) - .putInt(mClass) - .array(); - - // Discard the top byte - return Arrays.copyOfRange(bytes, 1, bytes.length); - } - - /** @hide */ - @UnsupportedAppUsage - public static final int PROFILE_HEADSET = 0; - /** @hide */ - @UnsupportedAppUsage - public static final int PROFILE_A2DP = 1; - /** @hide */ - public static final int PROFILE_OPP = 2; - /** @hide */ - public static final int PROFILE_HID = 3; - /** @hide */ - public static final int PROFILE_PANU = 4; - /** @hide */ - public static final int PROFILE_NAP = 5; - /** @hide */ - public static final int PROFILE_A2DP_SINK = 6; - - /** - * Check class bits for possible bluetooth profile support. - * This is a simple heuristic that tries to guess if a device with the - * given class bits might support specified profile. It is not accurate for all - * devices. It tries to err on the side of false positives. - * - * @param profile The profile to be checked - * @return True if this device might support specified profile. - * @hide - */ - @UnsupportedAppUsage - public boolean doesClassMatch(int profile) { - if (profile == PROFILE_A2DP) { - if (hasService(Service.RENDER)) { - return true; - } - // By the A2DP spec, sinks must indicate the RENDER service. - // However we found some that do not (Chordette). So lets also - // match on some other class bits. - switch (getDeviceClass()) { - case Device.AUDIO_VIDEO_HIFI_AUDIO: - case Device.AUDIO_VIDEO_HEADPHONES: - case Device.AUDIO_VIDEO_LOUDSPEAKER: - case Device.AUDIO_VIDEO_CAR_AUDIO: - return true; - default: - return false; - } - } else if (profile == PROFILE_A2DP_SINK) { - if (hasService(Service.CAPTURE)) { - return true; - } - // By the A2DP spec, srcs must indicate the CAPTURE service. - // However if some device that do not, we try to - // match on some other class bits. - switch (getDeviceClass()) { - case Device.AUDIO_VIDEO_HIFI_AUDIO: - case Device.AUDIO_VIDEO_SET_TOP_BOX: - case Device.AUDIO_VIDEO_VCR: - return true; - default: - return false; - } - } else if (profile == PROFILE_HEADSET) { - // The render service class is required by the spec for HFP, so is a - // pretty good signal - if (hasService(Service.RENDER)) { - return true; - } - // Just in case they forgot the render service class - switch (getDeviceClass()) { - case Device.AUDIO_VIDEO_HANDSFREE: - case Device.AUDIO_VIDEO_WEARABLE_HEADSET: - case Device.AUDIO_VIDEO_CAR_AUDIO: - return true; - default: - return false; - } - } else if (profile == PROFILE_OPP) { - if (hasService(Service.OBJECT_TRANSFER)) { - return true; - } - - switch (getDeviceClass()) { - case Device.COMPUTER_UNCATEGORIZED: - case Device.COMPUTER_DESKTOP: - case Device.COMPUTER_SERVER: - case Device.COMPUTER_LAPTOP: - case Device.COMPUTER_HANDHELD_PC_PDA: - case Device.COMPUTER_PALM_SIZE_PC_PDA: - case Device.COMPUTER_WEARABLE: - case Device.PHONE_UNCATEGORIZED: - case Device.PHONE_CELLULAR: - case Device.PHONE_CORDLESS: - case Device.PHONE_SMART: - case Device.PHONE_MODEM_OR_GATEWAY: - case Device.PHONE_ISDN: - return true; - default: - return false; - } - } else if (profile == PROFILE_HID) { - return getMajorDeviceClass() == Device.Major.PERIPHERAL; - } else if (profile == PROFILE_PANU || profile == PROFILE_NAP) { - // No good way to distinguish between the two, based on class bits. - if (hasService(Service.NETWORKING)) { - return true; - } - return getMajorDeviceClass() == Device.Major.NETWORKING; - } else { - return false; - } - } -} diff --git a/core/java/android/bluetooth/BluetoothCodecConfig.java b/core/java/android/bluetooth/BluetoothCodecConfig.java deleted file mode 100644 index 9a4151adffc76dbd9e8f550df986cb5a93075114..0000000000000000000000000000000000000000 --- a/core/java/android/bluetooth/BluetoothCodecConfig.java +++ /dev/null @@ -1,807 +0,0 @@ -/* - * Copyright (C) 2016 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.bluetooth; - -import android.annotation.IntDef; -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.compat.annotation.UnsupportedAppUsage; -import android.os.Parcel; -import android.os.Parcelable; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.util.Objects; - -/** - * Represents the codec configuration for a Bluetooth A2DP source device. - *

Contains the source codec type, the codec priority, the codec sample - * rate, the codec bits per sample, and the codec channel mode. - *

The source codec type values are the same as those supported by the - * device hardware. - * - * {@see BluetoothA2dp} - */ -public final class BluetoothCodecConfig implements Parcelable { - /** @hide */ - @IntDef(prefix = "SOURCE_CODEC_TYPE_", value = { - SOURCE_CODEC_TYPE_SBC, - SOURCE_CODEC_TYPE_AAC, - SOURCE_CODEC_TYPE_APTX, - SOURCE_CODEC_TYPE_APTX_HD, - SOURCE_CODEC_TYPE_LDAC, - SOURCE_CODEC_TYPE_INVALID - }) - @Retention(RetentionPolicy.SOURCE) - public @interface SourceCodecType {} - - /** - * Source codec type SBC. This is the mandatory source codec - * type. - */ - public static final int SOURCE_CODEC_TYPE_SBC = 0; - - /** - * Source codec type AAC. - */ - public static final int SOURCE_CODEC_TYPE_AAC = 1; - - /** - * Source codec type APTX. - */ - public static final int SOURCE_CODEC_TYPE_APTX = 2; - - /** - * Source codec type APTX HD. - */ - public static final int SOURCE_CODEC_TYPE_APTX_HD = 3; - - /** - * Source codec type LDAC. - */ - public static final int SOURCE_CODEC_TYPE_LDAC = 4; - - /** - * Source codec type invalid. This is the default value used for codec - * type. - */ - public static final int SOURCE_CODEC_TYPE_INVALID = 1000 * 1000; - - /** - * Represents the count of valid source codec types. Can be accessed via - * {@link #getMaxCodecType}. - */ - private static final int SOURCE_CODEC_TYPE_MAX = 5; - - /** @hide */ - @IntDef(prefix = "CODEC_PRIORITY_", value = { - CODEC_PRIORITY_DISABLED, - CODEC_PRIORITY_DEFAULT, - CODEC_PRIORITY_HIGHEST - }) - @Retention(RetentionPolicy.SOURCE) - public @interface CodecPriority {} - - /** - * Codec priority disabled. - * Used to indicate that this codec is disabled and should not be used. - */ - public static final int CODEC_PRIORITY_DISABLED = -1; - - /** - * Codec priority default. - * Default value used for codec priority. - */ - public static final int CODEC_PRIORITY_DEFAULT = 0; - - /** - * Codec priority highest. - * Used to indicate the highest priority a codec can have. - */ - public static final int CODEC_PRIORITY_HIGHEST = 1000 * 1000; - - /** @hide */ - @IntDef(prefix = "SAMPLE_RATE_", value = { - SAMPLE_RATE_NONE, - SAMPLE_RATE_44100, - SAMPLE_RATE_48000, - SAMPLE_RATE_88200, - SAMPLE_RATE_96000, - SAMPLE_RATE_176400, - SAMPLE_RATE_192000 - }) - @Retention(RetentionPolicy.SOURCE) - public @interface SampleRate {} - - /** - * Codec sample rate 0 Hz. Default value used for - * codec sample rate. - */ - public static final int SAMPLE_RATE_NONE = 0; - - /** - * Codec sample rate 44100 Hz. - */ - public static final int SAMPLE_RATE_44100 = 0x1 << 0; - - /** - * Codec sample rate 48000 Hz. - */ - public static final int SAMPLE_RATE_48000 = 0x1 << 1; - - /** - * Codec sample rate 88200 Hz. - */ - public static final int SAMPLE_RATE_88200 = 0x1 << 2; - - /** - * Codec sample rate 96000 Hz. - */ - public static final int SAMPLE_RATE_96000 = 0x1 << 3; - - /** - * Codec sample rate 176400 Hz. - */ - public static final int SAMPLE_RATE_176400 = 0x1 << 4; - - /** - * Codec sample rate 192000 Hz. - */ - public static final int SAMPLE_RATE_192000 = 0x1 << 5; - - /** @hide */ - @IntDef(prefix = "BITS_PER_SAMPLE_", value = { - BITS_PER_SAMPLE_NONE, - BITS_PER_SAMPLE_16, - BITS_PER_SAMPLE_24, - BITS_PER_SAMPLE_32 - }) - @Retention(RetentionPolicy.SOURCE) - public @interface BitsPerSample {} - - /** - * Codec bits per sample 0. Default value of the codec - * bits per sample. - */ - public static final int BITS_PER_SAMPLE_NONE = 0; - - /** - * Codec bits per sample 16. - */ - public static final int BITS_PER_SAMPLE_16 = 0x1 << 0; - - /** - * Codec bits per sample 24. - */ - public static final int BITS_PER_SAMPLE_24 = 0x1 << 1; - - /** - * Codec bits per sample 32. - */ - public static final int BITS_PER_SAMPLE_32 = 0x1 << 2; - - /** @hide */ - @IntDef(prefix = "CHANNEL_MODE_", value = { - CHANNEL_MODE_NONE, - CHANNEL_MODE_MONO, - CHANNEL_MODE_STEREO - }) - @Retention(RetentionPolicy.SOURCE) - public @interface ChannelMode {} - - /** - * Codec channel mode NONE. Default value of the - * codec channel mode. - */ - public static final int CHANNEL_MODE_NONE = 0; - - /** - * Codec channel mode MONO. - */ - public static final int CHANNEL_MODE_MONO = 0x1 << 0; - - /** - * Codec channel mode STEREO. - */ - public static final int CHANNEL_MODE_STEREO = 0x1 << 1; - - private final @SourceCodecType int mCodecType; - private @CodecPriority int mCodecPriority; - private final @SampleRate int mSampleRate; - private final @BitsPerSample int mBitsPerSample; - private final @ChannelMode int mChannelMode; - private final long mCodecSpecific1; - private final long mCodecSpecific2; - private final long mCodecSpecific3; - private final long mCodecSpecific4; - - /** - * Creates a new BluetoothCodecConfig. - * - * @param codecType the source codec type - * @param codecPriority the priority of this codec - * @param sampleRate the codec sample rate - * @param bitsPerSample the bits per sample of this codec - * @param channelMode the channel mode of this codec - * @param codecSpecific1 the specific value 1 - * @param codecSpecific2 the specific value 2 - * @param codecSpecific3 the specific value 3 - * @param codecSpecific4 the specific value 4 - * values to 0. - * @hide - */ - @UnsupportedAppUsage - public BluetoothCodecConfig(@SourceCodecType int codecType, @CodecPriority int codecPriority, - @SampleRate int sampleRate, @BitsPerSample int bitsPerSample, - @ChannelMode int channelMode, long codecSpecific1, - long codecSpecific2, long codecSpecific3, - long codecSpecific4) { - mCodecType = codecType; - mCodecPriority = codecPriority; - mSampleRate = sampleRate; - mBitsPerSample = bitsPerSample; - mChannelMode = channelMode; - mCodecSpecific1 = codecSpecific1; - mCodecSpecific2 = codecSpecific2; - mCodecSpecific3 = codecSpecific3; - mCodecSpecific4 = codecSpecific4; - } - - /** - * Creates a new BluetoothCodecConfig. - *

By default, the codec priority will be set - * to {@link BluetoothCodecConfig#CODEC_PRIORITY_DEFAULT}, the sample rate to - * {@link BluetoothCodecConfig#SAMPLE_RATE_NONE}, the bits per sample to - * {@link BluetoothCodecConfig#BITS_PER_SAMPLE_NONE}, the channel mode to - * {@link BluetoothCodecConfig#CHANNEL_MODE_NONE}, and all the codec specific - * values to 0. - * - * @param codecType the source codec type - */ - public BluetoothCodecConfig(@SourceCodecType int codecType) { - this(codecType, BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, - BluetoothCodecConfig.SAMPLE_RATE_NONE, - BluetoothCodecConfig.BITS_PER_SAMPLE_NONE, - BluetoothCodecConfig.CHANNEL_MODE_NONE, 0, 0, 0, 0); - } - - private BluetoothCodecConfig(Parcel in) { - mCodecType = in.readInt(); - mCodecPriority = in.readInt(); - mSampleRate = in.readInt(); - mBitsPerSample = in.readInt(); - mChannelMode = in.readInt(); - mCodecSpecific1 = in.readLong(); - mCodecSpecific2 = in.readLong(); - mCodecSpecific3 = in.readLong(); - mCodecSpecific4 = in.readLong(); - } - - @Override - public boolean equals(@Nullable Object o) { - if (o instanceof BluetoothCodecConfig) { - BluetoothCodecConfig other = (BluetoothCodecConfig) o; - return (other.mCodecType == mCodecType - && other.mCodecPriority == mCodecPriority - && other.mSampleRate == mSampleRate - && other.mBitsPerSample == mBitsPerSample - && other.mChannelMode == mChannelMode - && other.mCodecSpecific1 == mCodecSpecific1 - && other.mCodecSpecific2 == mCodecSpecific2 - && other.mCodecSpecific3 == mCodecSpecific3 - && other.mCodecSpecific4 == mCodecSpecific4); - } - return false; - } - - /** - * Returns a hash representation of this BluetoothCodecConfig - * based on all the config values. - */ - @Override - public int hashCode() { - return Objects.hash(mCodecType, mCodecPriority, mSampleRate, - mBitsPerSample, mChannelMode, mCodecSpecific1, - mCodecSpecific2, mCodecSpecific3, mCodecSpecific4); - } - - /** - * Adds capability string to an existing string. - * - * @param prevStr the previous string with the capabilities. Can be a {@code null} pointer - * @param capStr the capability string to append to prevStr argument - * @return the result string in the form "prevStr|capStr" - */ - private static String appendCapabilityToString(@Nullable String prevStr, - @NonNull String capStr) { - if (prevStr == null) { - return capStr; - } - return prevStr + "|" + capStr; - } - - /** - * Returns a {@link String} that describes each BluetoothCodecConfig parameter - * current value. - */ - @Override - public String toString() { - String sampleRateStr = null; - if (mSampleRate == SAMPLE_RATE_NONE) { - sampleRateStr = appendCapabilityToString(sampleRateStr, "NONE"); - } - if ((mSampleRate & SAMPLE_RATE_44100) != 0) { - sampleRateStr = appendCapabilityToString(sampleRateStr, "44100"); - } - if ((mSampleRate & SAMPLE_RATE_48000) != 0) { - sampleRateStr = appendCapabilityToString(sampleRateStr, "48000"); - } - if ((mSampleRate & SAMPLE_RATE_88200) != 0) { - sampleRateStr = appendCapabilityToString(sampleRateStr, "88200"); - } - if ((mSampleRate & SAMPLE_RATE_96000) != 0) { - sampleRateStr = appendCapabilityToString(sampleRateStr, "96000"); - } - if ((mSampleRate & SAMPLE_RATE_176400) != 0) { - sampleRateStr = appendCapabilityToString(sampleRateStr, "176400"); - } - if ((mSampleRate & SAMPLE_RATE_192000) != 0) { - sampleRateStr = appendCapabilityToString(sampleRateStr, "192000"); - } - - String bitsPerSampleStr = null; - if (mBitsPerSample == BITS_PER_SAMPLE_NONE) { - bitsPerSampleStr = appendCapabilityToString(bitsPerSampleStr, "NONE"); - } - if ((mBitsPerSample & BITS_PER_SAMPLE_16) != 0) { - bitsPerSampleStr = appendCapabilityToString(bitsPerSampleStr, "16"); - } - if ((mBitsPerSample & BITS_PER_SAMPLE_24) != 0) { - bitsPerSampleStr = appendCapabilityToString(bitsPerSampleStr, "24"); - } - if ((mBitsPerSample & BITS_PER_SAMPLE_32) != 0) { - bitsPerSampleStr = appendCapabilityToString(bitsPerSampleStr, "32"); - } - - String channelModeStr = null; - if (mChannelMode == CHANNEL_MODE_NONE) { - channelModeStr = appendCapabilityToString(channelModeStr, "NONE"); - } - if ((mChannelMode & CHANNEL_MODE_MONO) != 0) { - channelModeStr = appendCapabilityToString(channelModeStr, "MONO"); - } - if ((mChannelMode & CHANNEL_MODE_STEREO) != 0) { - channelModeStr = appendCapabilityToString(channelModeStr, "STEREO"); - } - - return "{codecName:" + getCodecName() - + ",mCodecType:" + mCodecType - + ",mCodecPriority:" + mCodecPriority - + ",mSampleRate:" + String.format("0x%x", mSampleRate) - + "(" + sampleRateStr + ")" - + ",mBitsPerSample:" + String.format("0x%x", mBitsPerSample) - + "(" + bitsPerSampleStr + ")" - + ",mChannelMode:" + String.format("0x%x", mChannelMode) - + "(" + channelModeStr + ")" - + ",mCodecSpecific1:" + mCodecSpecific1 - + ",mCodecSpecific2:" + mCodecSpecific2 - + ",mCodecSpecific3:" + mCodecSpecific3 - + ",mCodecSpecific4:" + mCodecSpecific4 + "}"; - } - - /** - * @return 0 - * @hide - */ - @Override - public int describeContents() { - return 0; - } - - public static final @android.annotation.NonNull Parcelable.Creator CREATOR = - new Parcelable.Creator() { - public BluetoothCodecConfig createFromParcel(Parcel in) { - return new BluetoothCodecConfig(in); - } - - public BluetoothCodecConfig[] newArray(int size) { - return new BluetoothCodecConfig[size]; - } - }; - - /** - * Flattens the object to a parcel - * - * @param out The Parcel in which the object should be written - * @param flags Additional flags about how the object should be written - * - * @hide - */ - @Override - public void writeToParcel(Parcel out, int flags) { - out.writeInt(mCodecType); - out.writeInt(mCodecPriority); - out.writeInt(mSampleRate); - out.writeInt(mBitsPerSample); - out.writeInt(mChannelMode); - out.writeLong(mCodecSpecific1); - out.writeLong(mCodecSpecific2); - out.writeLong(mCodecSpecific3); - out.writeLong(mCodecSpecific4); - } - - /** - * Returns the codec name converted to {@link String}. - * @hide - */ - public @NonNull String getCodecName() { - switch (mCodecType) { - case SOURCE_CODEC_TYPE_SBC: - return "SBC"; - case SOURCE_CODEC_TYPE_AAC: - return "AAC"; - case SOURCE_CODEC_TYPE_APTX: - return "aptX"; - case SOURCE_CODEC_TYPE_APTX_HD: - return "aptX HD"; - case SOURCE_CODEC_TYPE_LDAC: - return "LDAC"; - case SOURCE_CODEC_TYPE_INVALID: - return "INVALID CODEC"; - default: - break; - } - return "UNKNOWN CODEC(" + mCodecType + ")"; - } - - /** - * Returns the source codec type of this config. - */ - public @SourceCodecType int getCodecType() { - return mCodecType; - } - - /** - * Returns the valid codec types count. - */ - public static int getMaxCodecType() { - return SOURCE_CODEC_TYPE_MAX; - } - - /** - * Checks whether the codec is mandatory. - *

The actual mandatory codec type for Android Bluetooth audio is SBC. - * See {@link #SOURCE_CODEC_TYPE_SBC}. - * - * @return {@code true} if the codec is mandatory, {@code false} otherwise - * @hide - */ - public boolean isMandatoryCodec() { - return mCodecType == SOURCE_CODEC_TYPE_SBC; - } - - /** - * Returns the codec selection priority. - *

The codec selection priority is relative to other codecs: larger value - * means higher priority. - */ - public @CodecPriority int getCodecPriority() { - return mCodecPriority; - } - - /** - * Sets the codec selection priority. - *

The codec selection priority is relative to other codecs: larger value - * means higher priority. - * - * @param codecPriority the priority this codec should have - * @hide - */ - public void setCodecPriority(@CodecPriority int codecPriority) { - mCodecPriority = codecPriority; - } - - /** - * Returns the codec sample rate. The value can be a bitmask with all - * supported sample rates. - */ - public @SampleRate int getSampleRate() { - return mSampleRate; - } - - /** - * Returns the codec bits per sample. The value can be a bitmask with all - * bits per sample supported. - */ - public @BitsPerSample int getBitsPerSample() { - return mBitsPerSample; - } - - /** - * Returns the codec channel mode. The value can be a bitmask with all - * supported channel modes. - */ - public @ChannelMode int getChannelMode() { - return mChannelMode; - } - - /** - * Returns the codec specific value1. - */ - public long getCodecSpecific1() { - return mCodecSpecific1; - } - - /** - * Returns the codec specific value2. - */ - public long getCodecSpecific2() { - return mCodecSpecific2; - } - - /** - * Returns the codec specific value3. - */ - public long getCodecSpecific3() { - return mCodecSpecific3; - } - - /** - * Returns the codec specific value4. - */ - public long getCodecSpecific4() { - return mCodecSpecific4; - } - - /** - * Checks whether a value set presented by a bitmask has zero or single bit - * - * @param valueSet the value set presented by a bitmask - * @return {@code true} if the valueSet contains zero or single bit, {@code false} otherwise - * @hide - */ - private static boolean hasSingleBit(int valueSet) { - return (valueSet == 0 || (valueSet & (valueSet - 1)) == 0); - } - - /** - * Returns whether the object contains none or single sample rate. - * @hide - */ - public boolean hasSingleSampleRate() { - return hasSingleBit(mSampleRate); - } - - /** - * Returns whether the object contains none or single bits per sample. - * @hide - */ - public boolean hasSingleBitsPerSample() { - return hasSingleBit(mBitsPerSample); - } - - /** - * Returns whether the object contains none or single channel mode. - * @hide - */ - public boolean hasSingleChannelMode() { - return hasSingleBit(mChannelMode); - } - - /** - * Checks whether the audio feeding parameters are the same. - * - * @param other the codec config to compare against - * @return {@code true} if the audio feeding parameters are same, {@code false} otherwise - * @hide - */ - public boolean sameAudioFeedingParameters(BluetoothCodecConfig other) { - return (other != null && other.mSampleRate == mSampleRate - && other.mBitsPerSample == mBitsPerSample - && other.mChannelMode == mChannelMode); - } - - /** - * Checks whether another codec config has the similar feeding parameters. - * Any parameters with NONE value will be considered to be a wildcard matching. - * - * @param other the codec config to compare against - * @return {@code true} if the audio feeding parameters are similar, {@code false} otherwise - * @hide - */ - public boolean similarCodecFeedingParameters(BluetoothCodecConfig other) { - if (other == null || mCodecType != other.mCodecType) { - return false; - } - int sampleRate = other.mSampleRate; - if (mSampleRate == SAMPLE_RATE_NONE - || sampleRate == SAMPLE_RATE_NONE) { - sampleRate = mSampleRate; - } - int bitsPerSample = other.mBitsPerSample; - if (mBitsPerSample == BITS_PER_SAMPLE_NONE - || bitsPerSample == BITS_PER_SAMPLE_NONE) { - bitsPerSample = mBitsPerSample; - } - int channelMode = other.mChannelMode; - if (mChannelMode == CHANNEL_MODE_NONE - || channelMode == CHANNEL_MODE_NONE) { - channelMode = mChannelMode; - } - return sameAudioFeedingParameters(new BluetoothCodecConfig( - mCodecType, /* priority */ 0, sampleRate, bitsPerSample, channelMode, - /* specific1 */ 0, /* specific2 */ 0, /* specific3 */ 0, - /* specific4 */ 0)); - } - - /** - * Checks whether the codec specific parameters are the same. - *

Currently, only AAC VBR and LDAC Playback Quality on CodecSpecific1 - * are compared. - * - * @param other the codec config to compare against - * @return {@code true} if the codec specific parameters are the same, {@code false} otherwise - * @hide - */ - public boolean sameCodecSpecificParameters(BluetoothCodecConfig other) { - if (other == null && mCodecType != other.mCodecType) { - return false; - } - switch (mCodecType) { - case SOURCE_CODEC_TYPE_AAC: - case SOURCE_CODEC_TYPE_LDAC: - if (mCodecSpecific1 != other.mCodecSpecific1) { - return false; - } - default: - return true; - } - } - - /** - * Builder for {@link BluetoothCodecConfig}. - *

By default, the codec type will be set to - * {@link BluetoothCodecConfig#SOURCE_CODEC_TYPE_INVALID}, the codec priority - * to {@link BluetoothCodecConfig#CODEC_PRIORITY_DEFAULT}, the sample rate to - * {@link BluetoothCodecConfig#SAMPLE_RATE_NONE}, the bits per sample to - * {@link BluetoothCodecConfig#BITS_PER_SAMPLE_NONE}, the channel mode to - * {@link BluetoothCodecConfig#CHANNEL_MODE_NONE}, and all the codec specific - * values to 0. - */ - public static final class Builder { - private int mCodecType = BluetoothCodecConfig.SOURCE_CODEC_TYPE_INVALID; - private int mCodecPriority = BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT; - private int mSampleRate = BluetoothCodecConfig.SAMPLE_RATE_NONE; - private int mBitsPerSample = BluetoothCodecConfig.BITS_PER_SAMPLE_NONE; - private int mChannelMode = BluetoothCodecConfig.CHANNEL_MODE_NONE; - private long mCodecSpecific1 = 0; - private long mCodecSpecific2 = 0; - private long mCodecSpecific3 = 0; - private long mCodecSpecific4 = 0; - - /** - * Set codec type for Bluetooth codec config. - * - * @param codecType of this codec - * @return the same Builder instance - */ - public @NonNull Builder setCodecType(@SourceCodecType int codecType) { - mCodecType = codecType; - return this; - } - - /** - * Set codec priority for Bluetooth codec config. - * - * @param codecPriority of this codec - * @return the same Builder instance - */ - public @NonNull Builder setCodecPriority(@CodecPriority int codecPriority) { - mCodecPriority = codecPriority; - return this; - } - - /** - * Set sample rate for Bluetooth codec config. - * - * @param sampleRate of this codec - * @return the same Builder instance - */ - public @NonNull Builder setSampleRate(@SampleRate int sampleRate) { - mSampleRate = sampleRate; - return this; - } - - /** - * Set the bits per sample for Bluetooth codec config. - * - * @param bitsPerSample of this codec - * @return the same Builder instance - */ - public @NonNull Builder setBitsPerSample(@BitsPerSample int bitsPerSample) { - mBitsPerSample = bitsPerSample; - return this; - } - - /** - * Set the channel mode for Bluetooth codec config. - * - * @param channelMode of this codec - * @return the same Builder instance - */ - public @NonNull Builder setChannelMode(@ChannelMode int channelMode) { - mChannelMode = channelMode; - return this; - } - - /** - * Set the first codec specific values for Bluetooth codec config. - * - * @param codecSpecific1 codec specific value or 0 if default - * @return the same Builder instance - */ - public @NonNull Builder setCodecSpecific1(long codecSpecific1) { - mCodecSpecific1 = codecSpecific1; - return this; - } - - /** - * Set the second codec specific values for Bluetooth codec config. - * - * @param codecSpecific2 codec specific value or 0 if default - * @return the same Builder instance - */ - public @NonNull Builder setCodecSpecific2(long codecSpecific2) { - mCodecSpecific2 = codecSpecific2; - return this; - } - - /** - * Set the third codec specific values for Bluetooth codec config. - * - * @param codecSpecific3 codec specific value or 0 if default - * @return the same Builder instance - */ - public @NonNull Builder setCodecSpecific3(long codecSpecific3) { - mCodecSpecific3 = codecSpecific3; - return this; - } - - /** - * Set the fourth codec specific values for Bluetooth codec config. - * - * @param codecSpecific4 codec specific value or 0 if default - * @return the same Builder instance - */ - public @NonNull Builder setCodecSpecific4(long codecSpecific4) { - mCodecSpecific4 = codecSpecific4; - return this; - } - - /** - * Build {@link BluetoothCodecConfig}. - * @return new BluetoothCodecConfig built - */ - public @NonNull BluetoothCodecConfig build() { - return new BluetoothCodecConfig(mCodecType, mCodecPriority, - mSampleRate, mBitsPerSample, - mChannelMode, mCodecSpecific1, - mCodecSpecific2, mCodecSpecific3, - mCodecSpecific4); - } - } -} diff --git a/core/java/android/bluetooth/BluetoothCodecStatus.java b/core/java/android/bluetooth/BluetoothCodecStatus.java deleted file mode 100644 index 02606feb3b3fdc3a4a88a60b9fce4585065dcd45..0000000000000000000000000000000000000000 --- a/core/java/android/bluetooth/BluetoothCodecStatus.java +++ /dev/null @@ -1,208 +0,0 @@ -/* - * Copyright (C) 2017 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.bluetooth; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.os.Parcel; -import android.os.Parcelable; - -import java.util.Collections; -import java.util.List; -import java.util.Objects; - -/** - * Represents the codec status (configuration and capability) for a Bluetooth - * A2DP source device. - * - * {@see BluetoothA2dp} - */ -public final class BluetoothCodecStatus implements Parcelable { - /** - * Extra for the codec configuration intents of the individual profiles. - * - * This extra represents the current codec status of the A2DP - * profile. - */ - public static final String EXTRA_CODEC_STATUS = - "android.bluetooth.extra.CODEC_STATUS"; - - private final @Nullable BluetoothCodecConfig mCodecConfig; - private final @Nullable List mCodecsLocalCapabilities; - private final @Nullable List mCodecsSelectableCapabilities; - - public BluetoothCodecStatus(@Nullable BluetoothCodecConfig codecConfig, - @Nullable List codecsLocalCapabilities, - @Nullable List codecsSelectableCapabilities) { - mCodecConfig = codecConfig; - mCodecsLocalCapabilities = codecsLocalCapabilities; - mCodecsSelectableCapabilities = codecsSelectableCapabilities; - } - - private BluetoothCodecStatus(Parcel in) { - mCodecConfig = in.readTypedObject(BluetoothCodecConfig.CREATOR); - mCodecsLocalCapabilities = in.createTypedArrayList(BluetoothCodecConfig.CREATOR); - mCodecsSelectableCapabilities = in.createTypedArrayList(BluetoothCodecConfig.CREATOR); - } - - @Override - public boolean equals(@Nullable Object o) { - if (o instanceof BluetoothCodecStatus) { - BluetoothCodecStatus other = (BluetoothCodecStatus) o; - return (Objects.equals(other.mCodecConfig, mCodecConfig) - && sameCapabilities(other.mCodecsLocalCapabilities, mCodecsLocalCapabilities) - && sameCapabilities(other.mCodecsSelectableCapabilities, - mCodecsSelectableCapabilities)); - } - return false; - } - - /** - * Checks whether two lists of capabilities contain same capabilities. - * The order of the capabilities in each list is ignored. - * - * @param c1 the first list of capabilities to compare - * @param c2 the second list of capabilities to compare - * @return {@code true} if both lists contain same capabilities - */ - private static boolean sameCapabilities(@Nullable List c1, - @Nullable List c2) { - if (c1 == null) { - return (c2 == null); - } - if (c2 == null) { - return false; - } - if (c1.size() != c2.size()) { - return false; - } - return c1.containsAll(c2); - } - - /** - * Checks whether the codec config matches the selectable capabilities. - * Any parameters of the codec config with NONE value will be considered a wildcard matching. - * - * @param codecConfig the codec config to compare against - * @return {@code true} if the codec config matches, {@code false} otherwise - */ - public boolean isCodecConfigSelectable(@Nullable BluetoothCodecConfig codecConfig) { - if (codecConfig == null || !codecConfig.hasSingleSampleRate() - || !codecConfig.hasSingleBitsPerSample() || !codecConfig.hasSingleChannelMode()) { - return false; - } - for (BluetoothCodecConfig selectableConfig : mCodecsSelectableCapabilities) { - if (codecConfig.getCodecType() != selectableConfig.getCodecType()) { - continue; - } - int sampleRate = codecConfig.getSampleRate(); - if ((sampleRate & selectableConfig.getSampleRate()) == 0 - && sampleRate != BluetoothCodecConfig.SAMPLE_RATE_NONE) { - continue; - } - int bitsPerSample = codecConfig.getBitsPerSample(); - if ((bitsPerSample & selectableConfig.getBitsPerSample()) == 0 - && bitsPerSample != BluetoothCodecConfig.BITS_PER_SAMPLE_NONE) { - continue; - } - int channelMode = codecConfig.getChannelMode(); - if ((channelMode & selectableConfig.getChannelMode()) == 0 - && channelMode != BluetoothCodecConfig.CHANNEL_MODE_NONE) { - continue; - } - return true; - } - return false; - } - - /** - * Returns a hash based on the codec config and local capabilities. - */ - @Override - public int hashCode() { - return Objects.hash(mCodecConfig, mCodecsLocalCapabilities, - mCodecsLocalCapabilities); - } - - /** - * Returns a {@link String} that describes each BluetoothCodecStatus parameter - * current value. - */ - @Override - public String toString() { - return "{mCodecConfig:" + mCodecConfig - + ",mCodecsLocalCapabilities:" + mCodecsLocalCapabilities - + ",mCodecsSelectableCapabilities:" + mCodecsSelectableCapabilities - + "}"; - } - - /** - * @return 0 - * @hide - */ - @Override - public int describeContents() { - return 0; - } - - public static final @android.annotation.NonNull Parcelable.Creator CREATOR = - new Parcelable.Creator() { - public BluetoothCodecStatus createFromParcel(Parcel in) { - return new BluetoothCodecStatus(in); - } - - public BluetoothCodecStatus[] newArray(int size) { - return new BluetoothCodecStatus[size]; - } - }; - - /** - * Flattens the object to a parcel. - * - * @param out The Parcel in which the object should be written - * @param flags Additional flags about how the object should be written - */ - @Override - public void writeToParcel(@NonNull Parcel out, int flags) { - out.writeTypedObject(mCodecConfig, 0); - out.writeTypedList(mCodecsLocalCapabilities); - out.writeTypedList(mCodecsSelectableCapabilities); - } - - /** - * Returns the current codec configuration. - */ - public @Nullable BluetoothCodecConfig getCodecConfig() { - return mCodecConfig; - } - - /** - * Returns the codecs local capabilities. - */ - public @NonNull List getCodecsLocalCapabilities() { - return (mCodecsLocalCapabilities == null) - ? Collections.emptyList() : mCodecsLocalCapabilities; - } - - /** - * Returns the codecs selectable capabilities. - */ - public @NonNull List getCodecsSelectableCapabilities() { - return (mCodecsSelectableCapabilities == null) - ? Collections.emptyList() : mCodecsSelectableCapabilities; - } -} diff --git a/core/java/android/bluetooth/BluetoothCsipSetCoordinator.java b/core/java/android/bluetooth/BluetoothCsipSetCoordinator.java deleted file mode 100644 index ba57ec472a6e58398c66f994742ef2ccc12dc0a3..0000000000000000000000000000000000000000 --- a/core/java/android/bluetooth/BluetoothCsipSetCoordinator.java +++ /dev/null @@ -1,555 +0,0 @@ -/* - * Copyright 2021 HIMSA II K/S - www.himsa.com. - * Represented by EHIMA - www.ehima.com - * - * 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.bluetooth; - -import static android.bluetooth.BluetoothUtils.getSyncTimeout; - -import android.Manifest; -import android.annotation.CallbackExecutor; -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.annotation.RequiresPermission; -import android.annotation.SdkConstant; -import android.annotation.SdkConstant.SdkConstantType; -import android.annotation.SystemApi; -import android.content.AttributionSource; -import android.content.Context; -import android.os.IBinder; -import android.os.ParcelUuid; -import android.os.RemoteException; -import android.util.CloseGuard; -import android.util.Log; - -import com.android.modules.utils.SynchronousResultReceiver; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.UUID; -import java.util.concurrent.Executor; -import java.util.concurrent.TimeoutException; - -/** - * This class provides the public APIs to control the Bluetooth CSIP set coordinator. - * - *

BluetoothCsipSetCoordinator is a proxy object for controlling the Bluetooth VC - * Service via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get - * the BluetoothCsipSetCoordinator proxy object. - * - */ -public final class BluetoothCsipSetCoordinator implements BluetoothProfile, AutoCloseable { - private static final String TAG = "BluetoothCsipSetCoordinator"; - private static final boolean DBG = false; - private static final boolean VDBG = false; - - private CloseGuard mCloseGuard; - - /** - * @hide - */ - @SystemApi - public interface ClientLockCallback { - /** - * @hide - */ - @SystemApi void onGroupLockSet(int groupId, int opStatus, boolean isLocked); - } - - private static class BluetoothCsipSetCoordinatorLockCallbackDelegate - extends IBluetoothCsipSetCoordinatorLockCallback.Stub { - private final ClientLockCallback mCallback; - private final Executor mExecutor; - - BluetoothCsipSetCoordinatorLockCallbackDelegate( - Executor executor, ClientLockCallback callback) { - mExecutor = executor; - mCallback = callback; - } - - @Override - public void onGroupLockSet(int groupId, int opStatus, boolean isLocked) { - mExecutor.execute(() -> mCallback.onGroupLockSet(groupId, opStatus, isLocked)); - } - }; - - /** - * Intent used to broadcast the change in connection state of the CSIS - * Client. - * - *

This intent will have 3 extras: - *

    - *
  • {@link #EXTRA_STATE} - The current state of the profile.
  • - *
  • {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile.
  • - *
  • {@link BluetoothDevice#EXTRA_DEVICE} - The remote device.
  • - *
- * - *

{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of - * {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING}, - * {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}. - */ - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - public static final String ACTION_CSIS_CONNECTION_STATE_CHANGED = - "android.bluetooth.action.CSIS_CONNECTION_STATE_CHANGED"; - - /** - * Intent used to expose broadcast receiving device. - * - *

This intent will have 2 extras: - *

    - *
  • {@link BluetoothDevice#EXTRA_DEVICE} - The remote Broadcast receiver device.
  • - *
  • {@link #EXTRA_CSIS_GROUP_ID} - Group identifier.
  • - *
  • {@link #EXTRA_CSIS_GROUP_SIZE} - Group size.
  • - *
  • {@link #EXTRA_CSIS_GROUP_TYPE_UUID} - Group type UUID.
  • - *
- * - * @hide - */ - @SystemApi - @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - public static final String ACTION_CSIS_DEVICE_AVAILABLE = - "android.bluetooth.action.CSIS_DEVICE_AVAILABLE"; - - /** - * Used as an extra field in {@link #ACTION_CSIS_DEVICE_AVAILABLE} intent. - * Contains the group id. - * - * @hide - */ - public static final String EXTRA_CSIS_GROUP_ID = "android.bluetooth.extra.CSIS_GROUP_ID"; - - /** - * Group size as int extra field in {@link #ACTION_CSIS_DEVICE_AVAILABLE} intent. - * - * @hide - */ - public static final String EXTRA_CSIS_GROUP_SIZE = "android.bluetooth.extra.CSIS_GROUP_SIZE"; - - /** - * Group type uuid extra field in {@link #ACTION_CSIS_DEVICE_AVAILABLE} intent. - * - * @hide - */ - public static final String EXTRA_CSIS_GROUP_TYPE_UUID = - "android.bluetooth.extra.CSIS_GROUP_TYPE_UUID"; - - /** - * Intent used to broadcast information about identified set member - * ready to connect. - * - *

This intent will have one extra: - *

    - *
  • {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. It can - * be null if no device is active.
  • - *
  • {@link #EXTRA_CSIS_GROUP_ID} - Group identifier.
  • - *
- * - * @hide - */ - @SystemApi - @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - public static final String ACTION_CSIS_SET_MEMBER_AVAILABLE = - "android.bluetooth.action.CSIS_SET_MEMBER_AVAILABLE"; - - /** - * This represents an invalid group ID. - * - * @hide - */ - public static final int GROUP_ID_INVALID = IBluetoothCsipSetCoordinator.CSIS_GROUP_ID_INVALID; - - /** - * Indicating that group was locked with success. - * - * @hide - */ - public static final int GROUP_LOCK_SUCCESS = 0; - - /** - * Indicating that group locked failed due to invalid group ID. - * - * @hide - */ - public static final int GROUP_LOCK_FAILED_INVALID_GROUP = 1; - - /** - * Indicating that group locked failed due to empty group. - * - * @hide - */ - public static final int GROUP_LOCK_FAILED_GROUP_EMPTY = 2; - - /** - * Indicating that group locked failed due to group members being disconnected. - * - * @hide - */ - public static final int GROUP_LOCK_FAILED_GROUP_NOT_CONNECTED = 3; - - /** - * Indicating that group locked failed due to group member being already locked. - * - * @hide - */ - public static final int GROUP_LOCK_FAILED_LOCKED_BY_OTHER = 4; - - /** - * Indicating that group locked failed due to other reason. - * - * @hide - */ - public static final int GROUP_LOCK_FAILED_OTHER_REASON = 5; - - /** - * Indicating that group member in locked state was lost. - * - * @hide - */ - public static final int LOCKED_GROUP_MEMBER_LOST = 6; - - private final BluetoothAdapter mAdapter; - private final AttributionSource mAttributionSource; - private final BluetoothProfileConnector mProfileConnector = - new BluetoothProfileConnector(this, BluetoothProfile.CSIP_SET_COORDINATOR, TAG, - IBluetoothCsipSetCoordinator.class.getName()) { - @Override - public IBluetoothCsipSetCoordinator getServiceInterface(IBinder service) { - return IBluetoothCsipSetCoordinator.Stub.asInterface(service); - } - }; - - /** - * Create a BluetoothCsipSetCoordinator proxy object for interacting with the local - * Bluetooth CSIS service. - */ - /*package*/ BluetoothCsipSetCoordinator(Context context, ServiceListener listener, BluetoothAdapter adapter) { - mAdapter = adapter; - mAttributionSource = adapter.getAttributionSource(); - mProfileConnector.connect(context, listener); - mCloseGuard = new CloseGuard(); - mCloseGuard.open("close"); - } - - /** - * @hide - */ - protected void finalize() { - if (mCloseGuard != null) { - mCloseGuard.warnIfOpen(); - } - close(); - } - - /** - * @hide - */ - public void close() { - mProfileConnector.disconnect(); - } - - private IBluetoothCsipSetCoordinator getService() { - return mProfileConnector.getService(); - } - - /** - * Lock the set. - * @param groupId group ID to lock, - * @param executor callback executor, - * @param cb callback to report lock and unlock events - stays valid until the app unlocks - * using the returned lock identifier or the lock timeouts on the remote side, - * as per CSIS specification, - * @return unique lock identifier used for unlocking or null if lock has failed. - * - * @hide - */ - @SystemApi - @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) - public - @Nullable UUID groupLock(int groupId, @Nullable @CallbackExecutor Executor executor, - @Nullable ClientLockCallback cb) { - if (VDBG) log("groupLockSet()"); - final IBluetoothCsipSetCoordinator service = getService(); - final UUID defaultValue = null; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled()) { - IBluetoothCsipSetCoordinatorLockCallback delegate = null; - if ((executor != null) && (cb != null)) { - delegate = new BluetoothCsipSetCoordinatorLockCallbackDelegate(executor, cb); - } - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.groupLock(groupId, delegate, mAttributionSource, recv); - final ParcelUuid ret = recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(null); - return ret == null ? defaultValue : ret.getUuid(); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Unlock the set. - * @param lockUuid unique lock identifier - * @return true if unlocked, false on error - * - * @hide - */ - @SystemApi - @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) - public boolean groupUnlock(@NonNull UUID lockUuid) { - if (VDBG) log("groupLockSet()"); - if (lockUuid == null) { - return false; - } - final IBluetoothCsipSetCoordinator service = getService(); - final boolean defaultValue = false; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled()) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.groupUnlock(new ParcelUuid(lockUuid), mAttributionSource, recv); - recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(null); - return true; - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Get device's groups. - * @param device the active device - * @return Map of groups ids and related UUIDs - * - * @hide - */ - @SystemApi - @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) - public @NonNull Map getGroupUuidMapByDevice(@Nullable BluetoothDevice device) { - if (VDBG) log("getGroupUuidMapByDevice()"); - final IBluetoothCsipSetCoordinator service = getService(); - final Map defaultValue = new HashMap<>(); - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled()) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.getGroupUuidMapByDevice(device, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Get group id for the given UUID - * @param uuid - * @return list of group IDs - * - * @hide - */ - @SystemApi - @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) - public @NonNull List getAllGroupIds(@Nullable ParcelUuid uuid) { - if (VDBG) log("getAllGroupIds()"); - final IBluetoothCsipSetCoordinator service = getService(); - final List defaultValue = new ArrayList<>(); - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled()) { - try { - final SynchronousResultReceiver> recv = - new SynchronousResultReceiver(); - service.getAllGroupIds(uuid, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * {@inheritDoc} - */ - @Override - public @NonNull List getConnectedDevices() { - if (VDBG) log("getConnectedDevices()"); - final IBluetoothCsipSetCoordinator service = getService(); - final List defaultValue = new ArrayList<>(); - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled()) { - try { - final SynchronousResultReceiver> recv = - new SynchronousResultReceiver(); - service.getConnectedDevices(mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * {@inheritDoc} - */ - @Override - public - @NonNull List getDevicesMatchingConnectionStates(@NonNull int[] states) { - if (VDBG) log("getDevicesMatchingStates(states=" + Arrays.toString(states) + ")"); - final IBluetoothCsipSetCoordinator service = getService(); - final List defaultValue = new ArrayList<>(); - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled()) { - try { - final SynchronousResultReceiver> recv = - new SynchronousResultReceiver(); - service.getDevicesMatchingConnectionStates(states, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * {@inheritDoc} - */ - @Override - public - @BluetoothProfile.BtProfileState int getConnectionState(@Nullable BluetoothDevice device) { - if (VDBG) log("getState(" + device + ")"); - final IBluetoothCsipSetCoordinator service = getService(); - final int defaultValue = BluetoothProfile.STATE_DISCONNECTED; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled()) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.getConnectionState(device, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Set connection policy of the profile - * - *

The device should already be paired. - * Connection policy can be one of {@link #CONNECTION_POLICY_ALLOWED}, - * {@link #CONNECTION_POLICY_FORBIDDEN}, {@link #CONNECTION_POLICY_UNKNOWN} - * - * @param device Paired bluetooth device - * @param connectionPolicy is the connection policy to set to for this profile - * @return true if connectionPolicy is set, false on error - * - * @hide - */ - @SystemApi - @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) - public boolean setConnectionPolicy( - @Nullable BluetoothDevice device, @ConnectionPolicy int connectionPolicy) { - if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")"); - final IBluetoothCsipSetCoordinator service = getService(); - final boolean defaultValue = false; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device) - && (connectionPolicy == BluetoothProfile.CONNECTION_POLICY_FORBIDDEN - || connectionPolicy == BluetoothProfile.CONNECTION_POLICY_ALLOWED)) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.setConnectionPolicy(device, connectionPolicy, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Get the connection policy of the profile. - * - *

The connection policy can be any of: - * {@link #CONNECTION_POLICY_ALLOWED}, {@link #CONNECTION_POLICY_FORBIDDEN}, - * {@link #CONNECTION_POLICY_UNKNOWN} - * - * @param device Bluetooth device - * @return connection policy of the device - * - * @hide - */ - @SystemApi - @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) - public @ConnectionPolicy int getConnectionPolicy(@Nullable BluetoothDevice device) { - if (VDBG) log("getConnectionPolicy(" + device + ")"); - final IBluetoothCsipSetCoordinator service = getService(); - final int defaultValue = BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device)) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.getConnectionPolicy(device, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - private boolean isEnabled() { - return mAdapter.getState() == BluetoothAdapter.STATE_ON; - } - - private static boolean isValidDevice(@Nullable BluetoothDevice device) { - return device != null && BluetoothAdapter.checkBluetoothAddress(device.getAddress()); - } - - private static void log(String msg) { - Log.d(TAG, msg); - } -} diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java deleted file mode 100644 index 1edf5cc96b0da1c12fa6c3f4ff19a08e01c415bc..0000000000000000000000000000000000000000 --- a/core/java/android/bluetooth/BluetoothDevice.java +++ /dev/null @@ -1,2831 +0,0 @@ -/* - * Copyright (C) 2009 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.bluetooth; - -import android.annotation.IntDef; -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.annotation.RequiresPermission; -import android.annotation.SdkConstant; -import android.annotation.SdkConstant.SdkConstantType; -import android.annotation.SuppressLint; -import android.annotation.SystemApi; //import android.app.PropertyInvalidatedCache; -import android.bluetooth.annotations.RequiresBluetoothConnectPermission; -import android.bluetooth.annotations.RequiresBluetoothLocationPermission; -import android.bluetooth.annotations.RequiresBluetoothScanPermission; -import android.bluetooth.annotations.RequiresLegacyBluetoothAdminPermission; -import android.bluetooth.annotations.RequiresLegacyBluetoothPermission; -import android.companion.AssociationRequest; -import android.compat.annotation.UnsupportedAppUsage; -import android.content.AttributionSource; -import android.content.Context; -import android.os.Build; -import android.os.Handler; -import android.os.Parcel; -import android.os.ParcelUuid; -import android.os.Parcelable; -import android.os.Process; -import android.os.RemoteException; -import android.util.Log; - -import java.io.IOException; -import java.io.UnsupportedEncodingException; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.util.UUID; - -/** - * Represents a remote Bluetooth device. A {@link BluetoothDevice} lets you - * create a connection with the respective device or query information about - * it, such as the name, address, class, and bonding state. - * - *

This class is really just a thin wrapper for a Bluetooth hardware - * address. Objects of this class are immutable. Operations on this class - * are performed on the remote Bluetooth hardware address, using the - * {@link BluetoothAdapter} that was used to create this {@link - * BluetoothDevice}. - * - *

To get a {@link BluetoothDevice}, use - * {@link BluetoothAdapter#getRemoteDevice(String) - * BluetoothAdapter.getRemoteDevice(String)} to create one representing a device - * of a known MAC address (which you can get through device discovery with - * {@link BluetoothAdapter}) or get one from the set of bonded devices - * returned by {@link BluetoothAdapter#getBondedDevices() - * BluetoothAdapter.getBondedDevices()}. You can then open a - * {@link BluetoothSocket} for communication with the remote device, using - * {@link #createRfcommSocketToServiceRecord(UUID)} over Bluetooth BR/EDR or using - * {@link #createL2capChannel(int)} over Bluetooth LE. - * - *

- *

Developer Guides

- *

- * For more information about using Bluetooth, read the Bluetooth developer - * guide. - *

- *
- * - * {@see BluetoothAdapter} - * {@see BluetoothSocket} - */ -public final class BluetoothDevice implements Parcelable, Attributable { - private static final String TAG = "BluetoothDevice"; - private static final boolean DBG = false; - - /** - * Connection state bitmask as returned by getConnectionState. - */ - private static final int CONNECTION_STATE_DISCONNECTED = 0; - private static final int CONNECTION_STATE_CONNECTED = 1; - private static final int CONNECTION_STATE_ENCRYPTED_BREDR = 2; - private static final int CONNECTION_STATE_ENCRYPTED_LE = 4; - - /** - * Sentinel error value for this class. Guaranteed to not equal any other - * integer constant in this class. Provided as a convenience for functions - * that require a sentinel error value, for example: - *

Intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, - * BluetoothDevice.ERROR) - */ - public static final int ERROR = Integer.MIN_VALUE; - - /** - * Broadcast Action: Remote device discovered. - *

Sent when a remote device is found during discovery. - *

Always contains the extra fields {@link #EXTRA_DEVICE} and {@link - * #EXTRA_CLASS}. Can contain the extra fields {@link #EXTRA_NAME} and/or - * {@link #EXTRA_RSSI} and/or {@link #EXTRA_IS_COORDINATED_SET_MEMBER} if they are available. - */ - // TODO: Change API to not broadcast RSSI if not available (incoming connection) - @RequiresLegacyBluetoothPermission - @RequiresBluetoothScanPermission - @RequiresBluetoothLocationPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - public static final String ACTION_FOUND = - "android.bluetooth.device.action.FOUND"; - - /** - * Broadcast Action: Bluetooth class of a remote device has changed. - *

Always contains the extra fields {@link #EXTRA_DEVICE} and {@link - * #EXTRA_CLASS}. - * {@see BluetoothClass} - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - public static final String ACTION_CLASS_CHANGED = - "android.bluetooth.device.action.CLASS_CHANGED"; - - /** - * Broadcast Action: Indicates a low level (ACL) connection has been - * established with a remote device. - *

Always contains the extra field {@link #EXTRA_DEVICE}. - *

ACL connections are managed automatically by the Android Bluetooth - * stack. - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - public static final String ACTION_ACL_CONNECTED = - "android.bluetooth.device.action.ACL_CONNECTED"; - - /** - * Broadcast Action: Indicates that a low level (ACL) disconnection has - * been requested for a remote device, and it will soon be disconnected. - *

This is useful for graceful disconnection. Applications should use - * this intent as a hint to immediately terminate higher level connections - * (RFCOMM, L2CAP, or profile connections) to the remote device. - *

Always contains the extra field {@link #EXTRA_DEVICE}. - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - public static final String ACTION_ACL_DISCONNECT_REQUESTED = - "android.bluetooth.device.action.ACL_DISCONNECT_REQUESTED"; - - /** - * Broadcast Action: Indicates a low level (ACL) disconnection from a - * remote device. - *

Always contains the extra field {@link #EXTRA_DEVICE}. - *

ACL connections are managed automatically by the Android Bluetooth - * stack. - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - public static final String ACTION_ACL_DISCONNECTED = - "android.bluetooth.device.action.ACL_DISCONNECTED"; - - /** - * Broadcast Action: Indicates the friendly name of a remote device has - * been retrieved for the first time, or changed since the last retrieval. - *

Always contains the extra fields {@link #EXTRA_DEVICE} and {@link - * #EXTRA_NAME}. - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - public static final String ACTION_NAME_CHANGED = - "android.bluetooth.device.action.NAME_CHANGED"; - - /** - * Broadcast Action: Indicates the alias of a remote device has been - * changed. - *

Always contains the extra field {@link #EXTRA_DEVICE}. - */ - @SuppressLint("ActionValue") - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - public static final String ACTION_ALIAS_CHANGED = - "android.bluetooth.device.action.ALIAS_CHANGED"; - - /** - * Broadcast Action: Indicates a change in the bond state of a remote - * device. For example, if a device is bonded (paired). - *

Always contains the extra fields {@link #EXTRA_DEVICE}, {@link - * #EXTRA_BOND_STATE} and {@link #EXTRA_PREVIOUS_BOND_STATE}. - */ - // Note: When EXTRA_BOND_STATE is BOND_NONE then this will also - // contain a hidden extra field EXTRA_REASON with the result code. - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - public static final String ACTION_BOND_STATE_CHANGED = - "android.bluetooth.device.action.BOND_STATE_CHANGED"; - - /** - * Broadcast Action: Indicates the battery level of a remote device has - * been retrieved for the first time, or changed since the last retrieval - *

Always contains the extra fields {@link #EXTRA_DEVICE} and {@link - * #EXTRA_BATTERY_LEVEL}. - * - * @hide - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - public static final String ACTION_BATTERY_LEVEL_CHANGED = - "android.bluetooth.device.action.BATTERY_LEVEL_CHANGED"; - - /** - * Used as an Integer extra field in {@link #ACTION_BATTERY_LEVEL_CHANGED} - * intent. It contains the most recently retrieved battery level information - * ranging from 0% to 100% for a remote device, {@link #BATTERY_LEVEL_UNKNOWN} - * when the valid is unknown or there is an error - * - * @hide - */ - public static final String EXTRA_BATTERY_LEVEL = - "android.bluetooth.device.extra.BATTERY_LEVEL"; - - /** - * Used as the unknown value for {@link #EXTRA_BATTERY_LEVEL} and {@link #getBatteryLevel()} - * - * @hide - */ - public static final int BATTERY_LEVEL_UNKNOWN = -1; - - /** - * Used as an error value for {@link #getBatteryLevel()} to represent bluetooth is off - * - * @hide - */ - public static final int BATTERY_LEVEL_BLUETOOTH_OFF = -100; - - /** - * Used as a Parcelable {@link BluetoothDevice} extra field in every intent - * broadcast by this class. It contains the {@link BluetoothDevice} that - * the intent applies to. - */ - public static final String EXTRA_DEVICE = "android.bluetooth.device.extra.DEVICE"; - - /** - * Used as a String extra field in {@link #ACTION_NAME_CHANGED} and {@link - * #ACTION_FOUND} intents. It contains the friendly Bluetooth name. - */ - public static final String EXTRA_NAME = "android.bluetooth.device.extra.NAME"; - - /** - * Used as an optional short extra field in {@link #ACTION_FOUND} intents. - * Contains the RSSI value of the remote device as reported by the - * Bluetooth hardware. - */ - public static final String EXTRA_RSSI = "android.bluetooth.device.extra.RSSI"; - - /** - * Used as an bool extra field in {@link #ACTION_FOUND} intents. - * It contains the information if device is discovered as member of a coordinated set or not. - * Pairing with device that belongs to a set would trigger pairing with the rest of set members. - * See Bluetooth CSIP specification for more details. - */ - public static final String EXTRA_IS_COORDINATED_SET_MEMBER = - "android.bluetooth.extra.IS_COORDINATED_SET_MEMBER"; - - /** - * Used as a Parcelable {@link BluetoothClass} extra field in {@link - * #ACTION_FOUND} and {@link #ACTION_CLASS_CHANGED} intents. - */ - public static final String EXTRA_CLASS = "android.bluetooth.device.extra.CLASS"; - - /** - * Used as an int extra field in {@link #ACTION_BOND_STATE_CHANGED} intents. - * Contains the bond state of the remote device. - *

Possible values are: - * {@link #BOND_NONE}, - * {@link #BOND_BONDING}, - * {@link #BOND_BONDED}. - */ - public static final String EXTRA_BOND_STATE = "android.bluetooth.device.extra.BOND_STATE"; - /** - * Used as an int extra field in {@link #ACTION_BOND_STATE_CHANGED} intents. - * Contains the previous bond state of the remote device. - *

Possible values are: - * {@link #BOND_NONE}, - * {@link #BOND_BONDING}, - * {@link #BOND_BONDED}. - */ - public static final String EXTRA_PREVIOUS_BOND_STATE = - "android.bluetooth.device.extra.PREVIOUS_BOND_STATE"; - /** - * Indicates the remote device is not bonded (paired). - *

There is no shared link key with the remote device, so communication - * (if it is allowed at all) will be unauthenticated and unencrypted. - */ - public static final int BOND_NONE = 10; - /** - * Indicates bonding (pairing) is in progress with the remote device. - */ - public static final int BOND_BONDING = 11; - /** - * Indicates the remote device is bonded (paired). - *

A shared link keys exists locally for the remote device, so - * communication can be authenticated and encrypted. - *

Being bonded (paired) with a remote device does not necessarily - * mean the device is currently connected. It just means that the pending - * procedure was completed at some earlier time, and the link key is still - * stored locally, ready to use on the next connection. - * - */ - public static final int BOND_BONDED = 12; - - /** - * Used as an int extra field in {@link #ACTION_PAIRING_REQUEST} - * intents for unbond reason. - * - * @hide - */ - @UnsupportedAppUsage - public static final String EXTRA_REASON = "android.bluetooth.device.extra.REASON"; - - /** - * Used as an int extra field in {@link #ACTION_PAIRING_REQUEST} - * intents to indicate pairing method used. Possible values are: - * {@link #PAIRING_VARIANT_PIN}, - * {@link #PAIRING_VARIANT_PASSKEY_CONFIRMATION}, - */ - public static final String EXTRA_PAIRING_VARIANT = - "android.bluetooth.device.extra.PAIRING_VARIANT"; - - /** - * Used as an int extra field in {@link #ACTION_PAIRING_REQUEST} - * intents as the value of passkey. - */ - public static final String EXTRA_PAIRING_KEY = "android.bluetooth.device.extra.PAIRING_KEY"; - - /** - * Used as an int extra field in {@link #ACTION_PAIRING_REQUEST} - * intents as the value of passkey. - * @hide - */ - public static final String EXTRA_PAIRING_INITIATOR = - "android.bluetooth.device.extra.PAIRING_INITIATOR"; - - /** - * Bluetooth pairing initiator, Foreground App - * @hide - */ - public static final int EXTRA_PAIRING_INITIATOR_FOREGROUND = 1; - - /** - * Bluetooth pairing initiator, Background - * @hide - */ - public static final int EXTRA_PAIRING_INITIATOR_BACKGROUND = 2; - - /** - * Bluetooth device type, Unknown - */ - public static final int DEVICE_TYPE_UNKNOWN = 0; - - /** - * Bluetooth device type, Classic - BR/EDR devices - */ - public static final int DEVICE_TYPE_CLASSIC = 1; - - /** - * Bluetooth device type, Low Energy - LE-only - */ - public static final int DEVICE_TYPE_LE = 2; - - /** - * Bluetooth device type, Dual Mode - BR/EDR/LE - */ - public static final int DEVICE_TYPE_DUAL = 3; - - - /** @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 = - "android.bluetooth.device.action.SDP_RECORD"; - - /** @hide */ - @IntDef(prefix = "METADATA_", value = { - METADATA_MANUFACTURER_NAME, - METADATA_MODEL_NAME, - METADATA_SOFTWARE_VERSION, - METADATA_HARDWARE_VERSION, - METADATA_COMPANION_APP, - METADATA_MAIN_ICON, - METADATA_IS_UNTETHERED_HEADSET, - METADATA_UNTETHERED_LEFT_ICON, - METADATA_UNTETHERED_RIGHT_ICON, - METADATA_UNTETHERED_CASE_ICON, - METADATA_UNTETHERED_LEFT_BATTERY, - METADATA_UNTETHERED_RIGHT_BATTERY, - METADATA_UNTETHERED_CASE_BATTERY, - METADATA_UNTETHERED_LEFT_CHARGING, - METADATA_UNTETHERED_RIGHT_CHARGING, - METADATA_UNTETHERED_CASE_CHARGING, - METADATA_ENHANCED_SETTINGS_UI_URI, - METADATA_DEVICE_TYPE, - METADATA_MAIN_BATTERY, - METADATA_MAIN_CHARGING, - METADATA_MAIN_LOW_BATTERY_THRESHOLD, - METADATA_UNTETHERED_LEFT_LOW_BATTERY_THRESHOLD, - METADATA_UNTETHERED_RIGHT_LOW_BATTERY_THRESHOLD, - METADATA_UNTETHERED_CASE_LOW_BATTERY_THRESHOLD}) - @Retention(RetentionPolicy.SOURCE) - public @interface MetadataKey{} - - /** - * Maximum length of a metadata entry, this is to avoid exploding Bluetooth - * disk usage - * @hide - */ - @SystemApi - public static final int METADATA_MAX_LENGTH = 2048; - - /** - * Manufacturer name of this Bluetooth device - * Data type should be {@String} as {@link Byte} array. - * @hide - */ - @SystemApi - public static final int METADATA_MANUFACTURER_NAME = 0; - - /** - * Model name of this Bluetooth device - * Data type should be {@String} as {@link Byte} array. - * @hide - */ - @SystemApi - public static final int METADATA_MODEL_NAME = 1; - - /** - * Software version of this Bluetooth device - * Data type should be {@String} as {@link Byte} array. - * @hide - */ - @SystemApi - public static final int METADATA_SOFTWARE_VERSION = 2; - - /** - * Hardware version of this Bluetooth device - * Data type should be {@String} as {@link Byte} array. - * @hide - */ - @SystemApi - public static final int METADATA_HARDWARE_VERSION = 3; - - /** - * Package name of the companion app, if any - * Data type should be {@String} as {@link Byte} array. - * @hide - */ - @SystemApi - public static final int METADATA_COMPANION_APP = 4; - - /** - * URI to the main icon shown on the settings UI - * Data type should be {@link Byte} array. - * @hide - */ - @SystemApi - public static final int METADATA_MAIN_ICON = 5; - - /** - * Whether this device is an untethered headset with left, right and case - * Data type should be {@String} as {@link Byte} array. - * @hide - */ - @SystemApi - public static final int METADATA_IS_UNTETHERED_HEADSET = 6; - - /** - * URI to icon of the left headset - * Data type should be {@link Byte} array. - * @hide - */ - @SystemApi - public static final int METADATA_UNTETHERED_LEFT_ICON = 7; - - /** - * URI to icon of the right headset - * Data type should be {@link Byte} array. - * @hide - */ - @SystemApi - public static final int METADATA_UNTETHERED_RIGHT_ICON = 8; - - /** - * URI to icon of the headset charging case - * Data type should be {@link Byte} array. - * @hide - */ - @SystemApi - public static final int METADATA_UNTETHERED_CASE_ICON = 9; - - /** - * Battery level of left headset - * Data type should be {@String} 0-100 as {@link Byte} array, otherwise - * as invalid. - * @hide - */ - @SystemApi - public static final int METADATA_UNTETHERED_LEFT_BATTERY = 10; - - /** - * Battery level of rigth headset - * Data type should be {@String} 0-100 as {@link Byte} array, otherwise - * as invalid. - * @hide - */ - @SystemApi - public static final int METADATA_UNTETHERED_RIGHT_BATTERY = 11; - - /** - * Battery level of the headset charging case - * Data type should be {@String} 0-100 as {@link Byte} array, otherwise - * as invalid. - * @hide - */ - @SystemApi - public static final int METADATA_UNTETHERED_CASE_BATTERY = 12; - - /** - * Whether the left headset is charging - * Data type should be {@String} as {@link Byte} array. - * @hide - */ - @SystemApi - public static final int METADATA_UNTETHERED_LEFT_CHARGING = 13; - - /** - * Whether the right headset is charging - * Data type should be {@String} as {@link Byte} array. - * @hide - */ - @SystemApi - public static final int METADATA_UNTETHERED_RIGHT_CHARGING = 14; - - /** - * Whether the headset charging case is charging - * Data type should be {@String} as {@link Byte} array. - * @hide - */ - @SystemApi - public static final int METADATA_UNTETHERED_CASE_CHARGING = 15; - - /** - * URI to the enhanced settings UI slice - * Data type should be {@String} as {@link Byte} array, null means - * the UI does not exist. - * @hide - */ - @SystemApi - public static final int METADATA_ENHANCED_SETTINGS_UI_URI = 16; - - /** - * Type of the Bluetooth device, must be within the list of - * BluetoothDevice.DEVICE_TYPE_* - * Data type should be {@String} as {@link Byte} array. - * @hide - */ - @SystemApi - public static final int METADATA_DEVICE_TYPE = 17; - - /** - * Battery level of the Bluetooth device, use when the Bluetooth device - * does not support HFP battery indicator. - * Data type should be {@String} as {@link Byte} array. - * @hide - */ - @SystemApi - public static final int METADATA_MAIN_BATTERY = 18; - - /** - * Whether the device is charging. - * Data type should be {@String} as {@link Byte} array. - * @hide - */ - @SystemApi - public static final int METADATA_MAIN_CHARGING = 19; - - /** - * The battery threshold of the Bluetooth device to show low battery icon. - * Data type should be {@String} as {@link Byte} array. - * @hide - */ - @SystemApi - public static final int METADATA_MAIN_LOW_BATTERY_THRESHOLD = 20; - - /** - * The battery threshold of the left headset to show low battery icon. - * Data type should be {@String} as {@link Byte} array. - * @hide - */ - @SystemApi - public static final int METADATA_UNTETHERED_LEFT_LOW_BATTERY_THRESHOLD = 21; - - /** - * The battery threshold of the right headset to show low battery icon. - * Data type should be {@String} as {@link Byte} array. - * @hide - */ - @SystemApi - public static final int METADATA_UNTETHERED_RIGHT_LOW_BATTERY_THRESHOLD = 22; - - /** - * The battery threshold of the case to show low battery icon. - * Data type should be {@String} as {@link Byte} array. - * @hide - */ - @SystemApi - public static final int METADATA_UNTETHERED_CASE_LOW_BATTERY_THRESHOLD = 23; - - /** - * Device type which is used in METADATA_DEVICE_TYPE - * Indicates this Bluetooth device is a standard Bluetooth accessory or - * not listed in METADATA_DEVICE_TYPE_*. - * @hide - */ - @SystemApi - public static final String DEVICE_TYPE_DEFAULT = "Default"; - - /** - * Device type which is used in METADATA_DEVICE_TYPE - * Indicates this Bluetooth device is a watch. - * @hide - */ - @SystemApi - public static final String DEVICE_TYPE_WATCH = "Watch"; - - /** - * Device type which is used in METADATA_DEVICE_TYPE - * Indicates this Bluetooth device is an untethered headset. - * @hide - */ - @SystemApi - public static final String DEVICE_TYPE_UNTETHERED_HEADSET = "Untethered Headset"; - - /** - * Broadcast Action: This intent is used to broadcast the {@link UUID} - * wrapped as a {@link android.os.ParcelUuid} of the remote device after it - * has been fetched. This intent is sent only when the UUIDs of the remote - * device are requested to be fetched using Service Discovery Protocol - *

Always contains the extra field {@link #EXTRA_DEVICE} - *

Always contains the extra field {@link #EXTRA_UUID} - */ - @RequiresLegacyBluetoothAdminPermission - @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"; - - /** - * Broadcast Action: Indicates a failure to retrieve the name of a remote - * device. - *

Always contains the extra field {@link #EXTRA_DEVICE}. - * - * @hide - */ - //TODO: is this actually useful? - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - public static final String ACTION_NAME_FAILED = - "android.bluetooth.device.action.NAME_FAILED"; - - /** - * Broadcast Action: This intent is used to broadcast PAIRING REQUEST - */ - @RequiresLegacyBluetoothAdminPermission - @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"; - - /** - * Intent to broadcast silence mode changed. - * Alway contains the extra field {@link #EXTRA_DEVICE} - * - * @hide - */ - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - @SystemApi - public static final String ACTION_SILENCE_MODE_CHANGED = - "android.bluetooth.device.action.SILENCE_MODE_CHANGED"; - - /** - * Used as an extra field in {@link #ACTION_CONNECTION_ACCESS_REQUEST} intent. - * - * @hide - */ - public static final String EXTRA_ACCESS_REQUEST_TYPE = - "android.bluetooth.device.extra.ACCESS_REQUEST_TYPE"; - - /** @hide */ - public static final int REQUEST_TYPE_PROFILE_CONNECTION = 1; - - /** @hide */ - public static final int REQUEST_TYPE_PHONEBOOK_ACCESS = 2; - - /** @hide */ - public static final int REQUEST_TYPE_MESSAGE_ACCESS = 3; - - /** @hide */ - public static final int REQUEST_TYPE_SIM_ACCESS = 4; - - /** - * Used as an extra field in {@link #ACTION_CONNECTION_ACCESS_REQUEST} intents, - * Contains package name to return reply intent to. - * - * @hide - */ - public static final String EXTRA_PACKAGE_NAME = "android.bluetooth.device.extra.PACKAGE_NAME"; - - /** - * Used as an extra field in {@link #ACTION_CONNECTION_ACCESS_REQUEST} intents, - * Contains class name to return reply intent to. - * - * @hide - */ - public static final String EXTRA_CLASS_NAME = "android.bluetooth.device.extra.CLASS_NAME"; - - /** - * Used as an extra field in {@link #ACTION_CONNECTION_ACCESS_REPLY} intent. - * - * @hide - */ - public static final String EXTRA_CONNECTION_ACCESS_RESULT = - "android.bluetooth.device.extra.CONNECTION_ACCESS_RESULT"; - - /** @hide */ - public static final int CONNECTION_ACCESS_YES = 1; - - /** @hide */ - public static final int CONNECTION_ACCESS_NO = 2; - - /** - * Used as an extra field in {@link #ACTION_CONNECTION_ACCESS_REPLY} intents, - * Contains boolean to indicate if the allowed response is once-for-all so that - * next request will be granted without asking user again. - * - * @hide - */ - public static final String EXTRA_ALWAYS_ALLOWED = - "android.bluetooth.device.extra.ALWAYS_ALLOWED"; - - /** - * A bond attempt succeeded - * - * @hide - */ - public static final int BOND_SUCCESS = 0; - - /** - * A bond attempt failed because pins did not match, or remote device did - * not respond to pin request in time - * - * @hide - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public static final int UNBOND_REASON_AUTH_FAILED = 1; - - /** - * A bond attempt failed because the other side explicitly rejected - * bonding - * - * @hide - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public static final int UNBOND_REASON_AUTH_REJECTED = 2; - - /** - * A bond attempt failed because we canceled the bonding process - * - * @hide - */ - public static final int UNBOND_REASON_AUTH_CANCELED = 3; - - /** - * A bond attempt failed because we could not contact the remote device - * - * @hide - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public static final int UNBOND_REASON_REMOTE_DEVICE_DOWN = 4; - - /** - * A bond attempt failed because a discovery is in progress - * - * @hide - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public static final int UNBOND_REASON_DISCOVERY_IN_PROGRESS = 5; - - /** - * A bond attempt failed because of authentication timeout - * - * @hide - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public static final int UNBOND_REASON_AUTH_TIMEOUT = 6; - - /** - * A bond attempt failed because of repeated attempts - * - * @hide - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public static final int UNBOND_REASON_REPEATED_ATTEMPTS = 7; - - /** - * A bond attempt failed because we received an Authentication Cancel - * by remote end - * - * @hide - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public static final int UNBOND_REASON_REMOTE_AUTH_CANCELED = 8; - - /** - * An existing bond was explicitly revoked - * - * @hide - */ - public static final int UNBOND_REASON_REMOVED = 9; - - /** - * The user will be prompted to enter a pin or - * an app will enter a pin for user. - */ - public static final int PAIRING_VARIANT_PIN = 0; - - /** - * The user will be prompted to enter a passkey - * - * @hide - */ - public static final int PAIRING_VARIANT_PASSKEY = 1; - - /** - * The user will be prompted to confirm the passkey displayed on the screen or - * an app will confirm the passkey for the user. - */ - public static final int PAIRING_VARIANT_PASSKEY_CONFIRMATION = 2; - - /** - * The user will be prompted to accept or deny the incoming pairing request - * - * @hide - */ - public static final int PAIRING_VARIANT_CONSENT = 3; - - /** - * The user will be prompted to enter the passkey displayed on remote device - * This is used for Bluetooth 2.1 pairing. - * - * @hide - */ - public static final int PAIRING_VARIANT_DISPLAY_PASSKEY = 4; - - /** - * The user will be prompted to enter the PIN displayed on remote device. - * This is used for Bluetooth 2.0 pairing. - * - * @hide - */ - public static final int PAIRING_VARIANT_DISPLAY_PIN = 5; - - /** - * The user will be prompted to accept or deny the OOB pairing request - * - * @hide - */ - public static final int PAIRING_VARIANT_OOB_CONSENT = 6; - - /** - * The user will be prompted to enter a 16 digit pin or - * an app will enter a 16 digit pin for user. - * - * @hide - */ - public static final int PAIRING_VARIANT_PIN_16_DIGITS = 7; - - /** - * Used as an extra field in {@link #ACTION_UUID} intents, - * Contains the {@link android.os.ParcelUuid}s of the remote device which - * is a parcelable version of {@link UUID}. - */ - public static final String EXTRA_UUID = "android.bluetooth.device.extra.UUID"; - - /** @hide */ - public static final String EXTRA_SDP_RECORD = - "android.bluetooth.device.extra.SDP_RECORD"; - - /** @hide */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public static final String EXTRA_SDP_SEARCH_STATUS = - "android.bluetooth.device.extra.SDP_SEARCH_STATUS"; - - /** @hide */ - @IntDef(prefix = "ACCESS_", value = {ACCESS_UNKNOWN, - ACCESS_ALLOWED, ACCESS_REJECTED}) - @Retention(RetentionPolicy.SOURCE) - public @interface AccessPermission{} - - /** - * For {@link #getPhonebookAccessPermission}, {@link #setPhonebookAccessPermission}, - * {@link #getMessageAccessPermission} and {@link #setMessageAccessPermission}. - * - * @hide - */ - @SystemApi - public static final int ACCESS_UNKNOWN = 0; - - /** - * For {@link #getPhonebookAccessPermission}, {@link #setPhonebookAccessPermission}, - * {@link #getMessageAccessPermission} and {@link #setMessageAccessPermission}. - * - * @hide - */ - @SystemApi - public static final int ACCESS_ALLOWED = 1; - - /** - * For {@link #getPhonebookAccessPermission}, {@link #setPhonebookAccessPermission}, - * {@link #getMessageAccessPermission} and {@link #setMessageAccessPermission}. - * - * @hide - */ - @SystemApi - public static final int ACCESS_REJECTED = 2; - - /** @hide */ - @Retention(RetentionPolicy.SOURCE) - @IntDef( - prefix = { "TRANSPORT_" }, - value = { - /** Allow host to automatically select a transport (dual-mode only) */ - TRANSPORT_AUTO, - /** Use Classic or BR/EDR transport.*/ - TRANSPORT_BREDR, - /** Use Low Energy transport.*/ - TRANSPORT_LE, - } - ) - public @interface Transport {} - - /** - * No preference of physical transport for GATT connections to remote dual-mode devices - */ - public static final int TRANSPORT_AUTO = 0; - - /** - * Prefer BR/EDR transport for GATT connections to remote dual-mode devices - */ - public static final int TRANSPORT_BREDR = 1; - - /** - * Prefer LE transport for GATT connections to remote dual-mode devices - */ - public static final int TRANSPORT_LE = 2; - - /** - * Bluetooth LE 1M PHY. Used to refer to LE 1M Physical Channel for advertising, scanning or - * connection. - */ - public static final int PHY_LE_1M = 1; - - /** - * Bluetooth LE 2M PHY. Used to refer to LE 2M Physical Channel for advertising, scanning or - * connection. - */ - public static final int PHY_LE_2M = 2; - - /** - * Bluetooth LE Coded PHY. Used to refer to LE Coded Physical Channel for advertising, scanning - * or connection. - */ - public static final int PHY_LE_CODED = 3; - - /** - * Bluetooth LE 1M PHY mask. Used to specify LE 1M Physical Channel as one of many available - * options in a bitmask. - */ - public static final int PHY_LE_1M_MASK = 1; - - /** - * Bluetooth LE 2M PHY mask. Used to specify LE 2M Physical Channel as one of many available - * options in a bitmask. - */ - public static final int PHY_LE_2M_MASK = 2; - - /** - * Bluetooth LE Coded PHY mask. Used to specify LE Coded Physical Channel as one of many - * available options in a bitmask. - */ - public static final int PHY_LE_CODED_MASK = 4; - - /** - * No preferred coding when transmitting on the LE Coded PHY. - */ - public static final int PHY_OPTION_NO_PREFERRED = 0; - - /** - * Prefer the S=2 coding to be used when transmitting on the LE Coded PHY. - */ - public static final int PHY_OPTION_S2 = 1; - - /** - * Prefer the S=8 coding to be used when transmitting on the LE Coded PHY. - */ - public static final int PHY_OPTION_S8 = 2; - - - /** @hide */ - public static final String EXTRA_MAS_INSTANCE = - "android.bluetooth.device.extra.MAS_INSTANCE"; - - /** @hide */ - @Retention(RetentionPolicy.SOURCE) - @IntDef( - prefix = { "ADDRESS_TYPE_" }, - value = { - /** Hardware MAC Address */ - ADDRESS_TYPE_PUBLIC, - /** Address is either resolvable, non-resolvable or static.*/ - ADDRESS_TYPE_RANDOM, - } - ) - public @interface AddressType {} - - /** Hardware MAC Address of the device */ - public static final int ADDRESS_TYPE_PUBLIC = 0; - /** Address is either resolvable, non-resolvable or static. */ - public static final int ADDRESS_TYPE_RANDOM = 1; - - private static final String NULL_MAC_ADDRESS = "00:00:00:00:00:00"; - - /** - * Lazy initialization. Guaranteed final after first object constructed, or - * getService() called. - * TODO: Unify implementation of sService amongst BluetoothFoo API's - */ - private static volatile IBluetooth sService; - - private final String mAddress; - @AddressType private final int mAddressType; - - private AttributionSource mAttributionSource; - - /*package*/ - @UnsupportedAppUsage - static IBluetooth getService() { - synchronized (BluetoothDevice.class) { - if (sService == null) { - BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); - sService = adapter.getBluetoothService(sStateChangeCallback); - } - } - return sService; - } - - static IBluetoothManagerCallback sStateChangeCallback = new IBluetoothManagerCallback.Stub() { - - public void onBluetoothServiceUp(IBluetooth bluetoothService) - throws RemoteException { - synchronized (BluetoothDevice.class) { - if (sService == null) { - sService = bluetoothService; - } - } - } - - public void onBluetoothServiceDown() - throws RemoteException { - synchronized (BluetoothDevice.class) { - sService = null; - } - } - - public void onBrEdrDown() { - if (DBG) Log.d(TAG, "onBrEdrDown: reached BLE ON state"); - } - - public void onOobData(@Transport int transport, OobData oobData) { - if (DBG) Log.d(TAG, "onOobData: got data"); - } - }; - - /** - * Create a new BluetoothDevice - * Bluetooth MAC address must be upper case, such as "00:11:22:33:AA:BB", - * and is validated in this constructor. - * - * @param address valid Bluetooth MAC address - * @param attributionSource attribution for permission-protected calls - * @throws RuntimeException Bluetooth is not available on this platform - * @throws IllegalArgumentException address is invalid - * @hide - */ - @UnsupportedAppUsage - /*package*/ BluetoothDevice(String address) { - getService(); // ensures sService is initialized - if (!BluetoothAdapter.checkBluetoothAddress(address)) { - throw new IllegalArgumentException(address + " is not a valid Bluetooth address"); - } - - mAddress = address; - mAddressType = ADDRESS_TYPE_PUBLIC; - mAttributionSource = AttributionSource.myAttributionSource(); - } - - /** {@hide} */ - public void setAttributionSource(@NonNull AttributionSource attributionSource) { - mAttributionSource = attributionSource; - } - - /** {@hide} */ - public void prepareToEnterProcess(@NonNull AttributionSource attributionSource) { - setAttributionSource(attributionSource); - } - - @Override - public boolean equals(@Nullable Object o) { - if (o instanceof BluetoothDevice) { - return mAddress.equals(((BluetoothDevice) o).getAddress()); - } - return false; - } - - @Override - public int hashCode() { - return mAddress.hashCode(); - } - - /** - * Returns a string representation of this BluetoothDevice. - *

Currently this is the Bluetooth hardware address, for example - * "00:11:22:AA:BB:CC". However, you should always use {@link #getAddress} - * if you explicitly require the Bluetooth hardware address in case the - * {@link #toString} representation changes in the future. - * - * @return string representation of this BluetoothDevice - */ - @Override - public String toString() { - return mAddress; - } - - @Override - public int describeContents() { - return 0; - } - - public static final @android.annotation.NonNull Parcelable.Creator CREATOR = - new Parcelable.Creator() { - public BluetoothDevice createFromParcel(Parcel in) { - return new BluetoothDevice(in.readString()); - } - - public BluetoothDevice[] newArray(int size) { - return new BluetoothDevice[size]; - } - }; - - @Override - public void writeToParcel(Parcel out, int flags) { - out.writeString(mAddress); - } - - /** - * Returns the hardware address of this BluetoothDevice. - *

For example, "00:11:22:AA:BB:CC". - * - * @return Bluetooth hardware address as string - */ - public String getAddress() { - if (DBG) Log.d(TAG, "mAddress: " + mAddress); - return mAddress; - } - - /** - * Returns the anonymized hardware address of this BluetoothDevice. The first three octets - * will be suppressed for anonymization. - *

For example, "XX:XX:XX:AA:BB:CC". - * - * @return Anonymized bluetooth hardware address as string - * @hide - */ - public String getAnonymizedAddress() { - return "XX:XX:XX" + getAddress().substring(8); - } - - /** - * Get the friendly Bluetooth name of the remote device. - * - *

The local adapter will automatically retrieve remote names when - * performing a device scan, and will cache them. This method just returns - * the name for this device from the cache. - * - * @return the Bluetooth name, or null if there was a problem. - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public String getName() { - final IBluetooth service = sService; - if (service == null) { - Log.e(TAG, "BT not enabled. Cannot get Remote Device name"); - return null; - } - try { - String name = service.getRemoteName(this, mAttributionSource); - if (name != null) { - // remove whitespace characters from the name - return name - .replace('\t', ' ') - .replace('\n', ' ') - .replace('\r', ' '); - } - return null; - } catch (RemoteException e) { - Log.e(TAG, "", e); - } - return null; - } - - /** - * Get the Bluetooth device type of the remote device. - * - * @return the device type {@link #DEVICE_TYPE_CLASSIC}, {@link #DEVICE_TYPE_LE} {@link - * #DEVICE_TYPE_DUAL}. {@link #DEVICE_TYPE_UNKNOWN} if it's not available - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public int getType() { - final IBluetooth service = sService; - if (service == null) { - Log.e(TAG, "BT not enabled. Cannot get Remote Device type"); - return DEVICE_TYPE_UNKNOWN; - } - try { - return service.getRemoteType(this, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "", e); - } - return DEVICE_TYPE_UNKNOWN; - } - - /** - * Get the locally modifiable name (alias) of the remote Bluetooth device. - * - * @return the Bluetooth alias, the friendly device name if no alias, or - * null if there was a problem - */ - @Nullable - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public String getAlias() { - final IBluetooth service = sService; - if (service == null) { - Log.e(TAG, "BT not enabled. Cannot get Remote Device Alias"); - return null; - } - try { - String alias = service.getRemoteAliasWithAttribution(this, mAttributionSource); - if (alias == null) { - return getName(); - } - return alias - .replace('\t', ' ') - .replace('\n', ' ') - .replace('\r', ' '); - } catch (RemoteException e) { - Log.e(TAG, "", e); - } - return null; - } - - /** @hide */ - @Retention(RetentionPolicy.SOURCE) - @IntDef(value = { - BluetoothStatusCodes.SUCCESS, - BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED, - BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ALLOWED, - BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION, - BluetoothStatusCodes.ERROR_DEVICE_NOT_BONDED - }) - public @interface SetAliasReturnValues{} - - /** - * Sets the locally modifiable name (alias) of the remote Bluetooth device. This method - * overwrites the previously stored alias. The new alias is saved in local - * storage so that the change is preserved over power cycles. - * - *

This method requires the calling app to be associated with Companion Device Manager (see - * {@link android.companion.CompanionDeviceManager#associate(AssociationRequest, - * android.companion.CompanionDeviceManager.Callback, Handler)}) and have the - * {@link android.Manifest.permission#BLUETOOTH_CONNECT} permission. Alternatively, if the - * caller has the {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED} permission, they can - * bypass the Companion Device Manager association requirement as well as other permission - * requirements. - * - * @param alias is the new locally modifiable name for the remote Bluetooth device which must - * be the empty string. If null, we clear the alias. - * @return whether the alias was successfully changed - * @throws IllegalArgumentException if the alias is the empty string - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public @SetAliasReturnValues int setAlias(@Nullable String alias) { - if (alias != null && alias.isEmpty()) { - throw new IllegalArgumentException("alias cannot be the empty string"); - } - final IBluetooth service = sService; - if (service == null) { - Log.e(TAG, "BT not enabled. Cannot set Remote Device name"); - return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED; - } - try { - return service.setRemoteAlias(this, alias, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "", e); - throw e.rethrowFromSystemServer(); - } - } - - /** - * Get the most recent identified battery level of this Bluetooth device - * - * @return Battery level in percents from 0 to 100, {@link #BATTERY_LEVEL_BLUETOOTH_OFF} if - * Bluetooth is disabled or {@link #BATTERY_LEVEL_UNKNOWN} if device is disconnected, or does - * not have any battery reporting service, or return value is invalid - * @hide - */ - @UnsupportedAppUsage - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public int getBatteryLevel() { - final IBluetooth service = sService; - if (service == null) { - Log.e(TAG, "Bluetooth disabled. Cannot get remote device battery level"); - return BATTERY_LEVEL_BLUETOOTH_OFF; - } - try { - return service.getBatteryLevel(this, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "", e); - } - return BATTERY_LEVEL_UNKNOWN; - } - - /** - * Start the bonding (pairing) process with the remote device. - *

This is an asynchronous call, it will return immediately. Register - * for {@link #ACTION_BOND_STATE_CHANGED} intents to be notified when - * the bonding process completes, and its result. - *

Android system services will handle the necessary user interactions - * to confirm and complete the bonding process. - * - * @return false on immediate error, true if bonding will begin - */ - @RequiresLegacyBluetoothAdminPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public boolean createBond() { - return createBond(TRANSPORT_AUTO); - } - - /** - * Start the bonding (pairing) process with the remote device using the - * specified transport. - * - *

This is an asynchronous call, it will return immediately. Register - * for {@link #ACTION_BOND_STATE_CHANGED} intents to be notified when - * the bonding process completes, and its result. - *

Android system services will handle the necessary user interactions - * to confirm and complete the bonding process. - * - * @param transport The transport to use for the pairing procedure. - * @return false on immediate error, true if bonding will begin - * @throws IllegalArgumentException if an invalid transport was specified - * @hide - */ - @SystemApi - @RequiresLegacyBluetoothAdminPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public boolean createBond(int transport) { - return createBondInternal(transport, null, null); - } - - /** - * Start the bonding (pairing) process with the remote device using the - * Out Of Band mechanism. - * - *

This is an asynchronous call, it will return immediately. Register - * for {@link #ACTION_BOND_STATE_CHANGED} intents to be notified when - * the bonding process completes, and its result. - * - *

Android system services will handle the necessary user interactions - * to confirm and complete the bonding process. - * - *

There are two possible versions of OOB Data. This data can come in as - * P192 or P256. This is a reference to the cryptography used to generate the key. - * The caller may pass one or both. If both types of data are passed, then the - * P256 data will be preferred, and thus used. - * - * @param transport - Transport to use - * @param remoteP192Data - Out Of Band data (P192) or null - * @param remoteP256Data - Out Of Band data (P256) or null - * @return false on immediate error, true if bonding will begin - * @hide - */ - @SystemApi - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public boolean createBondOutOfBand(int transport, @Nullable OobData remoteP192Data, - @Nullable OobData remoteP256Data) { - if (remoteP192Data == null && remoteP256Data == null) { - throw new IllegalArgumentException( - "One or both arguments for the OOB data types are required to not be null." - + " Please use createBond() instead if you do not have OOB data to pass."); - } - return createBondInternal(transport, remoteP192Data, remoteP256Data); - } - - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - private boolean createBondInternal(int transport, @Nullable OobData remoteP192Data, - @Nullable OobData remoteP256Data) { - final IBluetooth service = sService; - if (service == null) { - Log.w(TAG, "BT not enabled, createBondOutOfBand failed"); - return false; - } - if (NULL_MAC_ADDRESS.equals(mAddress)) { - Log.e(TAG, "Unable to create bond, invalid address " + mAddress); - return false; - } - try { - return service.createBond( - this, transport, remoteP192Data, remoteP256Data, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "", e); - } - return false; - } - - /** - * Gets whether bonding was initiated locally - * - * @return true if bonding is initiated locally, false otherwise - * - * @hide - */ - @UnsupportedAppUsage - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public boolean isBondingInitiatedLocally() { - final IBluetooth service = sService; - if (service == null) { - Log.w(TAG, "BT not enabled, isBondingInitiatedLocally failed"); - return false; - } - try { - return service.isBondingInitiatedLocally(this, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "", e); - } - return false; - } - - /** - * Cancel an in-progress bonding request started with {@link #createBond}. - * - * @return true on success, false on error - * @hide - */ - @SystemApi - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public boolean cancelBondProcess() { - final IBluetooth service = sService; - if (service == null) { - Log.e(TAG, "BT not enabled. Cannot cancel Remote Device bond"); - return false; - } - try { - Log.i(TAG, "cancelBondProcess() for device " + getAddress() - + " called by pid: " + Process.myPid() - + " tid: " + Process.myTid()); - return service.cancelBondProcess(this, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "", e); - } - return false; - } - - /** - * Remove bond (pairing) with the remote device. - *

Delete the link key associated with the remote device, and - * immediately terminate connections to that device that require - * authentication and encryption. - * - * @return true on success, false on error - * @hide - */ - @SystemApi - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public boolean removeBond() { - final IBluetooth service = sService; - if (service == null) { - Log.e(TAG, "BT not enabled. Cannot remove Remote Device bond"); - return false; - } - try { - Log.i(TAG, "removeBond() for device " + getAddress() - + " called by pid: " + Process.myPid() - + " tid: " + Process.myTid()); - return service.removeBond(this, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "", e); - } - return false; - } - - /* - private static final String BLUETOOTH_BONDING_CACHE_PROPERTY = - "cache_key.bluetooth.get_bond_state"; - private final PropertyInvalidatedCache mBluetoothBondCache = - new PropertyInvalidatedCache( - 8, BLUETOOTH_BONDING_CACHE_PROPERTY) { - @Override - @SuppressLint("AndroidFrameworkRequiresPermission") - protected Integer recompute(BluetoothDevice query) { - try { - return sService.getBondState(query, mAttributionSource); - } catch (RemoteException e) { - throw e.rethrowAsRuntimeException(); - } - } - }; - */ - - /** @hide */ - /* public void disableBluetoothGetBondStateCache() { - mBluetoothBondCache.disableLocal(); - } */ - - /** @hide */ - /* - public static void invalidateBluetoothGetBondStateCache() { - PropertyInvalidatedCache.invalidateCache(BLUETOOTH_BONDING_CACHE_PROPERTY); - } - */ - - /** - * Get the bond state of the remote device. - *

Possible values for the bond state are: - * {@link #BOND_NONE}, - * {@link #BOND_BONDING}, - * {@link #BOND_BONDED}. - * - * @return the bond state - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - @SuppressLint("AndroidFrameworkRequiresPermission") - public int getBondState() { - final IBluetooth service = sService; - if (service == null) { - Log.e(TAG, "BT not enabled. Cannot get bond state"); - return BOND_NONE; - } - try { - //return mBluetoothBondCache.query(this); - return sService.getBondState(this, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "failed to ", e); - e.rethrowFromSystemServer(); - } - return BOND_NONE; - } - - /** - * Checks whether this bluetooth device is associated with CDM and meets the criteria to skip - * the bluetooth pairing dialog because it has been already consented by the CDM prompt. - * - * @return true if we can bond without the dialog, false otherwise - * - * @hide - */ - @SystemApi - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) - public boolean canBondWithoutDialog() { - final IBluetooth service = sService; - if (service == null) { - Log.e(TAG, "BT not enabled. Cannot check if we can skip pairing dialog"); - return false; - } - try { - if (DBG) Log.d(TAG, "canBondWithoutDialog, device: " + this); - return service.canBondWithoutDialog(this, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "", e); - } - return false; - } - - /** @hide */ - @Retention(RetentionPolicy.SOURCE) - @IntDef(value = { - BluetoothStatusCodes.SUCCESS, - BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED, - BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ALLOWED, - BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION, - BluetoothStatusCodes.ERROR_DEVICE_NOT_BONDED - }) - public @interface ConnectionReturnValues{} - - /** - * Connects all user enabled and supported bluetooth profiles between the local and remote - * device. If no profiles are user enabled (e.g. first connection), we connect all supported - * profiles. If the device is not already connected, this will page the device before initiating - * profile connections. Connection is asynchronous and you should listen to each profile's - * broadcast intent ACTION_CONNECTION_STATE_CHANGED to verify whether connection was successful. - * For example, to verify a2dp is connected, you would listen for - * {@link BluetoothA2dp#ACTION_CONNECTION_STATE_CHANGED} - * - * @return whether the messages were successfully sent to try to connect all profiles - * @throws IllegalArgumentException if the device address is invalid - * - * @hide - */ - @SystemApi - @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - android.Manifest.permission.MODIFY_PHONE_STATE, - }) - public @ConnectionReturnValues int connect() { - if (!BluetoothAdapter.checkBluetoothAddress(getAddress())) { - throw new IllegalArgumentException("device cannot have an invalid address"); - } - - try { - if (sService == null) { - Log.e(TAG, "BT not enabled. Cannot connect to remote device."); - return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED; - } - return sService.connectAllEnabledProfiles(this, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "", e); - throw e.rethrowFromSystemServer(); - } - } - - /** - * Disconnects all connected bluetooth profiles between the local and remote device. - * Disconnection is asynchronous and you should listen to each profile's broadcast intent - * ACTION_CONNECTION_STATE_CHANGED to verify whether disconnection was successful. For example, - * to verify a2dp is disconnected, you would listen for - * {@link BluetoothA2dp#ACTION_CONNECTION_STATE_CHANGED} - * - * @return whether the messages were successfully sent to try to disconnect all profiles - * @throws IllegalArgumentException if the device address is invalid - * - * @hide - */ - @SystemApi - @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) - public @ConnectionReturnValues int disconnect() { - if (!BluetoothAdapter.checkBluetoothAddress(getAddress())) { - throw new IllegalArgumentException("device cannot have an invalid address"); - } - - try { - if (sService == null) { - Log.e(TAG, "BT not enabled. Cannot disconnect from remote device."); - return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED; - } - return sService.disconnectAllEnabledProfiles(this, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "", e); - throw e.rethrowFromSystemServer(); - } - } - - /** - * Returns whether there is an open connection to this device. - * - * @return True if there is at least one open connection to this device. - * @hide - */ - @SystemApi - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public boolean isConnected() { - final IBluetooth service = sService; - if (service == null) { - // BT is not enabled, we cannot be connected. - return false; - } - try { - return service.getConnectionStateWithAttribution(this, mAttributionSource) - != CONNECTION_STATE_DISCONNECTED; - } catch (RemoteException e) { - Log.e(TAG, "", e); - return false; - } - } - - /** - * Returns whether there is an open connection to this device - * that has been encrypted. - * - * @return True if there is at least one encrypted connection to this device. - * @hide - */ - @SystemApi - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public boolean isEncrypted() { - final IBluetooth service = sService; - if (service == null) { - // BT is not enabled, we cannot be connected. - return false; - } - try { - return service.getConnectionStateWithAttribution(this, mAttributionSource) - > CONNECTION_STATE_CONNECTED; - } catch (RemoteException e) { - Log.e(TAG, "", e); - return false; - } - } - - /** - * Get the Bluetooth class of the remote device. - * - * @return Bluetooth class object, or null on error - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public BluetoothClass getBluetoothClass() { - final IBluetooth service = sService; - if (service == null) { - Log.e(TAG, "BT not enabled. Cannot get Bluetooth Class"); - return null; - } - try { - int classInt = service.getRemoteClass(this, mAttributionSource); - if (classInt == BluetoothClass.ERROR) return null; - return new BluetoothClass(classInt); - } catch (RemoteException e) { - Log.e(TAG, "", e); - } - return null; - } - - /** - * Returns the supported features (UUIDs) of the remote device. - * - *

This method does not start a service discovery procedure to retrieve the UUIDs - * from the remote device. Instead, the local cached copy of the service - * UUIDs are returned. - *

Use {@link #fetchUuidsWithSdp} if fresh UUIDs are desired. - * - * @return the supported features (UUIDs) of the remote device, or null on error - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public ParcelUuid[] getUuids() { - final IBluetooth service = sService; - if (service == null || !isBluetoothEnabled()) { - Log.e(TAG, "BT not enabled. Cannot get remote device Uuids"); - return null; - } - try { - return service.getRemoteUuids(this, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "", e); - } - return null; - } - - /** - * Perform a service discovery on the remote device to get the UUIDs supported. - * - *

This API is asynchronous and {@link #ACTION_UUID} intent is sent, - * with the UUIDs supported by the remote end. If there is an error - * in getting the SDP records or if the process takes a long time, or the device is bonding and - * we have its UUIDs cached, {@link #ACTION_UUID} intent is sent with the UUIDs that is - * currently present in the cache. Clients should use the {@link #getUuids} to get UUIDs - * if service discovery is not to be performed. If there is an ongoing bonding process, - * service discovery or device inquiry, the request will be queued. - * - * @return False if the check fails, True if the process of initiating an ACL connection - * to the remote device was started or cached UUIDs will be broadcast. - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public boolean fetchUuidsWithSdp() { - return fetchUuidsWithSdp(TRANSPORT_AUTO); - } - - /** - * Perform a service discovery on the remote device to get the UUIDs supported with the - * specific transport. - * - *

This API is asynchronous and {@link #ACTION_UUID} intent is sent, - * with the UUIDs supported by the remote end. If there is an error - * in getting the SDP or GATT records or if the process takes a long time, or the device - * is bonding and we have its UUIDs cached, {@link #ACTION_UUID} intent is sent with the - * UUIDs that is currently present in the cache. Clients should use the {@link #getUuids} - * to get UUIDs if service discovery is not to be performed. If there is an ongoing bonding - * process, service discovery or device inquiry, the request will be queued. - * - * @param transport - provide type of transport (e.g. LE or Classic). - * @return False if the check fails, True if the process of initiating an ACL connection - * to the remote device was started or cached UUIDs will be broadcast with the specific - * transport. - * - * @hide - */ - @SystemApi - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) - public boolean fetchUuidsWithSdp(@Transport int transport) { - final IBluetooth service = sService; - if (service == null || !isBluetoothEnabled()) { - Log.e(TAG, "BT not enabled. Cannot fetchUuidsWithSdp"); - return false; - } - try { - return service.fetchRemoteUuidsWithAttribution(this, transport, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "", e); - } - return false; - } - - /** - * Perform a service discovery on the remote device to get the SDP records associated - * with the specified UUID. - * - *

This API is asynchronous and {@link #ACTION_SDP_RECORD} intent is sent, - * with the SDP records found on the remote end. If there is an error - * in getting the SDP records or if the process takes a long time, - * {@link #ACTION_SDP_RECORD} intent is sent with an status value in - * {@link #EXTRA_SDP_SEARCH_STATUS} different from 0. - * Detailed status error codes can be found by members of the Bluetooth package in - * the AbstractionLayer class. - *

The SDP record data will be stored in the intent as {@link #EXTRA_SDP_RECORD}. - * The object type will match one of the SdpXxxRecord types, depending on the UUID searched - * for. - * - * @return False if the check fails, True if the process - * of initiating an ACL connection to the remote device - * was started. - */ - /** @hide */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public boolean sdpSearch(ParcelUuid uuid) { - final IBluetooth service = sService; - if (service == null) { - Log.e(TAG, "BT not enabled. Cannot query remote device sdp records"); - return false; - } - try { - return service.sdpSearch(this, uuid, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "", e); - } - return false; - } - - /** - * Set the pin during pairing when the pairing method is {@link #PAIRING_VARIANT_PIN} - * - * @return true pin has been set false for error - */ - @RequiresLegacyBluetoothAdminPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public boolean setPin(byte[] pin) { - final IBluetooth service = sService; - if (service == null) { - Log.e(TAG, "BT not enabled. Cannot set Remote Device pin"); - return false; - } - try { - return service.setPin(this, true, pin.length, pin, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "", e); - } - return false; - } - - /** - * Set the pin during pairing when the pairing method is {@link #PAIRING_VARIANT_PIN} - * - * @return true pin has been set false for error - * @hide - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - @RequiresLegacyBluetoothAdminPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public boolean setPin(@NonNull String pin) { - byte[] pinBytes = convertPinToBytes(pin); - if (pinBytes == null) { - return false; - } - return setPin(pinBytes); - } - - /** - * Confirm passkey for {@link #PAIRING_VARIANT_PASSKEY_CONFIRMATION} pairing. - * - * @return true confirmation has been sent out false for error - */ - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) - public boolean setPairingConfirmation(boolean confirm) { - final IBluetooth service = sService; - if (service == null) { - Log.e(TAG, "BT not enabled. Cannot set pairing confirmation"); - return false; - } - try { - return service.setPairingConfirmation(this, confirm, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "", e); - } - return false; - } - - /** - * Cancels pairing to this device - * - * @return true if pairing cancelled successfully, false otherwise - * - * @hide - */ - @UnsupportedAppUsage - @RequiresLegacyBluetoothAdminPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public boolean cancelPairing() { - final IBluetooth service = sService; - if (service == null) { - Log.e(TAG, "BT not enabled. Cannot cancel pairing"); - return false; - } - try { - return service.cancelBondProcess(this, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "", e); - } - return false; - } - - boolean isBluetoothEnabled() { - boolean ret = false; - BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); - if (adapter != null && adapter.isEnabled()) { - ret = true; - } - return ret; - } - - /** - * Gets whether the phonebook access is allowed for this bluetooth device - * - * @return Whether the phonebook access is allowed to this device. Can be {@link - * #ACCESS_UNKNOWN}, {@link #ACCESS_ALLOWED} or {@link #ACCESS_REJECTED}. - * @hide - */ - @UnsupportedAppUsage - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public @AccessPermission int getPhonebookAccessPermission() { - final IBluetooth service = sService; - if (service == null) { - return ACCESS_UNKNOWN; - } - try { - return service.getPhonebookAccessPermission(this, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "", e); - } - return ACCESS_UNKNOWN; - } - - /** - * Sets whether the {@link BluetoothDevice} enters silence mode. Audio will not - * be routed to the {@link BluetoothDevice} if set to {@code true}. - * - * When the {@link BluetoothDevice} enters silence mode, and the {@link BluetoothDevice} - * is an active device (for A2DP or HFP), the active device for that profile - * will be set to null. - * If the {@link BluetoothDevice} exits silence mode while the A2DP or HFP - * active device is null, the {@link BluetoothDevice} will be set as the - * active device for that profile. - * If the {@link BluetoothDevice} is disconnected, it exits silence mode. - * If the {@link BluetoothDevice} is set as the active device for A2DP or - * HFP, while silence mode is enabled, then the device will exit silence mode. - * If the {@link BluetoothDevice} is in silence mode, AVRCP position change - * event and HFP AG indicators will be disabled. - * If the {@link BluetoothDevice} is not connected with A2DP or HFP, it cannot - * enter silence mode. - * - * @param silence true to enter silence mode, false to exit - * @return true on success, false on error. - * @throws IllegalStateException if Bluetooth is not turned ON. - * @hide - */ - @SystemApi - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) - public boolean setSilenceMode(boolean silence) { - final IBluetooth service = sService; - if (service == null) { - throw new IllegalStateException("Bluetooth is not turned ON"); - } - try { - return service.setSilenceMode(this, silence, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "setSilenceMode fail", e); - return false; - } - } - - /** - * Check whether the {@link BluetoothDevice} is in silence mode - * - * @return true on device in silence mode, otherwise false. - * @throws IllegalStateException if Bluetooth is not turned ON. - * @hide - */ - @SystemApi - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) - public boolean isInSilenceMode() { - final IBluetooth service = sService; - if (service == null) { - throw new IllegalStateException("Bluetooth is not turned ON"); - } - try { - return service.getSilenceMode(this, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "isInSilenceMode fail", e); - return false; - } - } - - /** - * Sets whether the phonebook access is allowed to this device. - * - * @param value Can be {@link #ACCESS_UNKNOWN}, {@link #ACCESS_ALLOWED} or {@link - * #ACCESS_REJECTED}. - * @return Whether the value has been successfully set. - * @hide - */ - @SystemApi - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) - public boolean setPhonebookAccessPermission(@AccessPermission int value) { - final IBluetooth service = sService; - if (service == null) { - return false; - } - try { - return service.setPhonebookAccessPermission(this, value, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "", e); - } - return false; - } - - /** - * Gets whether message access is allowed to this bluetooth device - * - * @return Whether the message access is allowed to this device. - * @hide - */ - @UnsupportedAppUsage - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public @AccessPermission int getMessageAccessPermission() { - final IBluetooth service = sService; - if (service == null) { - return ACCESS_UNKNOWN; - } - try { - return service.getMessageAccessPermission(this, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "", e); - } - return ACCESS_UNKNOWN; - } - - /** - * Sets whether the message access is allowed to this device. - * - * @param value Can be {@link #ACCESS_UNKNOWN} if the device is unbonded, - * {@link #ACCESS_ALLOWED} if the permission is being granted, or {@link #ACCESS_REJECTED} if - * the permission is not being granted. - * @return Whether the value has been successfully set. - * @hide - */ - @SystemApi - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) - public boolean setMessageAccessPermission(@AccessPermission int value) { - // Validates param value is one of the accepted constants - if (value != ACCESS_ALLOWED && value != ACCESS_REJECTED && value != ACCESS_UNKNOWN) { - throw new IllegalArgumentException(value + "is not a valid AccessPermission value"); - } - final IBluetooth service = sService; - if (service == null) { - return false; - } - try { - return service.setMessageAccessPermission(this, value, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "", e); - } - return false; - } - - /** - * Gets whether sim access is allowed for this bluetooth device - * - * @return Whether the Sim access is allowed to this device. - * @hide - */ - @SystemApi - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public @AccessPermission int getSimAccessPermission() { - final IBluetooth service = sService; - if (service == null) { - return ACCESS_UNKNOWN; - } - try { - return service.getSimAccessPermission(this, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "", e); - } - return ACCESS_UNKNOWN; - } - - /** - * Sets whether the Sim access is allowed to this device. - * - * @param value Can be {@link #ACCESS_UNKNOWN} if the device is unbonded, - * {@link #ACCESS_ALLOWED} if the permission is being granted, or {@link #ACCESS_REJECTED} if - * the permission is not being granted. - * @return Whether the value has been successfully set. - * @hide - */ - @SystemApi - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) - public boolean setSimAccessPermission(int value) { - final IBluetooth service = sService; - if (service == null) { - return false; - } - try { - return service.setSimAccessPermission(this, value, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "", e); - } - return false; - } - - /** - * Create an RFCOMM {@link BluetoothSocket} ready to start a secure - * outgoing connection to this remote device on given channel. - *

The remote device will be authenticated and communication on this - * socket will be encrypted. - *

Use this socket only if an authenticated socket link is possible. - * Authentication refers to the authentication of the link key to - * prevent person-in-the-middle type of attacks. - * For example, for Bluetooth 2.1 devices, if any of the devices does not - * have an input and output capability or just has the ability to - * display a numeric key, a secure socket connection is not possible. - * In such a case, use {@link createInsecureRfcommSocket}. - * For more details, refer to the Security Model section 5.2 (vol 3) of - * Bluetooth Core Specification version 2.1 + EDR. - *

Use {@link BluetoothSocket#connect} to initiate the outgoing - * connection. - *

Valid RFCOMM channels are in range 1 to 30. - * - * @param channel RFCOMM channel to connect to - * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection - * @throws IOException on error, for example Bluetooth not available, or insufficient - * permissions - * @hide - */ - @UnsupportedAppUsage - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - @SuppressLint("AndroidFrameworkRequiresPermission") - public BluetoothSocket createRfcommSocket(int channel) throws IOException { - if (!isBluetoothEnabled()) { - Log.e(TAG, "Bluetooth is not enabled"); - throw new IOException(); - } - return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, true, true, this, channel, - null); - } - - /** - * Create an L2cap {@link BluetoothSocket} ready to start a secure - * outgoing connection to this remote device on given channel. - *

The remote device will be authenticated and communication on this - * socket will be encrypted. - *

Use this socket only if an authenticated socket link is possible. - * Authentication refers to the authentication of the link key to - * prevent person-in-the-middle type of attacks. - * For example, for Bluetooth 2.1 devices, if any of the devices does not - * have an input and output capability or just has the ability to - * display a numeric key, a secure socket connection is not possible. - * In such a case, use {@link createInsecureRfcommSocket}. - * For more details, refer to the Security Model section 5.2 (vol 3) of - * Bluetooth Core Specification version 2.1 + EDR. - *

Use {@link BluetoothSocket#connect} to initiate the outgoing - * connection. - *

Valid L2CAP PSM channels are in range 1 to 2^16. - * - * @param channel L2cap PSM/channel to connect to - * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection - * @throws IOException on error, for example Bluetooth not available, or insufficient - * permissions - * @hide - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - @SuppressLint("AndroidFrameworkRequiresPermission") - public BluetoothSocket createL2capSocket(int channel) throws IOException { - return new BluetoothSocket(BluetoothSocket.TYPE_L2CAP, -1, true, true, this, channel, - null); - } - - /** - * Create an L2cap {@link BluetoothSocket} ready to start an insecure - * outgoing connection to this remote device on given channel. - *

The remote device will be not authenticated and communication on this - * socket will not be encrypted. - *

Use {@link BluetoothSocket#connect} to initiate the outgoing - * connection. - *

Valid L2CAP PSM channels are in range 1 to 2^16. - * - * @param channel L2cap PSM/channel to connect to - * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection - * @throws IOException on error, for example Bluetooth not available, or insufficient - * permissions - * @hide - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - @SuppressLint("AndroidFrameworkRequiresPermission") - public BluetoothSocket createInsecureL2capSocket(int channel) throws IOException { - return new BluetoothSocket(BluetoothSocket.TYPE_L2CAP, -1, false, false, this, channel, - null); - } - - /** - * Create an RFCOMM {@link BluetoothSocket} ready to start a secure - * outgoing connection to this remote device using SDP lookup of uuid. - *

This is designed to be used with {@link - * BluetoothAdapter#listenUsingRfcommWithServiceRecord} for peer-peer - * Bluetooth applications. - *

Use {@link BluetoothSocket#connect} to initiate the outgoing - * connection. This will also perform an SDP lookup of the given uuid to - * determine which channel to connect to. - *

The remote device will be authenticated and communication on this - * socket will be encrypted. - *

Use this socket only if an authenticated socket link is possible. - * Authentication refers to the authentication of the link key to - * prevent person-in-the-middle type of attacks. - * For example, for Bluetooth 2.1 devices, if any of the devices does not - * have an input and output capability or just has the ability to - * display a numeric key, a secure socket connection is not possible. - * In such a case, use {@link #createInsecureRfcommSocketToServiceRecord}. - * For more details, refer to the Security Model section 5.2 (vol 3) of - * Bluetooth Core Specification version 2.1 + EDR. - *

Hint: If you are connecting to a Bluetooth serial board then try - * using the well-known SPP UUID 00001101-0000-1000-8000-00805F9B34FB. - * However if you are connecting to an Android peer then please generate - * your own unique UUID. - * - * @param uuid service record uuid to lookup RFCOMM channel - * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection - * @throws IOException on error, for example Bluetooth not available, or insufficient - * permissions - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - @SuppressLint("AndroidFrameworkRequiresPermission") - public BluetoothSocket createRfcommSocketToServiceRecord(UUID uuid) throws IOException { - if (!isBluetoothEnabled()) { - Log.e(TAG, "Bluetooth is not enabled"); - throw new IOException(); - } - - return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, true, true, this, -1, - new ParcelUuid(uuid)); - } - - /** - * Create an RFCOMM {@link BluetoothSocket} socket ready to start an insecure - * outgoing connection to this remote device using SDP lookup of uuid. - *

The communication channel will not have an authenticated link key - * i.e it will be subject to person-in-the-middle attacks. For Bluetooth 2.1 - * devices, the link key will be encrypted, as encryption is mandatory. - * For legacy devices (pre Bluetooth 2.1 devices) the link key will - * be not be encrypted. Use {@link #createRfcommSocketToServiceRecord} if an - * encrypted and authenticated communication channel is desired. - *

This is designed to be used with {@link - * BluetoothAdapter#listenUsingInsecureRfcommWithServiceRecord} for peer-peer - * Bluetooth applications. - *

Use {@link BluetoothSocket#connect} to initiate the outgoing - * connection. This will also perform an SDP lookup of the given uuid to - * determine which channel to connect to. - *

The remote device will be authenticated and communication on this - * socket will be encrypted. - *

Hint: If you are connecting to a Bluetooth serial board then try - * using the well-known SPP UUID 00001101-0000-1000-8000-00805F9B34FB. - * However if you are connecting to an Android peer then please generate - * your own unique UUID. - * - * @param uuid service record uuid to lookup RFCOMM channel - * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection - * @throws IOException on error, for example Bluetooth not available, or insufficient - * permissions - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - @SuppressLint("AndroidFrameworkRequiresPermission") - public BluetoothSocket createInsecureRfcommSocketToServiceRecord(UUID uuid) throws IOException { - if (!isBluetoothEnabled()) { - Log.e(TAG, "Bluetooth is not enabled"); - throw new IOException(); - } - return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, false, false, this, -1, - new ParcelUuid(uuid)); - } - - /** - * Construct an insecure RFCOMM socket ready to start an outgoing - * connection. - * Call #connect on the returned #BluetoothSocket to begin the connection. - * The remote device will not be authenticated and communication on this - * socket will not be encrypted. - * - * @param port remote port - * @return An RFCOMM BluetoothSocket - * @throws IOException On error, for example Bluetooth not available, or insufficient - * permissions. - * @hide - */ - @UnsupportedAppUsage(publicAlternatives = "Use " - + "{@link #createInsecureRfcommSocketToServiceRecord} instead.") - @RequiresLegacyBluetoothAdminPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - @SuppressLint("AndroidFrameworkRequiresPermission") - public BluetoothSocket createInsecureRfcommSocket(int port) throws IOException { - if (!isBluetoothEnabled()) { - Log.e(TAG, "Bluetooth is not enabled"); - throw new IOException(); - } - return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, false, false, this, port, - null); - } - - /** - * Construct a SCO socket ready to start an outgoing connection. - * Call #connect on the returned #BluetoothSocket to begin the connection. - * - * @return a SCO BluetoothSocket - * @throws IOException on error, for example Bluetooth not available, or insufficient - * permissions. - * @hide - */ - @UnsupportedAppUsage - @RequiresLegacyBluetoothAdminPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - @SuppressLint("AndroidFrameworkRequiresPermission") - public BluetoothSocket createScoSocket() throws IOException { - if (!isBluetoothEnabled()) { - Log.e(TAG, "Bluetooth is not enabled"); - throw new IOException(); - } - return new BluetoothSocket(BluetoothSocket.TYPE_SCO, -1, true, true, this, -1, null); - } - - /** - * Check that a pin is valid and convert to byte array. - * - * Bluetooth pin's are 1 to 16 bytes of UTF-8 characters. - * - * @param pin pin as java String - * @return the pin code as a UTF-8 byte array, or null if it is an invalid Bluetooth pin. - * @hide - */ - @UnsupportedAppUsage - public static byte[] convertPinToBytes(String pin) { - if (pin == null) { - return null; - } - byte[] pinBytes; - try { - pinBytes = pin.getBytes("UTF-8"); - } catch (UnsupportedEncodingException uee) { - Log.e(TAG, "UTF-8 not supported?!?"); // this should not happen - return null; - } - if (pinBytes.length <= 0 || pinBytes.length > 16) { - return null; - } - return pinBytes; - } - - /** - * Connect to GATT Server hosted by this device. Caller acts as GATT client. - * The callback is used to deliver results to Caller, such as connection status as well - * as any further GATT client operations. - * The method returns a BluetoothGatt instance. You can use BluetoothGatt to conduct - * GATT client operations. - * - * @param callback GATT callback handler that will receive asynchronous callbacks. - * @param autoConnect Whether to directly connect to the remote device (false) or to - * automatically connect as soon as the remote device becomes available (true). - * @throws IllegalArgumentException if callback is null - */ - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public BluetoothGatt connectGatt(Context context, boolean autoConnect, - BluetoothGattCallback callback) { - return (connectGatt(context, autoConnect, callback, TRANSPORT_AUTO)); - } - - /** - * Connect to GATT Server hosted by this device. Caller acts as GATT client. - * The callback is used to deliver results to Caller, such as connection status as well - * as any further GATT client operations. - * The method returns a BluetoothGatt instance. You can use BluetoothGatt to conduct - * GATT client operations. - * - * @param callback GATT callback handler that will receive asynchronous callbacks. - * @param autoConnect Whether to directly connect to the remote device (false) or to - * automatically connect as soon as the remote device becomes available (true). - * @param transport preferred transport for GATT connections to remote dual-mode devices {@link - * BluetoothDevice#TRANSPORT_AUTO} or {@link BluetoothDevice#TRANSPORT_BREDR} or {@link - * BluetoothDevice#TRANSPORT_LE} - * @throws IllegalArgumentException if callback is null - */ - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public BluetoothGatt connectGatt(Context context, boolean autoConnect, - BluetoothGattCallback callback, int transport) { - return (connectGatt(context, autoConnect, callback, transport, PHY_LE_1M_MASK)); - } - - /** - * Connect to GATT Server hosted by this device. Caller acts as GATT client. - * The callback is used to deliver results to Caller, such as connection status as well - * as any further GATT client operations. - * The method returns a BluetoothGatt instance. You can use BluetoothGatt to conduct - * GATT client operations. - * - * @param callback GATT callback handler that will receive asynchronous callbacks. - * @param autoConnect Whether to directly connect to the remote device (false) or to - * automatically connect as soon as the remote device becomes available (true). - * @param transport preferred transport for GATT connections to remote dual-mode devices {@link - * BluetoothDevice#TRANSPORT_AUTO} or {@link BluetoothDevice#TRANSPORT_BREDR} or {@link - * BluetoothDevice#TRANSPORT_LE} - * @param phy preferred PHY for connections to remote LE device. Bitwise OR of any of {@link - * BluetoothDevice#PHY_LE_1M_MASK}, {@link BluetoothDevice#PHY_LE_2M_MASK}, and {@link - * BluetoothDevice#PHY_LE_CODED_MASK}. This option does not take effect if {@code autoConnect} - * is set to true. - * @throws NullPointerException if callback is null - */ - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public BluetoothGatt connectGatt(Context context, boolean autoConnect, - BluetoothGattCallback callback, int transport, int phy) { - return connectGatt(context, autoConnect, callback, transport, phy, null); - } - - /** - * Connect to GATT Server hosted by this device. Caller acts as GATT client. - * The callback is used to deliver results to Caller, such as connection status as well - * as any further GATT client operations. - * The method returns a BluetoothGatt instance. You can use BluetoothGatt to conduct - * GATT client operations. - * - * @param callback GATT callback handler that will receive asynchronous callbacks. - * @param autoConnect Whether to directly connect to the remote device (false) or to - * automatically connect as soon as the remote device becomes available (true). - * @param transport preferred transport for GATT connections to remote dual-mode devices {@link - * BluetoothDevice#TRANSPORT_AUTO} or {@link BluetoothDevice#TRANSPORT_BREDR} or {@link - * BluetoothDevice#TRANSPORT_LE} - * @param phy preferred PHY for connections to remote LE device. Bitwise OR of any of {@link - * BluetoothDevice#PHY_LE_1M_MASK}, {@link BluetoothDevice#PHY_LE_2M_MASK}, an d{@link - * BluetoothDevice#PHY_LE_CODED_MASK}. This option does not take effect if {@code autoConnect} - * is set to true. - * @param handler The handler to use for the callback. If {@code null}, callbacks will happen on - * an un-specified background thread. - * @throws NullPointerException if callback is null - */ - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public BluetoothGatt connectGatt(Context context, boolean autoConnect, - BluetoothGattCallback callback, int transport, int phy, - Handler handler) { - return connectGatt(context, autoConnect, callback, transport, false, phy, handler); - } - - /** - * Connect to GATT Server hosted by this device. Caller acts as GATT client. - * The callback is used to deliver results to Caller, such as connection status as well - * as any further GATT client operations. - * The method returns a BluetoothGatt instance. You can use BluetoothGatt to conduct - * GATT client operations. - * - * @param callback GATT callback handler that will receive asynchronous callbacks. - * @param autoConnect Whether to directly connect to the remote device (false) or to - * automatically connect as soon as the remote device becomes available (true). - * @param transport preferred transport for GATT connections to remote dual-mode devices {@link - * BluetoothDevice#TRANSPORT_AUTO} or {@link BluetoothDevice#TRANSPORT_BREDR} or {@link - * BluetoothDevice#TRANSPORT_LE} - * @param opportunistic Whether this GATT client is opportunistic. An opportunistic GATT client - * does not hold a GATT connection. It automatically disconnects when no other GATT connections - * are active for the remote device. - * @param phy preferred PHY for connections to remote LE device. Bitwise OR of any of {@link - * BluetoothDevice#PHY_LE_1M_MASK}, {@link BluetoothDevice#PHY_LE_2M_MASK}, an d{@link - * BluetoothDevice#PHY_LE_CODED_MASK}. This option does not take effect if {@code autoConnect} - * is set to true. - * @param handler The handler to use for the callback. If {@code null}, callbacks will happen on - * an un-specified background thread. - * @return A BluetoothGatt instance. You can use BluetoothGatt to conduct GATT client - * operations. - * @hide - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public BluetoothGatt connectGatt(Context context, boolean autoConnect, - BluetoothGattCallback callback, int transport, - boolean opportunistic, int phy, Handler handler) { - if (callback == null) { - throw new NullPointerException("callback is null"); - } - - // TODO(Bluetooth) check whether platform support BLE - // Do the check here or in GattServer? - BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); - IBluetoothManager managerService = adapter.getBluetoothManager(); - try { - IBluetoothGatt iGatt = managerService.getBluetoothGatt(); - if (iGatt == null) { - // BLE is not supported - return null; - } - BluetoothGatt gatt = new BluetoothGatt( - iGatt, this, transport, opportunistic, phy, mAttributionSource); - gatt.connect(autoConnect, callback, handler); - return gatt; - } catch (RemoteException e) { - Log.e(TAG, "", e); - } - return null; - } - - /** - * Create a Bluetooth L2CAP Connection-oriented Channel (CoC) {@link BluetoothSocket} that can - * be used to start a secure outgoing connection to the remote device with the same dynamic - * protocol/service multiplexer (PSM) value. The supported Bluetooth transport is LE only. - *

This is designed to be used with {@link BluetoothAdapter#listenUsingL2capChannel()} for - * peer-peer Bluetooth applications. - *

Use {@link BluetoothSocket#connect} to initiate the outgoing connection. - *

Application using this API is responsible for obtaining PSM value from remote device. - *

The remote device will be authenticated and communication on this socket will be - * encrypted. - *

Use this socket if an authenticated socket link is possible. Authentication refers - * to the authentication of the link key to prevent person-in-the-middle type of attacks. - * - * @param psm dynamic PSM value from remote device - * @return a CoC #BluetoothSocket ready for an outgoing connection - * @throws IOException on error, for example Bluetooth not available, or insufficient - * permissions - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - @SuppressLint("AndroidFrameworkRequiresPermission") - public @NonNull BluetoothSocket createL2capChannel(int psm) throws IOException { - if (!isBluetoothEnabled()) { - Log.e(TAG, "createL2capChannel: Bluetooth is not enabled"); - throw new IOException(); - } - if (DBG) Log.d(TAG, "createL2capChannel: psm=" + psm); - return new BluetoothSocket(BluetoothSocket.TYPE_L2CAP_LE, -1, true, true, this, psm, - null); - } - - /** - * Create a Bluetooth L2CAP Connection-oriented Channel (CoC) {@link BluetoothSocket} that can - * be used to start a secure outgoing connection to the remote device with the same dynamic - * protocol/service multiplexer (PSM) value. The supported Bluetooth transport is LE only. - *

This is designed to be used with {@link - * BluetoothAdapter#listenUsingInsecureL2capChannel()} for peer-peer Bluetooth applications. - *

Use {@link BluetoothSocket#connect} to initiate the outgoing connection. - *

Application using this API is responsible for obtaining PSM value from remote device. - *

The communication channel may not have an authenticated link key, i.e. it may be subject - * to person-in-the-middle attacks. Use {@link #createL2capChannel(int)} if an encrypted and - * authenticated communication channel is possible. - * - * @param psm dynamic PSM value from remote device - * @return a CoC #BluetoothSocket ready for an outgoing connection - * @throws IOException on error, for example Bluetooth not available, or insufficient - * permissions - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - @SuppressLint("AndroidFrameworkRequiresPermission") - public @NonNull BluetoothSocket createInsecureL2capChannel(int psm) throws IOException { - if (!isBluetoothEnabled()) { - Log.e(TAG, "createInsecureL2capChannel: Bluetooth is not enabled"); - throw new IOException(); - } - if (DBG) { - Log.d(TAG, "createInsecureL2capChannel: psm=" + psm); - } - return new BluetoothSocket(BluetoothSocket.TYPE_L2CAP_LE, -1, false, false, this, psm, - null); - } - - /** - * Set a keyed metadata of this {@link BluetoothDevice} to a - * {@link String} value. - * Only bonded devices's metadata will be persisted across Bluetooth - * restart. - * Metadata will be removed when the device's bond state is moved to - * {@link #BOND_NONE}. - * - * @param key must be within the list of BluetoothDevice.METADATA_* - * @param value a byte array data to set for key. Must be less than - * {@link BluetoothAdapter#METADATA_MAX_LENGTH} characters in length - * @return true on success, false on error - * @hide - */ - @SystemApi - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) - public boolean setMetadata(@MetadataKey int key, @NonNull byte[] value) { - final IBluetooth service = sService; - if (service == null) { - Log.e(TAG, "Bluetooth is not enabled. Cannot set metadata"); - return false; - } - if (value.length > METADATA_MAX_LENGTH) { - throw new IllegalArgumentException("value length is " + value.length - + ", should not over " + METADATA_MAX_LENGTH); - } - try { - return service.setMetadata(this, key, value, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "setMetadata fail", e); - return false; - } - } - - /** - * Get a keyed metadata for this {@link BluetoothDevice} as {@link String} - * - * @param key must be within the list of BluetoothDevice.METADATA_* - * @return Metadata of the key as byte array, null on error or not found - * @hide - */ - @SystemApi - @Nullable - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) - public byte[] getMetadata(@MetadataKey int key) { - final IBluetooth service = sService; - if (service == null) { - Log.e(TAG, "Bluetooth is not enabled. Cannot get metadata"); - return null; - } - try { - return service.getMetadata(this, key, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "getMetadata fail", e); - return null; - } - } - - /** - * Get the maxinum metadata key ID. - * - * @return the last supported metadata key - * @hide - */ - public static @MetadataKey int getMaxMetadataKey() { - return METADATA_UNTETHERED_CASE_LOW_BATTERY_THRESHOLD; - } -} diff --git a/core/java/android/bluetooth/BluetoothDevicePicker.java b/core/java/android/bluetooth/BluetoothDevicePicker.java deleted file mode 100644 index 26e46573dd9580b16ce9fc4a73712dfa3187553a..0000000000000000000000000000000000000000 --- a/core/java/android/bluetooth/BluetoothDevicePicker.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (C) 2009 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.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. - * - * @hide - */ -public interface BluetoothDevicePicker { - public static final String EXTRA_NEED_AUTH = - "android.bluetooth.devicepicker.extra.NEED_AUTH"; - public static final String EXTRA_FILTER_TYPE = - "android.bluetooth.devicepicker.extra.FILTER_TYPE"; - public static final String EXTRA_LAUNCH_PACKAGE = - "android.bluetooth.devicepicker.extra.LAUNCH_PACKAGE"; - public static final String EXTRA_LAUNCH_CLASS = - "android.bluetooth.devicepicker.extra.DEVICE_PICKER_LAUNCH_CLASS"; - - /** - * Broadcast when one BT device is selected from BT device picker screen. - * 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"; - - /** - * Broadcast when someone want to select one BT device from devices list. - * This intent contains below extra data: - * - {@link #EXTRA_NEED_AUTH} (boolean): if need authentication - * - {@link #EXTRA_FILTER_TYPE} (int): what kinds of device should be - * listed - * - {@link #EXTRA_LAUNCH_PACKAGE} (string): where(which package) this - * intent come from - * - {@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"; - - /** Ask device picker to show all kinds of BT devices */ - public static final int FILTER_TYPE_ALL = 0; - /** Ask device picker to show BT devices that support AUDIO profiles */ - public static final int FILTER_TYPE_AUDIO = 1; - /** Ask device picker to show BT devices that support Object Transfer */ - public static final int FILTER_TYPE_TRANSFER = 2; - /** - * Ask device picker to show BT devices that support - * Personal Area Networking User (PANU) profile - */ - public static final int FILTER_TYPE_PANU = 3; - /** Ask device picker to show BT devices that support Network Access Point (NAP) profile */ - public static final int FILTER_TYPE_NAP = 4; -} diff --git a/core/java/android/bluetooth/BluetoothGatt.java b/core/java/android/bluetooth/BluetoothGatt.java deleted file mode 100644 index b531829d2940df292f10c285f78150c2eeba467e..0000000000000000000000000000000000000000 --- a/core/java/android/bluetooth/BluetoothGatt.java +++ /dev/null @@ -1,1848 +0,0 @@ -/* - * Copyright (C) 2013 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.bluetooth; - -import android.annotation.IntDef; -import android.annotation.NonNull; -import android.annotation.RequiresNoPermission; -import android.annotation.RequiresPermission; -import android.annotation.SuppressLint; -import android.bluetooth.annotations.RequiresBluetoothConnectPermission; -import android.bluetooth.annotations.RequiresLegacyBluetoothPermission; -import android.compat.annotation.UnsupportedAppUsage; -import android.content.AttributionSource; -import android.os.Build; -import android.os.Handler; -import android.os.ParcelUuid; -import android.os.RemoteException; -import android.util.Log; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; - -/** - * Public API for the Bluetooth GATT Profile. - * - *

This class provides Bluetooth GATT functionality to enable communication - * with Bluetooth Smart or Smart Ready devices. - * - *

To connect to a remote peripheral device, create a {@link BluetoothGattCallback} - * and call {@link BluetoothDevice#connectGatt} to get a instance of this class. - * GATT capable devices can be discovered using the Bluetooth device discovery or BLE - * scan process. - */ -public final class BluetoothGatt implements BluetoothProfile { - private static final String TAG = "BluetoothGatt"; - private static final boolean DBG = true; - private static final boolean VDBG = false; - - @UnsupportedAppUsage - private IBluetoothGatt mService; - @UnsupportedAppUsage - private volatile BluetoothGattCallback mCallback; - private Handler mHandler; - @UnsupportedAppUsage - private int mClientIf; - private BluetoothDevice mDevice; - @UnsupportedAppUsage - private boolean mAutoConnect; - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) - private int mAuthRetryState; - private int mConnState; - private final Object mStateLock = new Object(); - private final Object mDeviceBusyLock = new Object(); - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - private Boolean mDeviceBusy = false; - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - private int mTransport; - private int mPhy; - private boolean mOpportunistic; - private final AttributionSource mAttributionSource; - - private static final int AUTH_RETRY_STATE_IDLE = 0; - private static final int AUTH_RETRY_STATE_NO_MITM = 1; - private static final int AUTH_RETRY_STATE_MITM = 2; - - private static final int CONN_STATE_IDLE = 0; - private static final int CONN_STATE_CONNECTING = 1; - private static final int CONN_STATE_CONNECTED = 2; - private static final int CONN_STATE_DISCONNECTING = 3; - private static final int CONN_STATE_CLOSED = 4; - - private static final int WRITE_CHARACTERISTIC_MAX_RETRIES = 5; - private static final int WRITE_CHARACTERISTIC_TIME_TO_WAIT = 10; // milliseconds - - private List mServices; - - /** A GATT operation completed successfully */ - public static final int GATT_SUCCESS = 0; - - /** GATT read operation is not permitted */ - public static final int GATT_READ_NOT_PERMITTED = 0x2; - - /** GATT write operation is not permitted */ - public static final int GATT_WRITE_NOT_PERMITTED = 0x3; - - /** Insufficient authentication for a given operation */ - public static final int GATT_INSUFFICIENT_AUTHENTICATION = 0x5; - - /** The given request is not supported */ - public static final int GATT_REQUEST_NOT_SUPPORTED = 0x6; - - /** Insufficient encryption for a given operation */ - public static final int GATT_INSUFFICIENT_ENCRYPTION = 0xf; - - /** A read or write operation was requested with an invalid offset */ - public static final int GATT_INVALID_OFFSET = 0x7; - - /** Insufficient authorization for a given operation */ - public static final int GATT_INSUFFICIENT_AUTHORIZATION = 0x8; - - /** A write operation exceeds the maximum length of the attribute */ - public static final int GATT_INVALID_ATTRIBUTE_LENGTH = 0xd; - - /** A remote device connection is congested. */ - public static final int GATT_CONNECTION_CONGESTED = 0x8f; - - /** A GATT operation failed, errors other than the above */ - public static final int GATT_FAILURE = 0x101; - - /** - * Connection parameter update - Use the connection parameters recommended by the - * Bluetooth SIG. This is the default value if no connection parameter update - * is requested. - */ - public static final int CONNECTION_PRIORITY_BALANCED = 0; - - /** - * Connection parameter update - Request a high priority, low latency connection. - * An application should only request high priority connection parameters to transfer large - * amounts of data over LE quickly. Once the transfer is complete, the application should - * request {@link BluetoothGatt#CONNECTION_PRIORITY_BALANCED} connection parameters to reduce - * energy use. - */ - public static final int CONNECTION_PRIORITY_HIGH = 1; - - /** Connection parameter update - Request low power, reduced data rate connection parameters. */ - public static final int CONNECTION_PRIORITY_LOW_POWER = 2; - - /** - * No authentication required. - * - * @hide - */ - /*package*/ static final int AUTHENTICATION_NONE = 0; - - /** - * Authentication requested; no person-in-the-middle protection required. - * - * @hide - */ - /*package*/ static final int AUTHENTICATION_NO_MITM = 1; - - /** - * Authentication with person-in-the-middle protection requested. - * - * @hide - */ - /*package*/ static final int AUTHENTICATION_MITM = 2; - - /** - * Bluetooth GATT callbacks. Overrides the default BluetoothGattCallback implementation. - */ - @SuppressLint("AndroidFrameworkBluetoothPermission") - private final IBluetoothGattCallback mBluetoothGattCallback = - new IBluetoothGattCallback.Stub() { - /** - * Application interface registered - app is ready to go - * @hide - */ - @Override - @SuppressLint("AndroidFrameworkRequiresPermission") - public void onClientRegistered(int status, int clientIf) { - if (DBG) { - Log.d(TAG, "onClientRegistered() - status=" + status - + " clientIf=" + clientIf); - } - if (VDBG) { - synchronized (mStateLock) { - if (mConnState != CONN_STATE_CONNECTING) { - Log.e(TAG, "Bad connection state: " + mConnState); - } - } - } - mClientIf = clientIf; - if (status != GATT_SUCCESS) { - runOrQueueCallback(new Runnable() { - @Override - public void run() { - final BluetoothGattCallback callback = mCallback; - if (callback != null) { - callback.onConnectionStateChange(BluetoothGatt.this, - GATT_FAILURE, - BluetoothProfile.STATE_DISCONNECTED); - } - } - }); - - synchronized (mStateLock) { - mConnState = CONN_STATE_IDLE; - } - return; - } - try { - mService.clientConnect(mClientIf, mDevice.getAddress(), - !mAutoConnect, mTransport, mOpportunistic, - mPhy, mAttributionSource); // autoConnect is inverse of "isDirect" - } catch (RemoteException e) { - Log.e(TAG, "", e); - } - } - - /** - * Phy update callback - * @hide - */ - @Override - public void onPhyUpdate(String address, int txPhy, int rxPhy, int status) { - if (DBG) { - Log.d(TAG, "onPhyUpdate() - status=" + status - + " address=" + address + " txPhy=" + txPhy + " rxPhy=" + rxPhy); - } - if (!address.equals(mDevice.getAddress())) { - return; - } - - runOrQueueCallback(new Runnable() { - @Override - public void run() { - final BluetoothGattCallback callback = mCallback; - if (callback != null) { - callback.onPhyUpdate(BluetoothGatt.this, txPhy, rxPhy, status); - } - } - }); - } - - /** - * Phy read callback - * @hide - */ - @Override - public void onPhyRead(String address, int txPhy, int rxPhy, int status) { - if (DBG) { - Log.d(TAG, "onPhyRead() - status=" + status - + " address=" + address + " txPhy=" + txPhy + " rxPhy=" + rxPhy); - } - if (!address.equals(mDevice.getAddress())) { - return; - } - - runOrQueueCallback(new Runnable() { - @Override - public void run() { - final BluetoothGattCallback callback = mCallback; - if (callback != null) { - callback.onPhyRead(BluetoothGatt.this, txPhy, rxPhy, status); - } - } - }); - } - - /** - * Client connection state changed - * @hide - */ - @Override - public void onClientConnectionState(int status, int clientIf, - boolean connected, String address) { - if (DBG) { - Log.d(TAG, "onClientConnectionState() - status=" + status - + " clientIf=" + clientIf + " device=" + address); - } - if (!address.equals(mDevice.getAddress())) { - return; - } - int profileState = connected ? BluetoothProfile.STATE_CONNECTED : - BluetoothProfile.STATE_DISCONNECTED; - - runOrQueueCallback(new Runnable() { - @Override - public void run() { - final BluetoothGattCallback callback = mCallback; - if (callback != null) { - callback.onConnectionStateChange(BluetoothGatt.this, status, - profileState); - } - } - }); - - synchronized (mStateLock) { - if (connected) { - mConnState = CONN_STATE_CONNECTED; - } else { - mConnState = CONN_STATE_IDLE; - } - } - - synchronized (mDeviceBusyLock) { - mDeviceBusy = false; - } - } - - /** - * Remote search has been completed. - * The internal object structure should now reflect the state - * of the remote device database. Let the application know that - * we are done at this point. - * @hide - */ - @Override - public void onSearchComplete(String address, List services, - int status) { - if (DBG) { - Log.d(TAG, - "onSearchComplete() = Device=" + address + " Status=" + status); - } - if (!address.equals(mDevice.getAddress())) { - return; - } - - for (BluetoothGattService s : services) { - //services we receive don't have device set properly. - s.setDevice(mDevice); - } - - mServices.addAll(services); - - // Fix references to included services, as they doesn't point to right objects. - for (BluetoothGattService fixedService : mServices) { - ArrayList includedServices = - new ArrayList(fixedService.getIncludedServices()); - fixedService.getIncludedServices().clear(); - - for (BluetoothGattService brokenRef : includedServices) { - BluetoothGattService includedService = getService(mDevice, - brokenRef.getUuid(), brokenRef.getInstanceId()); - if (includedService != null) { - fixedService.addIncludedService(includedService); - } else { - Log.e(TAG, "Broken GATT database: can't find included service."); - } - } - } - - runOrQueueCallback(new Runnable() { - @Override - public void run() { - final BluetoothGattCallback callback = mCallback; - if (callback != null) { - callback.onServicesDiscovered(BluetoothGatt.this, status); - } - } - }); - } - - /** - * Remote characteristic has been read. - * Updates the internal value. - * @hide - */ - @Override - @SuppressLint("AndroidFrameworkRequiresPermission") - public void onCharacteristicRead(String address, int status, int handle, - byte[] value) { - if (VDBG) { - Log.d(TAG, "onCharacteristicRead() - Device=" + address - + " handle=" + handle + " Status=" + status); - } - - if (!address.equals(mDevice.getAddress())) { - return; - } - - synchronized (mDeviceBusyLock) { - mDeviceBusy = false; - } - - if ((status == GATT_INSUFFICIENT_AUTHENTICATION - || status == GATT_INSUFFICIENT_ENCRYPTION) - && (mAuthRetryState != AUTH_RETRY_STATE_MITM)) { - try { - final int authReq = (mAuthRetryState == AUTH_RETRY_STATE_IDLE) - ? AUTHENTICATION_NO_MITM : AUTHENTICATION_MITM; - mService.readCharacteristic( - mClientIf, address, handle, authReq, mAttributionSource); - mAuthRetryState++; - return; - } catch (RemoteException e) { - Log.e(TAG, "", e); - } - } - - mAuthRetryState = AUTH_RETRY_STATE_IDLE; - - BluetoothGattCharacteristic characteristic = getCharacteristicById(mDevice, - handle); - if (characteristic == null) { - Log.w(TAG, "onCharacteristicRead() failed to find characteristic!"); - return; - } - - runOrQueueCallback(new Runnable() { - @Override - public void run() { - final BluetoothGattCallback callback = mCallback; - if (callback != null) { - if (status == 0) characteristic.setValue(value); - callback.onCharacteristicRead(BluetoothGatt.this, characteristic, - value, status); - // Keep calling deprecated callback to maintain app compatibility - callback.onCharacteristicRead(BluetoothGatt.this, characteristic, - status); - } - } - }); - } - - /** - * Characteristic has been written to the remote device. - * Let the app know how we did... - * @hide - */ - @Override - @SuppressLint("AndroidFrameworkRequiresPermission") - public void onCharacteristicWrite(String address, int status, int handle, - byte[] value) { - if (VDBG) { - Log.d(TAG, "onCharacteristicWrite() - Device=" + address - + " handle=" + handle + " Status=" + status); - } - - if (!address.equals(mDevice.getAddress())) { - return; - } - - synchronized (mDeviceBusyLock) { - mDeviceBusy = false; - } - - BluetoothGattCharacteristic characteristic = getCharacteristicById(mDevice, - handle); - if (characteristic == null) return; - - if ((status == GATT_INSUFFICIENT_AUTHENTICATION - || status == GATT_INSUFFICIENT_ENCRYPTION) - && (mAuthRetryState != AUTH_RETRY_STATE_MITM)) { - try { - final int authReq = (mAuthRetryState == AUTH_RETRY_STATE_IDLE) - ? AUTHENTICATION_NO_MITM : AUTHENTICATION_MITM; - int requestStatus = BluetoothStatusCodes.ERROR_UNKNOWN; - for (int i = 0; i < WRITE_CHARACTERISTIC_MAX_RETRIES; i++) { - requestStatus = mService.writeCharacteristic(mClientIf, address, - handle, characteristic.getWriteType(), authReq, - value, mAttributionSource); - if (requestStatus - != BluetoothStatusCodes.ERROR_GATT_WRITE_REQUEST_BUSY) { - break; - } - try { - Thread.sleep(WRITE_CHARACTERISTIC_TIME_TO_WAIT); - } catch (InterruptedException e) { - } - } - mAuthRetryState++; - return; - } catch (RemoteException e) { - Log.e(TAG, "", e); - } - } - - mAuthRetryState = AUTH_RETRY_STATE_IDLE; - runOrQueueCallback(new Runnable() { - @Override - public void run() { - final BluetoothGattCallback callback = mCallback; - if (callback != null) { - callback.onCharacteristicWrite(BluetoothGatt.this, characteristic, - status); - } - } - }); - } - - /** - * Remote characteristic has been updated. - * Updates the internal value. - * @hide - */ - @Override - public void onNotify(String address, int handle, byte[] value) { - if (VDBG) Log.d(TAG, "onNotify() - Device=" + address + " handle=" + handle); - - if (!address.equals(mDevice.getAddress())) { - return; - } - - BluetoothGattCharacteristic characteristic = getCharacteristicById(mDevice, - handle); - if (characteristic == null) return; - - runOrQueueCallback(new Runnable() { - @Override - public void run() { - final BluetoothGattCallback callback = mCallback; - if (callback != null) { - characteristic.setValue(value); - callback.onCharacteristicChanged(BluetoothGatt.this, - characteristic, value); - // Keep calling deprecated callback to maintain app compatibility - callback.onCharacteristicChanged(BluetoothGatt.this, - characteristic); - } - } - }); - } - - /** - * Descriptor has been read. - * @hide - */ - @Override - @SuppressLint("AndroidFrameworkRequiresPermission") - public void onDescriptorRead(String address, int status, int handle, byte[] value) { - if (VDBG) { - Log.d(TAG, - "onDescriptorRead() - Device=" + address + " handle=" + handle); - } - - if (!address.equals(mDevice.getAddress())) { - return; - } - - synchronized (mDeviceBusyLock) { - mDeviceBusy = false; - } - - BluetoothGattDescriptor descriptor = getDescriptorById(mDevice, handle); - if (descriptor == null) return; - - - if ((status == GATT_INSUFFICIENT_AUTHENTICATION - || status == GATT_INSUFFICIENT_ENCRYPTION) - && (mAuthRetryState != AUTH_RETRY_STATE_MITM)) { - try { - final int authReq = (mAuthRetryState == AUTH_RETRY_STATE_IDLE) - ? AUTHENTICATION_NO_MITM : AUTHENTICATION_MITM; - mService.readDescriptor( - mClientIf, address, handle, authReq, mAttributionSource); - mAuthRetryState++; - return; - } catch (RemoteException e) { - Log.e(TAG, "", e); - } - } - - mAuthRetryState = AUTH_RETRY_STATE_IDLE; - - runOrQueueCallback(new Runnable() { - @Override - public void run() { - final BluetoothGattCallback callback = mCallback; - if (callback != null) { - if (status == 0) descriptor.setValue(value); - callback.onDescriptorRead(BluetoothGatt.this, descriptor, status, - value); - // Keep calling deprecated callback to maintain app compatibility - callback.onDescriptorRead(BluetoothGatt.this, descriptor, status); - } - } - }); - } - - /** - * Descriptor write operation complete. - * @hide - */ - @Override - @SuppressLint("AndroidFrameworkRequiresPermission") - public void onDescriptorWrite(String address, int status, int handle, - byte[] value) { - if (VDBG) { - Log.d(TAG, - "onDescriptorWrite() - Device=" + address + " handle=" + handle); - } - - if (!address.equals(mDevice.getAddress())) { - return; - } - - synchronized (mDeviceBusyLock) { - mDeviceBusy = false; - } - - BluetoothGattDescriptor descriptor = getDescriptorById(mDevice, handle); - if (descriptor == null) return; - - if ((status == GATT_INSUFFICIENT_AUTHENTICATION - || status == GATT_INSUFFICIENT_ENCRYPTION) - && (mAuthRetryState != AUTH_RETRY_STATE_MITM)) { - try { - final int authReq = (mAuthRetryState == AUTH_RETRY_STATE_IDLE) - ? AUTHENTICATION_NO_MITM : AUTHENTICATION_MITM; - mService.writeDescriptor(mClientIf, address, handle, - authReq, value, mAttributionSource); - mAuthRetryState++; - return; - } catch (RemoteException e) { - Log.e(TAG, "", e); - } - } - - mAuthRetryState = AUTH_RETRY_STATE_IDLE; - - runOrQueueCallback(new Runnable() { - @Override - public void run() { - final BluetoothGattCallback callback = mCallback; - if (callback != null) { - callback.onDescriptorWrite(BluetoothGatt.this, descriptor, status); - } - } - }); - } - - /** - * Prepared write transaction completed (or aborted) - * @hide - */ - @Override - public void onExecuteWrite(String address, int status) { - if (VDBG) { - Log.d(TAG, "onExecuteWrite() - Device=" + address - + " status=" + status); - } - if (!address.equals(mDevice.getAddress())) { - return; - } - - synchronized (mDeviceBusyLock) { - mDeviceBusy = false; - } - - runOrQueueCallback(new Runnable() { - @Override - public void run() { - final BluetoothGattCallback callback = mCallback; - if (callback != null) { - callback.onReliableWriteCompleted(BluetoothGatt.this, status); - } - } - }); - } - - /** - * Remote device RSSI has been read - * @hide - */ - @Override - public void onReadRemoteRssi(String address, int rssi, int status) { - if (VDBG) { - Log.d(TAG, "onReadRemoteRssi() - Device=" + address - + " rssi=" + rssi + " status=" + status); - } - if (!address.equals(mDevice.getAddress())) { - return; - } - runOrQueueCallback(new Runnable() { - @Override - public void run() { - final BluetoothGattCallback callback = mCallback; - if (callback != null) { - callback.onReadRemoteRssi(BluetoothGatt.this, rssi, status); - } - } - }); - } - - /** - * Callback invoked when the MTU for a given connection changes - * @hide - */ - @Override - public void onConfigureMTU(String address, int mtu, int status) { - if (DBG) { - Log.d(TAG, "onConfigureMTU() - Device=" + address - + " mtu=" + mtu + " status=" + status); - } - if (!address.equals(mDevice.getAddress())) { - return; - } - - runOrQueueCallback(new Runnable() { - @Override - public void run() { - final BluetoothGattCallback callback = mCallback; - if (callback != null) { - callback.onMtuChanged(BluetoothGatt.this, mtu, status); - } - } - }); - } - - /** - * Callback invoked when the given connection is updated - * @hide - */ - @Override - public void onConnectionUpdated(String address, int interval, int latency, - int timeout, int status) { - if (DBG) { - Log.d(TAG, "onConnectionUpdated() - Device=" + address - + " interval=" + interval + " latency=" + latency - + " timeout=" + timeout + " status=" + status); - } - if (!address.equals(mDevice.getAddress())) { - return; - } - - runOrQueueCallback(new Runnable() { - @Override - public void run() { - final BluetoothGattCallback callback = mCallback; - if (callback != null) { - callback.onConnectionUpdated(BluetoothGatt.this, interval, latency, - timeout, status); - } - } - }); - } - - /** - * Callback invoked when service changed event is received - * @hide - */ - @Override - public void onServiceChanged(String address) { - if (DBG) { - Log.d(TAG, "onServiceChanged() - Device=" + address); - } - - if (!address.equals(mDevice.getAddress())) { - return; - } - - runOrQueueCallback(new Runnable() { - @Override - public void run() { - final BluetoothGattCallback callback = mCallback; - if (callback != null) { - callback.onServiceChanged(BluetoothGatt.this); - } - } - }); - } - }; - - /* package */ BluetoothGatt(IBluetoothGatt iGatt, BluetoothDevice device, int transport, - boolean opportunistic, int phy, AttributionSource attributionSource) { - mService = iGatt; - mDevice = device; - mTransport = transport; - mPhy = phy; - mOpportunistic = opportunistic; - mAttributionSource = attributionSource; - mServices = new ArrayList(); - - mConnState = CONN_STATE_IDLE; - mAuthRetryState = AUTH_RETRY_STATE_IDLE; - } - - /** - * Close this Bluetooth GATT client. - * - * 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()"); - - unregisterApp(); - mConnState = CONN_STATE_CLOSED; - mAuthRetryState = AUTH_RETRY_STATE_IDLE; - } - - /** - * Returns a service by UUID, instance and type. - * - * @hide - */ - /*package*/ BluetoothGattService getService(BluetoothDevice device, UUID uuid, - int instanceId) { - for (BluetoothGattService svc : mServices) { - if (svc.getDevice().equals(device) - && svc.getInstanceId() == instanceId - && svc.getUuid().equals(uuid)) { - return svc; - } - } - return null; - } - - - /** - * Returns a characteristic with id equal to instanceId. - * - * @hide - */ - /*package*/ BluetoothGattCharacteristic getCharacteristicById(BluetoothDevice device, - int instanceId) { - for (BluetoothGattService svc : mServices) { - for (BluetoothGattCharacteristic charac : svc.getCharacteristics()) { - if (charac.getInstanceId() == instanceId) { - return charac; - } - } - } - return null; - } - - /** - * Returns a descriptor with id equal to instanceId. - * - * @hide - */ - /*package*/ BluetoothGattDescriptor getDescriptorById(BluetoothDevice device, int instanceId) { - for (BluetoothGattService svc : mServices) { - for (BluetoothGattCharacteristic charac : svc.getCharacteristics()) { - for (BluetoothGattDescriptor desc : charac.getDescriptors()) { - if (desc.getInstanceId() == instanceId) { - return desc; - } - } - } - } - return null; - } - - /** - * Queue the runnable on a {@link Handler} provided by the user, or execute the runnable - * immediately if no Handler was provided. - */ - private void runOrQueueCallback(final Runnable cb) { - if (mHandler == null) { - try { - cb.run(); - } catch (Exception ex) { - Log.w(TAG, "Unhandled exception in callback", ex); - } - } else { - mHandler.post(cb); - } - } - - /** - * Register an application callback to start using GATT. - * - *

This is an asynchronous call. The callback {@link BluetoothGattCallback#onAppRegistered} - * is used to notify success or failure if the function returns true. - * - * @param callback GATT callback handler that will receive asynchronous callbacks. - * @return If true, the callback will be called to notify success or failure, false on immediate - * error - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - private boolean registerApp(BluetoothGattCallback callback, Handler handler) { - return registerApp(callback, handler, false); - } - - /** - * Register an application callback to start using GATT. - * - *

This is an asynchronous call. The callback {@link BluetoothGattCallback#onAppRegistered} - * is used to notify success or failure if the function returns true. - * - * @param callback GATT callback handler that will receive asynchronous callbacks. - * @param eatt_support indicate to allow for eatt support - * @return If true, the callback will be called to notify success or failure, false on immediate - * error - * @hide - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - private boolean registerApp(BluetoothGattCallback callback, Handler handler, - boolean eatt_support) { - if (DBG) Log.d(TAG, "registerApp()"); - if (mService == null) return false; - - mCallback = callback; - mHandler = handler; - UUID uuid = UUID.randomUUID(); - if (DBG) Log.d(TAG, "registerApp() - UUID=" + uuid); - - try { - mService.registerClient( - new ParcelUuid(uuid), mBluetoothGattCallback, eatt_support, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "", e); - return false; - } - - return true; - } - - /** - * 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); - if (mService == null || mClientIf == 0) return; - - try { - mCallback = null; - mService.unregisterClient(mClientIf, mAttributionSource); - mClientIf = 0; - } catch (RemoteException e) { - Log.e(TAG, "", e); - } - } - - /** - * Initiate a connection to a Bluetooth GATT capable device. - * - *

The connection may not be established right away, but will be - * completed when the remote device is available. A - * {@link BluetoothGattCallback#onConnectionStateChange} callback will be - * invoked when the connection state changes as a result of this function. - * - *

The autoConnect parameter determines whether to actively connect to - * the remote device, or rather passively scan and finalize the connection - * when the remote device is in range/available. Generally, the first ever - * connection to a device should be direct (autoConnect set to false) and - * subsequent connections to known devices should be invoked with the - * autoConnect parameter set to true. - * - * @param device Remote device to connect to - * @param autoConnect Whether to directly connect to the remote device (false) or to - * automatically connect as soon as the remote device becomes available (true). - * @return true, if the connection attempt was initiated successfully - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - /*package*/ boolean connect(Boolean autoConnect, BluetoothGattCallback callback, - Handler handler) { - if (DBG) { - Log.d(TAG, - "connect() - device: " + mDevice.getAddress() + ", auto: " + autoConnect); - } - synchronized (mStateLock) { - if (mConnState != CONN_STATE_IDLE) { - throw new IllegalStateException("Not idle"); - } - mConnState = CONN_STATE_CONNECTING; - } - - mAutoConnect = autoConnect; - - if (!registerApp(callback, handler)) { - synchronized (mStateLock) { - mConnState = CONN_STATE_IDLE; - } - Log.e(TAG, "Failed to register callback"); - return false; - } - - // The connection will continue in the onClientRegistered callback - return true; - } - - /** - * Disconnects an established connection, or cancels a connection attempt - * currently in progress. - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public void disconnect() { - if (DBG) Log.d(TAG, "cancelOpen() - device: " + mDevice.getAddress()); - if (mService == null || mClientIf == 0) return; - - try { - mService.clientDisconnect(mClientIf, mDevice.getAddress(), mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "", e); - } - } - - /** - * Connect back to remote device. - * - *

This method is used to re-connect to a remote device after the - * connection has been dropped. If the device is not in range, the - * re-connection will be triggered once the device is back in range. - * - * @return true, if the connection attempt was initiated successfully - */ - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public boolean connect() { - try { - // autoConnect is inverse of "isDirect" - mService.clientConnect(mClientIf, mDevice.getAddress(), false, mTransport, - mOpportunistic, mPhy, mAttributionSource); - return true; - } catch (RemoteException e) { - Log.e(TAG, "", e); - return false; - } - } - - /** - * Set the preferred connection PHY for this app. Please note that this is just a - * recommendation, whether the PHY change will happen depends on other applications preferences, - * local and remote controller capabilities. Controller can override these settings. - *

- * {@link BluetoothGattCallback#onPhyUpdate} will be triggered as a result of this call, even - * if no PHY change happens. It is also triggered when remote device updates the PHY. - * - * @param txPhy preferred transmitter PHY. Bitwise OR of any of {@link - * BluetoothDevice#PHY_LE_1M_MASK}, {@link BluetoothDevice#PHY_LE_2M_MASK}, and {@link - * BluetoothDevice#PHY_LE_CODED_MASK}. - * @param rxPhy preferred receiver PHY. Bitwise OR of any of {@link - * BluetoothDevice#PHY_LE_1M_MASK}, {@link BluetoothDevice#PHY_LE_2M_MASK}, and {@link - * BluetoothDevice#PHY_LE_CODED_MASK}. - * @param phyOptions preferred coding to use when transmitting on the LE Coded PHY. Can be one - * 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 { - mService.clientSetPreferredPhy(mClientIf, mDevice.getAddress(), txPhy, rxPhy, - phyOptions, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "", e); - } - } - - /** - * 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 { - mService.clientReadPhy(mClientIf, mDevice.getAddress(), mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "", e); - } - } - - /** - * Return the remote bluetooth device this GATT client targets to - * - * @return remote bluetooth device - */ - @RequiresNoPermission - public BluetoothDevice getDevice() { - return mDevice; - } - - /** - * Discovers services offered by a remote device as well as their - * characteristics and descriptors. - * - *

This is an asynchronous operation. Once service discovery is completed, - * the {@link BluetoothGattCallback#onServicesDiscovered} callback is - * triggered. If the discovery was successful, the remote services can be - * retrieved using the {@link #getServices} function. - * - * @return true, if the remote service discovery has been started - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public boolean discoverServices() { - if (DBG) Log.d(TAG, "discoverServices() - device: " + mDevice.getAddress()); - if (mService == null || mClientIf == 0) return false; - - mServices.clear(); - - try { - mService.discoverServices(mClientIf, mDevice.getAddress(), mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "", e); - return false; - } - - return true; - } - - /** - * Discovers a service by UUID. This is exposed only for passing PTS tests. - * It should never be used by real applications. The service is not searched - * for characteristics and descriptors, or returned in any callback. - * - * @return true, if the remote service discovery has been started - * @hide - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public boolean discoverServiceByUuid(UUID uuid) { - if (DBG) Log.d(TAG, "discoverServiceByUuid() - device: " + mDevice.getAddress()); - if (mService == null || mClientIf == 0) return false; - - mServices.clear(); - - try { - mService.discoverServiceByUuid( - mClientIf, mDevice.getAddress(), new ParcelUuid(uuid), mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "", e); - return false; - } - return true; - } - - /** - * Returns a list of GATT services offered by the remote device. - * - *

This function requires that service discovery has been completed - * for the given device. - * - * @return List of services on the remote device. Returns an empty list if service discovery has - * not yet been performed. - */ - @RequiresLegacyBluetoothPermission - @RequiresNoPermission - public List getServices() { - List result = - new ArrayList(); - - for (BluetoothGattService service : mServices) { - if (service.getDevice().equals(mDevice)) { - result.add(service); - } - } - - return result; - } - - /** - * Returns a {@link BluetoothGattService}, if the requested UUID is - * supported by the remote device. - * - *

This function requires that service discovery has been completed - * for the given device. - * - *

If multiple instances of the same service (as identified by UUID) - * exist, the first instance of the service is returned. - * - * @param uuid UUID of the requested service - * @return BluetoothGattService if supported, or null if the requested service is not offered by - * the remote device. - */ - @RequiresLegacyBluetoothPermission - @RequiresNoPermission - public BluetoothGattService getService(UUID uuid) { - for (BluetoothGattService service : mServices) { - if (service.getDevice().equals(mDevice) && service.getUuid().equals(uuid)) { - return service; - } - } - - return null; - } - - /** - * Reads the requested characteristic from the associated remote device. - * - *

This is an asynchronous operation. The result of the read operation - * is reported by the {@link BluetoothGattCallback#onCharacteristicRead(BluetoothGatt, - * BluetoothGattCharacteristic, byte[], int)} callback. - * - * @param characteristic Characteristic to read from the remote device - * @return true, if the read operation was initiated successfully - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public boolean readCharacteristic(BluetoothGattCharacteristic characteristic) { - if ((characteristic.getProperties() & BluetoothGattCharacteristic.PROPERTY_READ) == 0) { - return false; - } - - if (VDBG) Log.d(TAG, "readCharacteristic() - uuid: " + characteristic.getUuid()); - if (mService == null || mClientIf == 0) return false; - - BluetoothGattService service = characteristic.getService(); - if (service == null) return false; - - BluetoothDevice device = service.getDevice(); - if (device == null) return false; - - synchronized (mDeviceBusyLock) { - if (mDeviceBusy) return false; - mDeviceBusy = true; - } - - try { - mService.readCharacteristic(mClientIf, device.getAddress(), - characteristic.getInstanceId(), AUTHENTICATION_NONE, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "", e); - synchronized (mDeviceBusyLock) { - mDeviceBusy = false; - } - return false; - } - - return true; - } - - /** - * Reads the characteristic using its UUID from the associated remote device. - * - *

This is an asynchronous operation. The result of the read operation - * is reported by the {@link BluetoothGattCallback#onCharacteristicRead(BluetoothGatt, - * BluetoothGattCharacteristic, byte[], int)} callback. - * - * @param uuid UUID of characteristic to read from the remote device - * @return true, if the read operation was initiated successfully - * @hide - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public boolean readUsingCharacteristicUuid(UUID uuid, int startHandle, int endHandle) { - if (VDBG) Log.d(TAG, "readUsingCharacteristicUuid() - uuid: " + uuid); - if (mService == null || mClientIf == 0) return false; - - synchronized (mDeviceBusyLock) { - if (mDeviceBusy) return false; - mDeviceBusy = true; - } - - try { - mService.readUsingCharacteristicUuid(mClientIf, mDevice.getAddress(), - new ParcelUuid(uuid), startHandle, endHandle, AUTHENTICATION_NONE, - mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "", e); - synchronized (mDeviceBusyLock) { - mDeviceBusy = false; - } - return false; - } - - return true; - } - - - /** - * Writes a given characteristic and its values to the associated remote device. - * - *

Once the write operation has been completed, the - * {@link BluetoothGattCallback#onCharacteristicWrite} callback is invoked, - * reporting the result of the operation. - * - * @param characteristic Characteristic to write on the remote device - * @return true, if the write operation was initiated successfully - * @throws IllegalArgumentException if characteristic or its value are null - * - * @deprecated Use {@link BluetoothGatt#writeCharacteristic(BluetoothGattCharacteristic, byte[], - * int)} as this is not memory safe. - */ - @Deprecated - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public boolean writeCharacteristic(BluetoothGattCharacteristic characteristic) { - try { - return writeCharacteristic(characteristic, characteristic.getValue(), - characteristic.getWriteType()) == BluetoothStatusCodes.SUCCESS; - } catch (Exception e) { - return false; - } - } - - /** @hide */ - @Retention(RetentionPolicy.SOURCE) - @IntDef(value = { - BluetoothStatusCodes.SUCCESS, - BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION, - BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_PRIVILEGED_PERMISSION, - BluetoothStatusCodes.ERROR_DEVICE_NOT_CONNECTED, - BluetoothStatusCodes.ERROR_PROFILE_SERVICE_NOT_BOUND, - BluetoothStatusCodes.ERROR_GATT_WRITE_NOT_ALLOWED, - BluetoothStatusCodes.ERROR_GATT_WRITE_REQUEST_BUSY, - BluetoothStatusCodes.ERROR_UNKNOWN - }) - public @interface WriteOperationReturnValues{} - - /** - * Writes a given characteristic and its values to the associated remote device. - * - *

Once the write operation has been completed, the - * {@link BluetoothGattCallback#onCharacteristicWrite} callback is invoked, - * reporting the result of the operation. - * - * @param characteristic Characteristic to write on the remote device - * @return whether the characteristic was successfully written to - * @throws IllegalArgumentException if characteristic or value are null - */ - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - @WriteOperationReturnValues - public int writeCharacteristic(@NonNull BluetoothGattCharacteristic characteristic, - @NonNull byte[] value, int writeType) { - if (characteristic == null) { - throw new IllegalArgumentException("characteristic must not be null"); - } - if (value == null) { - throw new IllegalArgumentException("value must not be null"); - } - if (VDBG) Log.d(TAG, "writeCharacteristic() - uuid: " + characteristic.getUuid()); - if ((characteristic.getProperties() & BluetoothGattCharacteristic.PROPERTY_WRITE) == 0 - && (characteristic.getProperties() - & BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE) == 0) { - return BluetoothStatusCodes.ERROR_GATT_WRITE_NOT_ALLOWED; - } - if (mService == null || mClientIf == 0) { - return BluetoothStatusCodes.ERROR_PROFILE_SERVICE_NOT_BOUND; - } - - BluetoothGattService service = characteristic.getService(); - if (service == null) { - throw new IllegalArgumentException("Characteristic must have a non-null service"); - } - - BluetoothDevice device = service.getDevice(); - if (device == null) { - throw new IllegalArgumentException("Service must have a non-null device"); - } - - synchronized (mDeviceBusyLock) { - if (mDeviceBusy) { - return BluetoothStatusCodes.ERROR_GATT_WRITE_REQUEST_BUSY; - } - mDeviceBusy = true; - } - - int requestStatus = BluetoothStatusCodes.ERROR_UNKNOWN; - try { - for (int i = 0; i < WRITE_CHARACTERISTIC_MAX_RETRIES; i++) { - requestStatus = mService.writeCharacteristic(mClientIf, device.getAddress(), - characteristic.getInstanceId(), writeType, AUTHENTICATION_NONE, value, - mAttributionSource); - if (requestStatus != BluetoothStatusCodes.ERROR_GATT_WRITE_REQUEST_BUSY) { - break; - } - try { - Thread.sleep(WRITE_CHARACTERISTIC_TIME_TO_WAIT); - } catch (InterruptedException e) { - } - } - } catch (RemoteException e) { - Log.e(TAG, "", e); - synchronized (mDeviceBusyLock) { - mDeviceBusy = false; - } - throw e.rethrowFromSystemServer(); - } - - return requestStatus; - } - - /** - * Reads the value for a given descriptor from the associated remote device. - * - *

Once the read operation has been completed, the - * {@link BluetoothGattCallback#onDescriptorRead} callback is - * triggered, signaling the result of the operation. - * - * @param descriptor Descriptor value to read from the remote device - * @return true, if the read operation was initiated successfully - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public boolean readDescriptor(BluetoothGattDescriptor descriptor) { - if (VDBG) Log.d(TAG, "readDescriptor() - uuid: " + descriptor.getUuid()); - if (mService == null || mClientIf == 0) return false; - - BluetoothGattCharacteristic characteristic = descriptor.getCharacteristic(); - if (characteristic == null) return false; - - BluetoothGattService service = characteristic.getService(); - if (service == null) return false; - - BluetoothDevice device = service.getDevice(); - if (device == null) return false; - - synchronized (mDeviceBusyLock) { - if (mDeviceBusy) return false; - mDeviceBusy = true; - } - - try { - mService.readDescriptor(mClientIf, device.getAddress(), - descriptor.getInstanceId(), AUTHENTICATION_NONE, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "", e); - synchronized (mDeviceBusyLock) { - mDeviceBusy = false; - } - return false; - } - - return true; - } - - /** - * Write the value of a given descriptor to the associated remote device. - * - *

A {@link BluetoothGattCallback#onDescriptorWrite} callback is triggered to report the - * result of the write operation. - * - * @param descriptor Descriptor to write to the associated remote device - * @return true, if the write operation was initiated successfully - * @throws IllegalArgumentException if descriptor or its value are null - * - * @deprecated Use {@link BluetoothGatt#writeDescriptor(BluetoothGattDescriptor, byte[])} as - * this is not memory safe. - */ - @Deprecated - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public boolean writeDescriptor(BluetoothGattDescriptor descriptor) { - try { - return writeDescriptor(descriptor, descriptor.getValue()) - == BluetoothStatusCodes.SUCCESS; - } catch (Exception e) { - return false; - } - } - - /** - * Write the value of a given descriptor to the associated remote device. - * - *

A {@link BluetoothGattCallback#onDescriptorWrite} callback is triggered to report the - * result of the write operation. - * - * @param descriptor Descriptor to write to the associated remote device - * @return true, if the write operation was initiated successfully - * @throws IllegalArgumentException if descriptor or value are null - */ - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - @WriteOperationReturnValues - public int writeDescriptor(@NonNull BluetoothGattDescriptor descriptor, - @NonNull byte[] value) { - if (descriptor == null) { - throw new IllegalArgumentException("descriptor must not be null"); - } - if (value == null) { - throw new IllegalArgumentException("value must not be null"); - } - if (VDBG) Log.d(TAG, "writeDescriptor() - uuid: " + descriptor.getUuid()); - if (mService == null || mClientIf == 0) { - return BluetoothStatusCodes.ERROR_PROFILE_SERVICE_NOT_BOUND; - } - - BluetoothGattCharacteristic characteristic = descriptor.getCharacteristic(); - if (characteristic == null) { - throw new IllegalArgumentException("Descriptor must have a non-null characteristic"); - } - - BluetoothGattService service = characteristic.getService(); - if (service == null) { - throw new IllegalArgumentException("Characteristic must have a non-null service"); - } - - BluetoothDevice device = service.getDevice(); - if (device == null) { - throw new IllegalArgumentException("Service must have a non-null device"); - } - - synchronized (mDeviceBusyLock) { - if (mDeviceBusy) return BluetoothStatusCodes.ERROR_GATT_WRITE_REQUEST_BUSY; - mDeviceBusy = true; - } - - try { - return mService.writeDescriptor(mClientIf, device.getAddress(), - descriptor.getInstanceId(), AUTHENTICATION_NONE, value, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "", e); - synchronized (mDeviceBusyLock) { - mDeviceBusy = false; - } - e.rethrowFromSystemServer(); - } - return BluetoothStatusCodes.ERROR_UNKNOWN; - } - - /** - * Initiates a reliable write transaction for a given remote device. - * - *

Once a reliable write transaction has been initiated, all calls - * to {@link #writeCharacteristic} are sent to the remote device for - * verification and queued up for atomic execution. The application will - * receive a {@link BluetoothGattCallback#onCharacteristicWrite} callback in response to every - * {@link #writeCharacteristic(BluetoothGattCharacteristic, byte[], int)} call and is - * responsible for verifying if the value has been transmitted accurately. - * - *

After all characteristics have been queued up and verified, - * {@link #executeReliableWrite} will execute all writes. If a characteristic - * was not written correctly, calling {@link #abortReliableWrite} will - * cancel the current transaction without committing any values on the - * remote device. - * - * @return true, if the reliable write transaction has been initiated - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public boolean beginReliableWrite() { - if (VDBG) Log.d(TAG, "beginReliableWrite() - device: " + mDevice.getAddress()); - if (mService == null || mClientIf == 0) return false; - - try { - mService.beginReliableWrite(mClientIf, mDevice.getAddress(), mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "", e); - return false; - } - - return true; - } - - /** - * Executes a reliable write transaction for a given remote device. - * - *

This function will commit all queued up characteristic write - * operations for a given remote device. - * - *

A {@link BluetoothGattCallback#onReliableWriteCompleted} callback is - * invoked to indicate whether the transaction has been executed correctly. - * - * @return true, if the request to execute the transaction has been sent - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public boolean executeReliableWrite() { - if (VDBG) Log.d(TAG, "executeReliableWrite() - device: " + mDevice.getAddress()); - if (mService == null || mClientIf == 0) return false; - - synchronized (mDeviceBusyLock) { - if (mDeviceBusy) return false; - mDeviceBusy = true; - } - - try { - mService.endReliableWrite(mClientIf, mDevice.getAddress(), true, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "", e); - synchronized (mDeviceBusyLock) { - mDeviceBusy = false; - } - return false; - } - - return true; - } - - /** - * Cancels a reliable write transaction for a given device. - * - *

Calling this function will discard all queued characteristic write - * operations for a given remote device. - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public void abortReliableWrite() { - if (VDBG) Log.d(TAG, "abortReliableWrite() - device: " + mDevice.getAddress()); - if (mService == null || mClientIf == 0) return; - - try { - mService.endReliableWrite(mClientIf, mDevice.getAddress(), false, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "", e); - } - } - - /** - * @deprecated Use {@link #abortReliableWrite()} - */ - @Deprecated - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public void abortReliableWrite(BluetoothDevice mDevice) { - abortReliableWrite(); - } - - /** - * Enable or disable notifications/indications for a given characteristic. - * - *

Once notifications are enabled for a characteristic, a - * {@link BluetoothGattCallback#onCharacteristicChanged(BluetoothGatt, - * BluetoothGattCharacteristic, byte[])} callback will be triggered if the remote device - * indicates that the given characteristic has changed. - * - * @param characteristic The characteristic for which to enable notifications - * @param enable Set to true to enable notifications/indications - * @return true, if the requested notification status was set successfully - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public boolean setCharacteristicNotification(BluetoothGattCharacteristic characteristic, - boolean enable) { - if (DBG) { - Log.d(TAG, "setCharacteristicNotification() - uuid: " + characteristic.getUuid() - + " enable: " + enable); - } - if (mService == null || mClientIf == 0) return false; - - BluetoothGattService service = characteristic.getService(); - if (service == null) return false; - - BluetoothDevice device = service.getDevice(); - if (device == null) return false; - - try { - mService.registerForNotification(mClientIf, device.getAddress(), - characteristic.getInstanceId(), enable, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "", e); - return false; - } - - return true; - } - - /** - * Clears the internal cache and forces a refresh of the services from the - * remote device. - * - * @hide - */ - @UnsupportedAppUsage - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public boolean refresh() { - if (DBG) Log.d(TAG, "refresh() - device: " + mDevice.getAddress()); - if (mService == null || mClientIf == 0) return false; - - try { - mService.refreshDevice(mClientIf, mDevice.getAddress(), mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "", e); - return false; - } - - return true; - } - - /** - * Read the RSSI for a connected remote device. - * - *

The {@link BluetoothGattCallback#onReadRemoteRssi} callback will be - * invoked when the RSSI value has been read. - * - * @return true, if the RSSI value has been requested successfully - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public boolean readRemoteRssi() { - if (DBG) Log.d(TAG, "readRssi() - device: " + mDevice.getAddress()); - if (mService == null || mClientIf == 0) return false; - - try { - mService.readRemoteRssi(mClientIf, mDevice.getAddress(), mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "", e); - return false; - } - - return true; - } - - /** - * Request an MTU size used for a given connection. - * - *

When performing a write request operation (write without response), - * the data sent is truncated to the MTU size. This function may be used - * to request a larger MTU size to be able to send more data at once. - * - *

A {@link BluetoothGattCallback#onMtuChanged} callback will indicate - * whether this operation was successful. - * - * @return true, if the new MTU value has been requested successfully - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public boolean requestMtu(int mtu) { - if (DBG) { - Log.d(TAG, "configureMTU() - device: " + mDevice.getAddress() - + " mtu: " + mtu); - } - if (mService == null || mClientIf == 0) return false; - - try { - mService.configureMTU(mClientIf, mDevice.getAddress(), mtu, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "", e); - return false; - } - - return true; - } - - /** - * Request a connection parameter update. - * - *

This function will send a connection parameter update request to the - * remote device. - * - * @param connectionPriority Request a specific connection priority. Must be one of {@link - * BluetoothGatt#CONNECTION_PRIORITY_BALANCED}, {@link BluetoothGatt#CONNECTION_PRIORITY_HIGH} - * 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 - || connectionPriority > CONNECTION_PRIORITY_LOW_POWER) { - throw new IllegalArgumentException("connectionPriority not within valid range"); - } - - if (DBG) Log.d(TAG, "requestConnectionPriority() - params: " + connectionPriority); - if (mService == null || mClientIf == 0) return false; - - try { - mService.connectionParameterUpdate( - mClientIf, mDevice.getAddress(), connectionPriority, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "", e); - return false; - } - - return true; - } - - /** - * Request an LE connection parameter update. - * - *

This function will send an LE connection parameters update request to the remote device. - * - * @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, - int minConnectionEventLen, int maxConnectionEventLen) { - if (DBG) { - Log.d(TAG, "requestLeConnectionUpdate() - min=(" + minConnectionInterval - + ")" + (1.25 * minConnectionInterval) - + "msec, max=(" + maxConnectionInterval + ")" - + (1.25 * maxConnectionInterval) + "msec, latency=" + slaveLatency - + ", timeout=" + supervisionTimeout + "msec" + ", min_ce=" - + minConnectionEventLen + ", max_ce=" + maxConnectionEventLen); - } - if (mService == null || mClientIf == 0) return false; - - try { - mService.leConnectionUpdate(mClientIf, mDevice.getAddress(), - minConnectionInterval, maxConnectionInterval, - slaveLatency, supervisionTimeout, - minConnectionEventLen, maxConnectionEventLen, - mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "", e); - return false; - } - - return true; - } - - /** - * @deprecated Not supported - please use {@link BluetoothManager#getConnectedDevices(int)} - * with {@link BluetoothProfile#GATT} as argument - * @throws UnsupportedOperationException - */ - @Override - @RequiresNoPermission - @Deprecated - public int getConnectionState(BluetoothDevice device) { - throw new UnsupportedOperationException("Use BluetoothManager#getConnectionState instead."); - } - - /** - * @deprecated Not supported - please use {@link BluetoothManager#getConnectedDevices(int)} - * with {@link BluetoothProfile#GATT} as argument - * - * @throws UnsupportedOperationException - */ - @Override - @RequiresNoPermission - @Deprecated - public List getConnectedDevices() { - throw new UnsupportedOperationException( - "Use BluetoothManager#getConnectedDevices instead."); - } - - /** - * @deprecated Not supported - please use - * {@link BluetoothManager#getDevicesMatchingConnectionStates(int, int[])} - * with {@link BluetoothProfile#GATT} as first argument - * - * @throws UnsupportedOperationException - */ - @Override - @RequiresNoPermission - @Deprecated - public List getDevicesMatchingConnectionStates(int[] states) { - throw new UnsupportedOperationException( - "Use BluetoothManager#getDevicesMatchingConnectionStates instead."); - } -} diff --git a/core/java/android/bluetooth/BluetoothGattCallback.java b/core/java/android/bluetooth/BluetoothGattCallback.java deleted file mode 100644 index d0a5a1e729fee71e1833e893b060bba4e1b62860..0000000000000000000000000000000000000000 --- a/core/java/android/bluetooth/BluetoothGattCallback.java +++ /dev/null @@ -1,267 +0,0 @@ -/* - * Copyright (C) 2017 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.bluetooth; - -import android.annotation.NonNull; - -/** - * This abstract class is used to implement {@link BluetoothGatt} callbacks. - */ -public abstract class BluetoothGattCallback { - - /** - * Callback triggered as result of {@link BluetoothGatt#setPreferredPhy}, or as a result of - * remote device changing the PHY. - * - * @param gatt GATT client - * @param txPhy the transmitter PHY in use. One of {@link BluetoothDevice#PHY_LE_1M}, {@link - * BluetoothDevice#PHY_LE_2M}, and {@link BluetoothDevice#PHY_LE_CODED}. - * @param rxPhy the receiver PHY in use. One of {@link BluetoothDevice#PHY_LE_1M}, {@link - * BluetoothDevice#PHY_LE_2M}, and {@link BluetoothDevice#PHY_LE_CODED}. - * @param status Status of the PHY update operation. {@link BluetoothGatt#GATT_SUCCESS} if the - * operation succeeds. - */ - public void onPhyUpdate(BluetoothGatt gatt, int txPhy, int rxPhy, int status) { - } - - /** - * Callback triggered as result of {@link BluetoothGatt#readPhy} - * - * @param gatt GATT client - * @param txPhy the transmitter PHY in use. One of {@link BluetoothDevice#PHY_LE_1M}, {@link - * BluetoothDevice#PHY_LE_2M}, and {@link BluetoothDevice#PHY_LE_CODED}. - * @param rxPhy the receiver PHY in use. One of {@link BluetoothDevice#PHY_LE_1M}, {@link - * BluetoothDevice#PHY_LE_2M}, and {@link BluetoothDevice#PHY_LE_CODED}. - * @param status Status of the PHY read operation. {@link BluetoothGatt#GATT_SUCCESS} if the - * operation succeeds. - */ - public void onPhyRead(BluetoothGatt gatt, int txPhy, int rxPhy, int status) { - } - - /** - * Callback indicating when GATT client has connected/disconnected to/from a remote - * GATT server. - * - * @param gatt GATT client - * @param status Status of the connect or disconnect operation. {@link - * BluetoothGatt#GATT_SUCCESS} if the operation succeeds. - * @param newState Returns the new connection state. Can be one of {@link - * BluetoothProfile#STATE_DISCONNECTED} or {@link BluetoothProfile#STATE_CONNECTED} - */ - public void onConnectionStateChange(BluetoothGatt gatt, int status, - int newState) { - } - - /** - * Callback invoked when the list of remote services, characteristics and descriptors - * for the remote device have been updated, ie new services have been discovered. - * - * @param gatt GATT client invoked {@link BluetoothGatt#discoverServices} - * @param status {@link BluetoothGatt#GATT_SUCCESS} if the remote device has been explored - * successfully. - */ - public void onServicesDiscovered(BluetoothGatt gatt, int status) { - } - - /** - * Callback reporting the result of a characteristic read operation. - * - * @param gatt GATT client invoked - * {@link BluetoothGatt#readCharacteristic(BluetoothGattCharacteristic)} - * @param characteristic Characteristic that was read from the associated remote device. - * @param status {@link BluetoothGatt#GATT_SUCCESS} if the read operation was completed - * successfully. - * @deprecated Use {@link BluetoothGattCallback#onCharacteristicRead(BluetoothGatt, - * BluetoothGattCharacteristic, byte[], int)} as it is memory safe - */ - @Deprecated - public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, - int status) { - } - - /** - * Callback reporting the result of a characteristic read operation. - * - * @param gatt GATT client invoked - * {@link BluetoothGatt#readCharacteristic(BluetoothGattCharacteristic)} - * @param characteristic Characteristic that was read from the associated remote device. - * @param value the value of the characteristic - * @param status {@link BluetoothGatt#GATT_SUCCESS} if the read operation was completed - * successfully. - */ - public void onCharacteristicRead(@NonNull BluetoothGatt gatt, @NonNull - BluetoothGattCharacteristic characteristic, @NonNull byte[] value, int status) { - } - - /** - * Callback indicating the result of a characteristic write operation. - * - *

If this callback is invoked while a reliable write transaction is - * in progress, the value of the characteristic represents the value - * reported by the remote device. An application should compare this - * value to the desired value to be written. If the values don't match, - * the application must abort the reliable write transaction. - * - * @param gatt GATT client that invoked - * {@link BluetoothGatt#writeCharacteristic(BluetoothGattCharacteristic, - * byte[], int)} - * @param characteristic Characteristic that was written to the associated remote device. - * @param status The result of the write operation {@link BluetoothGatt#GATT_SUCCESS} if - * the - * operation succeeds. - */ - public void onCharacteristicWrite(BluetoothGatt gatt, - BluetoothGattCharacteristic characteristic, int status) { - } - - /** - * Callback triggered as a result of a remote characteristic notification. - * - * @param gatt GATT client the characteristic is associated with - * @param characteristic Characteristic that has been updated as a result of a remote - * notification event. - * @deprecated Use {@link BluetoothGattCallback#onCharacteristicChanged(BluetoothGatt, - * BluetoothGattCharacteristic, byte[])} as it is memory safe by providing the characteristic - * value at the time of notification. - */ - @Deprecated - public void onCharacteristicChanged(BluetoothGatt gatt, - BluetoothGattCharacteristic characteristic) { - } - - /** - * Callback triggered as a result of a remote characteristic notification. Note that the value - * within the characteristic object may have changed since receiving the remote characteristic - * notification, so check the parameter value for the value at the time of notification. - * - * @param gatt GATT client the characteristic is associated with - * @param characteristic Characteristic that has been updated as a result of a remote - * notification event. - * @param value notified characteristic value - */ - public void onCharacteristicChanged(@NonNull BluetoothGatt gatt, - @NonNull BluetoothGattCharacteristic characteristic, @NonNull byte[] value) { - } - - /** - * Callback reporting the result of a descriptor read operation. - * - * @param gatt GATT client invoked {@link BluetoothGatt#readDescriptor} - * @param descriptor Descriptor that was read from the associated remote device. - * @param status {@link BluetoothGatt#GATT_SUCCESS} if the read operation was completed - * successfully - * @deprecated Use {@link BluetoothGattCallback#onDescriptorRead(BluetoothGatt, - * BluetoothGattDescriptor, int, byte[])} as it is memory safe by providing the descriptor - * value at the time it was read. - */ - @Deprecated - public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, - int status) { - } - - /** - * Callback reporting the result of a descriptor read operation. - * - * @param gatt GATT client invoked {@link BluetoothGatt#readDescriptor} - * @param descriptor Descriptor that was read from the associated remote device. - * @param status {@link BluetoothGatt#GATT_SUCCESS} if the read operation was completed - * successfully - * @param value the descriptor value at the time of the read operation - */ - public void onDescriptorRead(@NonNull BluetoothGatt gatt, - @NonNull BluetoothGattDescriptor descriptor, int status, @NonNull byte[] value) { - } - - /** - * Callback indicating the result of a descriptor write operation. - * - * @param gatt GATT client invoked {@link BluetoothGatt#writeDescriptor} - * @param descriptor Descriptor that was writte to the associated remote device. - * @param status The result of the write operation {@link BluetoothGatt#GATT_SUCCESS} if the - * operation succeeds. - */ - public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, - int status) { - } - - /** - * Callback invoked when a reliable write transaction has been completed. - * - * @param gatt GATT client invoked {@link BluetoothGatt#executeReliableWrite} - * @param status {@link BluetoothGatt#GATT_SUCCESS} if the reliable write transaction was - * executed successfully - */ - public void onReliableWriteCompleted(BluetoothGatt gatt, int status) { - } - - /** - * Callback reporting the RSSI for a remote device connection. - * - * This callback is triggered in response to the - * {@link BluetoothGatt#readRemoteRssi} function. - * - * @param gatt GATT client invoked {@link BluetoothGatt#readRemoteRssi} - * @param rssi The RSSI value for the remote device - * @param status {@link BluetoothGatt#GATT_SUCCESS} if the RSSI was read successfully - */ - public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) { - } - - /** - * Callback indicating the MTU for a given device connection has changed. - * - * This callback is triggered in response to the - * {@link BluetoothGatt#requestMtu} function, or in response to a connection - * event. - * - * @param gatt GATT client invoked {@link BluetoothGatt#requestMtu} - * @param mtu The new MTU size - * @param status {@link BluetoothGatt#GATT_SUCCESS} if the MTU has been changed successfully - */ - public void onMtuChanged(BluetoothGatt gatt, int mtu, int status) { - } - - /** - * Callback indicating the connection parameters were updated. - * - * @param gatt GATT client involved - * @param interval Connection interval used on this connection, 1.25ms unit. Valid range is from - * 6 (7.5ms) to 3200 (4000ms). - * @param latency Worker latency for the connection in number of connection events. Valid range - * is from 0 to 499 - * @param timeout Supervision timeout for this connection, in 10ms unit. Valid range is from 10 - * (0.1s) to 3200 (32s) - * @param status {@link BluetoothGatt#GATT_SUCCESS} if the connection has been updated - * successfully - * @hide - */ - public void onConnectionUpdated(BluetoothGatt gatt, int interval, int latency, int timeout, - int status) { - } - - /** - * Callback indicating service changed event is received - * - *

Receiving this event means that the GATT database is out of sync with - * the remote device. {@link BluetoothGatt#discoverServices} should be - * called to re-discover the services. - * - * @param gatt GATT client involved - */ - public void onServiceChanged(@NonNull BluetoothGatt gatt) { - } -} diff --git a/core/java/android/bluetooth/BluetoothGattCharacteristic.java b/core/java/android/bluetooth/BluetoothGattCharacteristic.java deleted file mode 100644 index c5e986e895b25f49a959779df7e366ee9ff96abf..0000000000000000000000000000000000000000 --- a/core/java/android/bluetooth/BluetoothGattCharacteristic.java +++ /dev/null @@ -1,806 +0,0 @@ -/* - * Copyright (C) 2013 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.bluetooth; - -import android.compat.annotation.UnsupportedAppUsage; -import android.os.Parcel; -import android.os.ParcelUuid; -import android.os.Parcelable; - -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; - -/** - * Represents a Bluetooth GATT Characteristic - * - *

A GATT characteristic is a basic data element used to construct a GATT service, - * {@link BluetoothGattService}. The characteristic contains a value as well as - * additional information and optional GATT descriptors, {@link BluetoothGattDescriptor}. - */ -public class BluetoothGattCharacteristic implements Parcelable { - - /** - * Characteristic proprty: Characteristic is broadcastable. - */ - public static final int PROPERTY_BROADCAST = 0x01; - - /** - * Characteristic property: Characteristic is readable. - */ - public static final int PROPERTY_READ = 0x02; - - /** - * Characteristic property: Characteristic can be written without response. - */ - public static final int PROPERTY_WRITE_NO_RESPONSE = 0x04; - - /** - * Characteristic property: Characteristic can be written. - */ - public static final int PROPERTY_WRITE = 0x08; - - /** - * Characteristic property: Characteristic supports notification - */ - public static final int PROPERTY_NOTIFY = 0x10; - - /** - * Characteristic property: Characteristic supports indication - */ - public static final int PROPERTY_INDICATE = 0x20; - - /** - * Characteristic property: Characteristic supports write with signature - */ - public static final int PROPERTY_SIGNED_WRITE = 0x40; - - /** - * Characteristic property: Characteristic has extended properties - */ - public static final int PROPERTY_EXTENDED_PROPS = 0x80; - - /** - * Characteristic read permission - */ - public static final int PERMISSION_READ = 0x01; - - /** - * Characteristic permission: Allow encrypted read operations - */ - public static final int PERMISSION_READ_ENCRYPTED = 0x02; - - /** - * Characteristic permission: Allow reading with person-in-the-middle protection - */ - public static final int PERMISSION_READ_ENCRYPTED_MITM = 0x04; - - /** - * Characteristic write permission - */ - public static final int PERMISSION_WRITE = 0x10; - - /** - * Characteristic permission: Allow encrypted writes - */ - public static final int PERMISSION_WRITE_ENCRYPTED = 0x20; - - /** - * Characteristic permission: Allow encrypted writes with person-in-the-middle - * protection - */ - public static final int PERMISSION_WRITE_ENCRYPTED_MITM = 0x40; - - /** - * Characteristic permission: Allow signed write operations - */ - public static final int PERMISSION_WRITE_SIGNED = 0x80; - - /** - * Characteristic permission: Allow signed write operations with - * person-in-the-middle protection - */ - public static final int PERMISSION_WRITE_SIGNED_MITM = 0x100; - - /** - * Write characteristic, requesting acknoledgement by the remote device - */ - public static final int WRITE_TYPE_DEFAULT = 0x02; - - /** - * Write characteristic without requiring a response by the remote device - */ - public static final int WRITE_TYPE_NO_RESPONSE = 0x01; - - /** - * Write characteristic including authentication signature - */ - public static final int WRITE_TYPE_SIGNED = 0x04; - - /** - * Characteristic value format type uint8 - */ - public static final int FORMAT_UINT8 = 0x11; - - /** - * Characteristic value format type uint16 - */ - public static final int FORMAT_UINT16 = 0x12; - - /** - * Characteristic value format type uint32 - */ - public static final int FORMAT_UINT32 = 0x14; - - /** - * Characteristic value format type sint8 - */ - public static final int FORMAT_SINT8 = 0x21; - - /** - * Characteristic value format type sint16 - */ - public static final int FORMAT_SINT16 = 0x22; - - /** - * Characteristic value format type sint32 - */ - public static final int FORMAT_SINT32 = 0x24; - - /** - * Characteristic value format type sfloat (16-bit float) - */ - public static final int FORMAT_SFLOAT = 0x32; - - /** - * Characteristic value format type float (32-bit float) - */ - public static final int FORMAT_FLOAT = 0x34; - - - /** - * The UUID of this characteristic. - * - * @hide - */ - protected UUID mUuid; - - /** - * Instance ID for this characteristic. - * - * @hide - */ - @UnsupportedAppUsage - protected int mInstance; - - /** - * Characteristic properties. - * - * @hide - */ - protected int mProperties; - - /** - * Characteristic permissions. - * - * @hide - */ - protected int mPermissions; - - /** - * Key size (default = 16). - * - * @hide - */ - protected int mKeySize = 16; - - /** - * Write type for this characteristic. - * See WRITE_TYPE_* constants. - * - * @hide - */ - protected int mWriteType; - - /** - * Back-reference to the service this characteristic belongs to. - * - * @hide - */ - @UnsupportedAppUsage - protected BluetoothGattService mService; - - /** - * The cached value of this characteristic. - * - * @hide - */ - protected byte[] mValue; - - /** - * List of descriptors included in this characteristic. - */ - protected List mDescriptors; - - /** - * Create a new BluetoothGattCharacteristic. - * - * @param uuid The UUID for this characteristic - * @param properties Properties of this characteristic - * @param permissions Permissions for this characteristic - */ - public BluetoothGattCharacteristic(UUID uuid, int properties, int permissions) { - initCharacteristic(null, uuid, 0, properties, permissions); - } - - /** - * Create a new BluetoothGattCharacteristic - * - * @hide - */ - /*package*/ BluetoothGattCharacteristic(BluetoothGattService service, - UUID uuid, int instanceId, - int properties, int permissions) { - initCharacteristic(service, uuid, instanceId, properties, permissions); - } - - /** - * Create a new BluetoothGattCharacteristic - * - * @hide - */ - public BluetoothGattCharacteristic(UUID uuid, int instanceId, - int properties, int permissions) { - initCharacteristic(null, uuid, instanceId, properties, permissions); - } - - private void initCharacteristic(BluetoothGattService service, - UUID uuid, int instanceId, - int properties, int permissions) { - mUuid = uuid; - mInstance = instanceId; - mProperties = properties; - mPermissions = permissions; - mService = service; - mValue = null; - mDescriptors = new ArrayList(); - - if ((mProperties & PROPERTY_WRITE_NO_RESPONSE) != 0) { - mWriteType = WRITE_TYPE_NO_RESPONSE; - } else { - mWriteType = WRITE_TYPE_DEFAULT; - } - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel out, int flags) { - out.writeParcelable(new ParcelUuid(mUuid), 0); - out.writeInt(mInstance); - out.writeInt(mProperties); - out.writeInt(mPermissions); - out.writeInt(mKeySize); - out.writeInt(mWriteType); - out.writeTypedList(mDescriptors); - } - - public static final @android.annotation.NonNull Parcelable.Creator CREATOR = - new Parcelable.Creator() { - public BluetoothGattCharacteristic createFromParcel(Parcel in) { - return new BluetoothGattCharacteristic(in); - } - - public BluetoothGattCharacteristic[] newArray(int size) { - return new BluetoothGattCharacteristic[size]; - } - }; - - private BluetoothGattCharacteristic(Parcel in) { - mUuid = ((ParcelUuid) in.readParcelable(null)).getUuid(); - mInstance = in.readInt(); - mProperties = in.readInt(); - mPermissions = in.readInt(); - mKeySize = in.readInt(); - mWriteType = in.readInt(); - - mDescriptors = new ArrayList(); - - ArrayList descs = - in.createTypedArrayList(BluetoothGattDescriptor.CREATOR); - if (descs != null) { - for (BluetoothGattDescriptor desc : descs) { - desc.setCharacteristic(this); - mDescriptors.add(desc); - } - } - } - - /** - * Returns the desired key size. - * - * @hide - */ - public int getKeySize() { - return mKeySize; - } - - /** - * Adds a descriptor to this characteristic. - * - * @param descriptor Descriptor to be added to this characteristic. - * @return true, if the descriptor was added to the characteristic - */ - public boolean addDescriptor(BluetoothGattDescriptor descriptor) { - mDescriptors.add(descriptor); - descriptor.setCharacteristic(this); - return true; - } - - /** - * Get a descriptor by UUID and isntance id. - * - * @hide - */ - /*package*/ BluetoothGattDescriptor getDescriptor(UUID uuid, int instanceId) { - for (BluetoothGattDescriptor descriptor : mDescriptors) { - if (descriptor.getUuid().equals(uuid) - && descriptor.getInstanceId() == instanceId) { - return descriptor; - } - } - return null; - } - - /** - * Returns the service this characteristic belongs to. - * - * @return The asscociated service - */ - public BluetoothGattService getService() { - return mService; - } - - /** - * Sets the service associated with this device. - * - * @hide - */ - @UnsupportedAppUsage - /*package*/ void setService(BluetoothGattService service) { - mService = service; - } - - /** - * Returns the UUID of this characteristic - * - * @return UUID of this characteristic - */ - public UUID getUuid() { - return mUuid; - } - - /** - * Returns the instance ID for this characteristic. - * - *

If a remote device offers multiple characteristics with the same UUID, - * the instance ID is used to distuinguish between characteristics. - * - * @return Instance ID of this characteristic - */ - public int getInstanceId() { - return mInstance; - } - - /** - * Force the instance ID. - * - * @hide - */ - public void setInstanceId(int instanceId) { - mInstance = instanceId; - } - - /** - * Returns the properties of this characteristic. - * - *

The properties contain a bit mask of property flags indicating - * the features of this characteristic. - * - * @return Properties of this characteristic - */ - public int getProperties() { - return mProperties; - } - - /** - * Returns the permissions for this characteristic. - * - * @return Permissions of this characteristic - */ - public int getPermissions() { - return mPermissions; - } - - /** - * Gets the write type for this characteristic. - * - * @return Write type for this characteristic - */ - public int getWriteType() { - return mWriteType; - } - - /** - * Set the write type for this characteristic - * - *

Setting the write type of a characteristic determines how the - * {@link BluetoothGatt#writeCharacteristic(BluetoothGattCharacteristic, byte[], int)} function - * write this characteristic. - * - * @param writeType The write type to for this characteristic. Can be one of: {@link - * #WRITE_TYPE_DEFAULT}, {@link #WRITE_TYPE_NO_RESPONSE} or {@link #WRITE_TYPE_SIGNED}. - */ - public void setWriteType(int writeType) { - mWriteType = writeType; - } - - /** - * Set the desired key size. - * - * @hide - */ - @UnsupportedAppUsage - public void setKeySize(int keySize) { - mKeySize = keySize; - } - - /** - * Returns a list of descriptors for this characteristic. - * - * @return Descriptors for this characteristic - */ - public List getDescriptors() { - return mDescriptors; - } - - /** - * Returns a descriptor with a given UUID out of the list of - * descriptors for this characteristic. - * - * @return GATT descriptor object or null if no descriptor with the given UUID was found. - */ - public BluetoothGattDescriptor getDescriptor(UUID uuid) { - for (BluetoothGattDescriptor descriptor : mDescriptors) { - if (descriptor.getUuid().equals(uuid)) { - return descriptor; - } - } - return null; - } - - /** - * Get the stored value for this characteristic. - * - *

This function returns the stored value for this characteristic as - * retrieved by calling {@link BluetoothGatt#readCharacteristic}. The cached - * value of the characteristic is updated as a result of a read characteristic - * operation or if a characteristic update notification has been received. - * - * @return Cached value of the characteristic - * - * @deprecated Use {@link BluetoothGatt#readCharacteristic(BluetoothGattCharacteristic)} instead - */ - @Deprecated - public byte[] getValue() { - return mValue; - } - - /** - * Return the stored value of this characteristic. - * - *

The formatType parameter determines how the characteristic value - * is to be interpreted. For example, settting formatType to - * {@link #FORMAT_UINT16} specifies that the first two bytes of the - * characteristic value at the given offset are interpreted to generate the - * return value. - * - * @param formatType The format type used to interpret the characteristic value. - * @param offset Offset at which the integer value can be found. - * @return Cached value of the characteristic or null of offset exceeds value size. - * - * @deprecated Use {@link BluetoothGatt#readCharacteristic(BluetoothGattCharacteristic)} to get - * the characteristic value - */ - @Deprecated - public Integer getIntValue(int formatType, int offset) { - if ((offset + getTypeLen(formatType)) > mValue.length) return null; - - switch (formatType) { - case FORMAT_UINT8: - return unsignedByteToInt(mValue[offset]); - - case FORMAT_UINT16: - return unsignedBytesToInt(mValue[offset], mValue[offset + 1]); - - case FORMAT_UINT32: - return unsignedBytesToInt(mValue[offset], mValue[offset + 1], - mValue[offset + 2], mValue[offset + 3]); - case FORMAT_SINT8: - return unsignedToSigned(unsignedByteToInt(mValue[offset]), 8); - - case FORMAT_SINT16: - return unsignedToSigned(unsignedBytesToInt(mValue[offset], - mValue[offset + 1]), 16); - - case FORMAT_SINT32: - return unsignedToSigned(unsignedBytesToInt(mValue[offset], - mValue[offset + 1], mValue[offset + 2], mValue[offset + 3]), 32); - } - - return null; - } - - /** - * Return the stored value of this characteristic. - *

See {@link #getValue} for details. - * - * @param formatType The format type used to interpret the characteristic value. - * @param offset Offset at which the float value can be found. - * @return Cached value of the characteristic at a given offset or null if the requested offset - * exceeds the value size. - * - * @deprecated Use {@link BluetoothGatt#readCharacteristic(BluetoothGattCharacteristic)} to get - * the characteristic value - */ - @Deprecated - public Float getFloatValue(int formatType, int offset) { - if ((offset + getTypeLen(formatType)) > mValue.length) return null; - - switch (formatType) { - case FORMAT_SFLOAT: - return bytesToFloat(mValue[offset], mValue[offset + 1]); - - case FORMAT_FLOAT: - return bytesToFloat(mValue[offset], mValue[offset + 1], - mValue[offset + 2], mValue[offset + 3]); - } - - return null; - } - - /** - * Return the stored value of this characteristic. - *

See {@link #getValue} for details. - * - * @param offset Offset at which the string value can be found. - * @return Cached value of the characteristic - * - * @deprecated Use {@link BluetoothGatt#readCharacteristic(BluetoothGattCharacteristic)} to get - * the characteristic value - */ - @Deprecated - public String getStringValue(int offset) { - if (mValue == null || offset > mValue.length) return null; - byte[] strBytes = new byte[mValue.length - offset]; - for (int i = 0; i != (mValue.length - offset); ++i) strBytes[i] = mValue[offset + i]; - return new String(strBytes); - } - - /** - * Updates the locally stored value of this characteristic. - * - *

This function modifies the locally stored cached value of this - * characteristic. To send the value to the remote device, call - * {@link BluetoothGatt#writeCharacteristic} to send the value to the - * remote device. - * - * @param value New value for this characteristic - * @return true if the locally stored value has been set, false if the requested value could not - * be stored locally. - * - * @deprecated Pass the characteristic value directly into - * {@link BluetoothGatt#writeCharacteristic(BluetoothGattCharacteristic, byte[], int)} - */ - @Deprecated - public boolean setValue(byte[] value) { - mValue = value; - return true; - } - - /** - * Set the locally stored value of this characteristic. - *

See {@link #setValue(byte[])} for details. - * - * @param value New value for this characteristic - * @param formatType Integer format type used to transform the value parameter - * @param offset Offset at which the value should be placed - * @return true if the locally stored value has been set - * - * @deprecated Pass the characteristic value directly into - * {@link BluetoothGatt#writeCharacteristic(BluetoothGattCharacteristic, byte[], int)} - */ - @Deprecated - public boolean setValue(int value, int formatType, int offset) { - int len = offset + getTypeLen(formatType); - if (mValue == null) mValue = new byte[len]; - if (len > mValue.length) return false; - - switch (formatType) { - case FORMAT_SINT8: - value = intToSignedBits(value, 8); - // Fall-through intended - case FORMAT_UINT8: - mValue[offset] = (byte) (value & 0xFF); - break; - - case FORMAT_SINT16: - value = intToSignedBits(value, 16); - // Fall-through intended - case FORMAT_UINT16: - mValue[offset++] = (byte) (value & 0xFF); - mValue[offset] = (byte) ((value >> 8) & 0xFF); - break; - - case FORMAT_SINT32: - value = intToSignedBits(value, 32); - // Fall-through intended - case FORMAT_UINT32: - mValue[offset++] = (byte) (value & 0xFF); - mValue[offset++] = (byte) ((value >> 8) & 0xFF); - mValue[offset++] = (byte) ((value >> 16) & 0xFF); - mValue[offset] = (byte) ((value >> 24) & 0xFF); - break; - - default: - return false; - } - return true; - } - - /** - * Set the locally stored value of this characteristic. - *

See {@link #setValue(byte[])} for details. - * - * @param mantissa Mantissa for this characteristic - * @param exponent exponent value for this characteristic - * @param formatType Float format type used to transform the value parameter - * @param offset Offset at which the value should be placed - * @return true if the locally stored value has been set - * - * @deprecated Pass the characteristic value directly into - * {@link BluetoothGatt#writeCharacteristic(BluetoothGattCharacteristic, byte[], int)} - */ - @Deprecated - public boolean setValue(int mantissa, int exponent, int formatType, int offset) { - int len = offset + getTypeLen(formatType); - if (mValue == null) mValue = new byte[len]; - if (len > mValue.length) return false; - - switch (formatType) { - case FORMAT_SFLOAT: - mantissa = intToSignedBits(mantissa, 12); - exponent = intToSignedBits(exponent, 4); - mValue[offset++] = (byte) (mantissa & 0xFF); - mValue[offset] = (byte) ((mantissa >> 8) & 0x0F); - mValue[offset] += (byte) ((exponent & 0x0F) << 4); - break; - - case FORMAT_FLOAT: - mantissa = intToSignedBits(mantissa, 24); - exponent = intToSignedBits(exponent, 8); - mValue[offset++] = (byte) (mantissa & 0xFF); - mValue[offset++] = (byte) ((mantissa >> 8) & 0xFF); - mValue[offset++] = (byte) ((mantissa >> 16) & 0xFF); - mValue[offset] += (byte) (exponent & 0xFF); - break; - - default: - return false; - } - - return true; - } - - /** - * Set the locally stored value of this characteristic. - *

See {@link #setValue(byte[])} for details. - * - * @param value New value for this characteristic - * @return true if the locally stored value has been set - * - * @deprecated Pass the characteristic value directly into - * {@link BluetoothGatt#writeCharacteristic(BluetoothGattCharacteristic, byte[], int)} - */ - @Deprecated - public boolean setValue(String value) { - mValue = value.getBytes(); - return true; - } - - /** - * Returns the size of a give value type. - */ - private int getTypeLen(int formatType) { - return formatType & 0xF; - } - - /** - * Convert a signed byte to an unsigned int. - */ - private int unsignedByteToInt(byte b) { - return b & 0xFF; - } - - /** - * Convert signed bytes to a 16-bit unsigned int. - */ - private int unsignedBytesToInt(byte b0, byte b1) { - return (unsignedByteToInt(b0) + (unsignedByteToInt(b1) << 8)); - } - - /** - * Convert signed bytes to a 32-bit unsigned int. - */ - private int unsignedBytesToInt(byte b0, byte b1, byte b2, byte b3) { - return (unsignedByteToInt(b0) + (unsignedByteToInt(b1) << 8)) - + (unsignedByteToInt(b2) << 16) + (unsignedByteToInt(b3) << 24); - } - - /** - * Convert signed bytes to a 16-bit short float value. - */ - private float bytesToFloat(byte b0, byte b1) { - int mantissa = unsignedToSigned(unsignedByteToInt(b0) - + ((unsignedByteToInt(b1) & 0x0F) << 8), 12); - int exponent = unsignedToSigned(unsignedByteToInt(b1) >> 4, 4); - return (float) (mantissa * Math.pow(10, exponent)); - } - - /** - * Convert signed bytes to a 32-bit short float value. - */ - private float bytesToFloat(byte b0, byte b1, byte b2, byte b3) { - int mantissa = unsignedToSigned(unsignedByteToInt(b0) - + (unsignedByteToInt(b1) << 8) - + (unsignedByteToInt(b2) << 16), 24); - return (float) (mantissa * Math.pow(10, b3)); - } - - /** - * Convert an unsigned integer value to a two's-complement encoded - * signed value. - */ - private int unsignedToSigned(int unsigned, int size) { - if ((unsigned & (1 << size - 1)) != 0) { - unsigned = -1 * ((1 << size - 1) - (unsigned & ((1 << size - 1) - 1))); - } - return unsigned; - } - - /** - * Convert an integer into the signed bits of a given length. - */ - private int intToSignedBits(int i, int size) { - if (i < 0) { - i = (1 << size - 1) + (i & ((1 << size - 1) - 1)); - } - return i; - } -} diff --git a/core/java/android/bluetooth/BluetoothGattDescriptor.java b/core/java/android/bluetooth/BluetoothGattDescriptor.java deleted file mode 100644 index a35d5b99fd7b2f1fc9e62ff2cdfe7e69bca8f0bb..0000000000000000000000000000000000000000 --- a/core/java/android/bluetooth/BluetoothGattDescriptor.java +++ /dev/null @@ -1,291 +0,0 @@ -/* - * Copyright (C) 2013 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.bluetooth; - -import android.compat.annotation.UnsupportedAppUsage; -import android.os.Parcel; -import android.os.ParcelUuid; -import android.os.Parcelable; - -import java.util.UUID; - -/** - * Represents a Bluetooth GATT Descriptor - * - *

GATT Descriptors contain additional information and attributes of a GATT - * characteristic, {@link BluetoothGattCharacteristic}. They can be used to describe - * the characteristic's features or to control certain behaviours of the characteristic. - */ -public class BluetoothGattDescriptor implements Parcelable { - - /** - * Value used to enable notification for a client configuration descriptor - */ - public static final byte[] ENABLE_NOTIFICATION_VALUE = {0x01, 0x00}; - - /** - * Value used to enable indication for a client configuration descriptor - */ - public static final byte[] ENABLE_INDICATION_VALUE = {0x02, 0x00}; - - /** - * Value used to disable notifications or indicatinos - */ - public static final byte[] DISABLE_NOTIFICATION_VALUE = {0x00, 0x00}; - - /** - * Descriptor read permission - */ - public static final int PERMISSION_READ = 0x01; - - /** - * Descriptor permission: Allow encrypted read operations - */ - public static final int PERMISSION_READ_ENCRYPTED = 0x02; - - /** - * Descriptor permission: Allow reading with person-in-the-middle protection - */ - public static final int PERMISSION_READ_ENCRYPTED_MITM = 0x04; - - /** - * Descriptor write permission - */ - public static final int PERMISSION_WRITE = 0x10; - - /** - * Descriptor permission: Allow encrypted writes - */ - public static final int PERMISSION_WRITE_ENCRYPTED = 0x20; - - /** - * Descriptor permission: Allow encrypted writes with person-in-the-middle - * protection - */ - public static final int PERMISSION_WRITE_ENCRYPTED_MITM = 0x40; - - /** - * Descriptor permission: Allow signed write operations - */ - public static final int PERMISSION_WRITE_SIGNED = 0x80; - - /** - * Descriptor permission: Allow signed write operations with - * person-in-the-middle protection - */ - public static final int PERMISSION_WRITE_SIGNED_MITM = 0x100; - - /** - * The UUID of this descriptor. - * - * @hide - */ - protected UUID mUuid; - - /** - * Instance ID for this descriptor. - * - * @hide - */ - @UnsupportedAppUsage - protected int mInstance; - - /** - * Permissions for this descriptor - * - * @hide - */ - protected int mPermissions; - - /** - * Back-reference to the characteristic this descriptor belongs to. - * - * @hide - */ - @UnsupportedAppUsage - protected BluetoothGattCharacteristic mCharacteristic; - - /** - * The value for this descriptor. - * - * @hide - */ - protected byte[] mValue; - - /** - * Create a new BluetoothGattDescriptor. - * - * @param uuid The UUID for this descriptor - * @param permissions Permissions for this descriptor - */ - public BluetoothGattDescriptor(UUID uuid, int permissions) { - initDescriptor(null, uuid, 0, permissions); - } - - /** - * Create a new BluetoothGattDescriptor. - * - * @param characteristic The characteristic this descriptor belongs to - * @param uuid The UUID for this descriptor - * @param permissions Permissions for this descriptor - */ - /*package*/ BluetoothGattDescriptor(BluetoothGattCharacteristic characteristic, UUID uuid, - int instance, int permissions) { - initDescriptor(characteristic, uuid, instance, permissions); - } - - /** - * @hide - */ - public BluetoothGattDescriptor(UUID uuid, int instance, int permissions) { - initDescriptor(null, uuid, instance, permissions); - } - - private void initDescriptor(BluetoothGattCharacteristic characteristic, UUID uuid, - int instance, int permissions) { - mCharacteristic = characteristic; - mUuid = uuid; - mInstance = instance; - mPermissions = permissions; - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel out, int flags) { - out.writeParcelable(new ParcelUuid(mUuid), 0); - out.writeInt(mInstance); - out.writeInt(mPermissions); - } - - public static final @android.annotation.NonNull Parcelable.Creator CREATOR = - new Parcelable.Creator() { - public BluetoothGattDescriptor createFromParcel(Parcel in) { - return new BluetoothGattDescriptor(in); - } - - public BluetoothGattDescriptor[] newArray(int size) { - return new BluetoothGattDescriptor[size]; - } - }; - - private BluetoothGattDescriptor(Parcel in) { - mUuid = ((ParcelUuid) in.readParcelable(null)).getUuid(); - mInstance = in.readInt(); - mPermissions = in.readInt(); - } - - /** - * Returns the characteristic this descriptor belongs to. - * - * @return The characteristic. - */ - public BluetoothGattCharacteristic getCharacteristic() { - return mCharacteristic; - } - - /** - * Set the back-reference to the associated characteristic - * - * @hide - */ - @UnsupportedAppUsage - /*package*/ void setCharacteristic(BluetoothGattCharacteristic characteristic) { - mCharacteristic = characteristic; - } - - /** - * Returns the UUID of this descriptor. - * - * @return UUID of this descriptor - */ - public UUID getUuid() { - return mUuid; - } - - /** - * Returns the instance ID for this descriptor. - * - *

If a remote device offers multiple descriptors with the same UUID, - * the instance ID is used to distuinguish between descriptors. - * - * @return Instance ID of this descriptor - * @hide - */ - public int getInstanceId() { - return mInstance; - } - - /** - * Force the instance ID. - * - * @hide - */ - public void setInstanceId(int instanceId) { - mInstance = instanceId; - } - - /** - * Returns the permissions for this descriptor. - * - * @return Permissions of this descriptor - */ - public int getPermissions() { - return mPermissions; - } - - /** - * Returns the stored value for this descriptor - * - *

This function returns the stored value for this descriptor as - * retrieved by calling {@link BluetoothGatt#readDescriptor}. The cached - * value of the descriptor is updated as a result of a descriptor read - * operation. - * - * @return Cached value of the descriptor - * - * @deprecated Use {@link BluetoothGatt#readDescriptor(BluetoothGattDescriptor)} instead - */ - @Deprecated - public byte[] getValue() { - return mValue; - } - - /** - * Updates the locally stored value of this descriptor. - * - *

This function modifies the locally stored cached value of this - * descriptor. To send the value to the remote device, call - * {@link BluetoothGatt#writeDescriptor} to send the value to the - * remote device. - * - * @param value New value for this descriptor - * @return true if the locally stored value has been set, false if the requested value could not - * be stored locally. - * - * @deprecated Pass the descriptor value directly into - * {@link BluetoothGatt#writeDescriptor(BluetoothGattDescriptor, byte[])} - */ - @Deprecated - public boolean setValue(byte[] value) { - mValue = value; - return true; - } -} diff --git a/core/java/android/bluetooth/BluetoothGattIncludedService.java b/core/java/android/bluetooth/BluetoothGattIncludedService.java deleted file mode 100644 index 5580619033a65742d14a0953d7e06863d819dddb..0000000000000000000000000000000000000000 --- a/core/java/android/bluetooth/BluetoothGattIncludedService.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright (C) 2016 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.bluetooth; - -import android.os.Parcel; -import android.os.ParcelUuid; -import android.os.Parcelable; - -import java.util.UUID; - -/** - * Represents a Bluetooth GATT Included Service - * - * @hide - */ -public class BluetoothGattIncludedService implements Parcelable { - - /** - * The UUID of this service. - */ - protected UUID mUuid; - - /** - * Instance ID for this service. - */ - protected int mInstanceId; - - /** - * Service type (Primary/Secondary). - */ - protected int mServiceType; - - /** - * Create a new BluetoothGattIncludedService - */ - public BluetoothGattIncludedService(UUID uuid, int instanceId, int serviceType) { - mUuid = uuid; - mInstanceId = instanceId; - mServiceType = serviceType; - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel out, int flags) { - out.writeParcelable(new ParcelUuid(mUuid), 0); - out.writeInt(mInstanceId); - out.writeInt(mServiceType); - } - - public static final @android.annotation.NonNull Parcelable.Creator CREATOR = - new Parcelable.Creator() { - public BluetoothGattIncludedService createFromParcel(Parcel in) { - return new BluetoothGattIncludedService(in); - } - - public BluetoothGattIncludedService[] newArray(int size) { - return new BluetoothGattIncludedService[size]; - } - }; - - private BluetoothGattIncludedService(Parcel in) { - mUuid = ((ParcelUuid) in.readParcelable(null)).getUuid(); - mInstanceId = in.readInt(); - mServiceType = in.readInt(); - } - - /** - * Returns the UUID of this service - * - * @return UUID of this service - */ - public UUID getUuid() { - return mUuid; - } - - /** - * Returns the instance ID for this service - * - *

If a remote device offers multiple services with the same UUID - * (ex. multiple battery services for different batteries), the instance - * ID is used to distuinguish services. - * - * @return Instance ID of this service - */ - public int getInstanceId() { - return mInstanceId; - } - - /** - * Get the type of this service (primary/secondary) - */ - public int getType() { - return mServiceType; - } -} diff --git a/core/java/android/bluetooth/BluetoothGattServer.java b/core/java/android/bluetooth/BluetoothGattServer.java deleted file mode 100644 index 08e0178403f16a667cd535b969f66441a3fddf8c..0000000000000000000000000000000000000000 --- a/core/java/android/bluetooth/BluetoothGattServer.java +++ /dev/null @@ -1,954 +0,0 @@ -/* - * Copyright (C) 2013 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.bluetooth; - -import android.annotation.IntDef; -import android.annotation.NonNull; -import android.annotation.RequiresNoPermission; -import android.annotation.RequiresPermission; -import android.annotation.SuppressLint; -import android.bluetooth.annotations.RequiresBluetoothConnectPermission; -import android.bluetooth.annotations.RequiresLegacyBluetoothPermission; -import android.content.AttributionSource; -import android.os.ParcelUuid; -import android.os.RemoteException; -import android.util.Log; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; - -/** - * Public API for the Bluetooth GATT Profile server role. - * - *

This class provides Bluetooth GATT server role functionality, - * allowing applications to create Bluetooth Smart services and - * characteristics. - * - *

BluetoothGattServer is a proxy object for controlling the Bluetooth Service - * via IPC. Use {@link BluetoothManager#openGattServer} to get an instance - * of this class. - */ -public final class BluetoothGattServer implements BluetoothProfile { - private static final String TAG = "BluetoothGattServer"; - private static final boolean DBG = true; - private static final boolean VDBG = false; - - private final IBluetoothGatt mService; - private final BluetoothAdapter mAdapter; - private final AttributionSource mAttributionSource; - - private BluetoothGattServerCallback mCallback; - - private Object mServerIfLock = new Object(); - private int mServerIf; - private int mTransport; - private BluetoothGattService mPendingService; - private List mServices; - - private static final int CALLBACK_REG_TIMEOUT = 10000; - - /** - * Bluetooth GATT interface callbacks - */ - @SuppressLint("AndroidFrameworkBluetoothPermission") - private final IBluetoothGattServerCallback mBluetoothGattServerCallback = - new IBluetoothGattServerCallback.Stub() { - /** - * Application interface registered - app is ready to go - * @hide - */ - @Override - public void onServerRegistered(int status, int serverIf) { - if (DBG) { - Log.d(TAG, "onServerRegistered() - status=" + status - + " serverIf=" + serverIf); - } - synchronized (mServerIfLock) { - if (mCallback != null) { - mServerIf = serverIf; - mServerIfLock.notify(); - } else { - // registration timeout - Log.e(TAG, "onServerRegistered: mCallback is null"); - } - } - } - - /** - * Server connection state changed - * @hide - */ - @Override - public void onServerConnectionState(int status, int serverIf, - boolean connected, String address) { - if (DBG) { - Log.d(TAG, "onServerConnectionState() - status=" + status - + " serverIf=" + serverIf + " device=" + address); - } - try { - mCallback.onConnectionStateChange(mAdapter.getRemoteDevice(address), status, - connected ? BluetoothProfile.STATE_CONNECTED : - BluetoothProfile.STATE_DISCONNECTED); - } catch (Exception ex) { - Log.w(TAG, "Unhandled exception in callback", ex); - } - } - - /** - * Service has been added - * @hide - */ - @Override - public void onServiceAdded(int status, BluetoothGattService service) { - if (DBG) { - Log.d(TAG, "onServiceAdded() - handle=" + service.getInstanceId() - + " uuid=" + service.getUuid() + " status=" + status); - } - - if (mPendingService == null) { - return; - } - - BluetoothGattService tmp = mPendingService; - mPendingService = null; - - // Rewrite newly assigned handles to existing service. - tmp.setInstanceId(service.getInstanceId()); - List temp_chars = tmp.getCharacteristics(); - List svc_chars = service.getCharacteristics(); - for (int i = 0; i < svc_chars.size(); i++) { - BluetoothGattCharacteristic temp_char = temp_chars.get(i); - BluetoothGattCharacteristic svc_char = svc_chars.get(i); - - temp_char.setInstanceId(svc_char.getInstanceId()); - - List temp_descs = temp_char.getDescriptors(); - List svc_descs = svc_char.getDescriptors(); - for (int j = 0; j < svc_descs.size(); j++) { - temp_descs.get(j).setInstanceId(svc_descs.get(j).getInstanceId()); - } - } - - mServices.add(tmp); - - try { - mCallback.onServiceAdded((int) status, tmp); - } catch (Exception ex) { - Log.w(TAG, "Unhandled exception in callback", ex); - } - } - - /** - * Remote client characteristic read request. - * @hide - */ - @Override - public void onCharacteristicReadRequest(String address, int transId, - int offset, boolean isLong, int handle) { - if (VDBG) Log.d(TAG, "onCharacteristicReadRequest() - handle=" + handle); - - BluetoothDevice device = mAdapter.getRemoteDevice(address); - BluetoothGattCharacteristic characteristic = getCharacteristicByHandle(handle); - if (characteristic == null) { - Log.w(TAG, "onCharacteristicReadRequest() no char for handle " + handle); - return; - } - - try { - mCallback.onCharacteristicReadRequest(device, transId, offset, - characteristic); - } catch (Exception ex) { - Log.w(TAG, "Unhandled exception in callback", ex); - } - } - - /** - * Remote client descriptor read request. - * @hide - */ - @Override - public void onDescriptorReadRequest(String address, int transId, - int offset, boolean isLong, int handle) { - if (VDBG) Log.d(TAG, "onCharacteristicReadRequest() - handle=" + handle); - - BluetoothDevice device = mAdapter.getRemoteDevice(address); - BluetoothGattDescriptor descriptor = getDescriptorByHandle(handle); - if (descriptor == null) { - Log.w(TAG, "onDescriptorReadRequest() no desc for handle " + handle); - return; - } - - try { - mCallback.onDescriptorReadRequest(device, transId, offset, descriptor); - } catch (Exception ex) { - Log.w(TAG, "Unhandled exception in callback", ex); - } - } - - /** - * Remote client characteristic write request. - * @hide - */ - @Override - public void onCharacteristicWriteRequest(String address, int transId, - int offset, int length, boolean isPrep, boolean needRsp, - int handle, byte[] value) { - if (VDBG) Log.d(TAG, "onCharacteristicWriteRequest() - handle=" + handle); - - BluetoothDevice device = mAdapter.getRemoteDevice(address); - BluetoothGattCharacteristic characteristic = getCharacteristicByHandle(handle); - if (characteristic == null) { - Log.w(TAG, "onCharacteristicWriteRequest() no char for handle " + handle); - return; - } - - try { - mCallback.onCharacteristicWriteRequest(device, transId, characteristic, - isPrep, needRsp, offset, value); - } catch (Exception ex) { - Log.w(TAG, "Unhandled exception in callback", ex); - } - - } - - /** - * Remote client descriptor write request. - * @hide - */ - @Override - public void onDescriptorWriteRequest(String address, int transId, int offset, - int length, boolean isPrep, boolean needRsp, int handle, byte[] value) { - if (VDBG) Log.d(TAG, "onDescriptorWriteRequest() - handle=" + handle); - - BluetoothDevice device = mAdapter.getRemoteDevice(address); - BluetoothGattDescriptor descriptor = getDescriptorByHandle(handle); - if (descriptor == null) { - Log.w(TAG, "onDescriptorWriteRequest() no desc for handle " + handle); - return; - } - - try { - mCallback.onDescriptorWriteRequest(device, transId, descriptor, - isPrep, needRsp, offset, value); - } catch (Exception ex) { - Log.w(TAG, "Unhandled exception in callback", ex); - } - } - - /** - * Execute pending writes. - * @hide - */ - @Override - public void onExecuteWrite(String address, int transId, - boolean execWrite) { - if (DBG) { - Log.d(TAG, "onExecuteWrite() - " - + "device=" + address + ", transId=" + transId - + "execWrite=" + execWrite); - } - - BluetoothDevice device = mAdapter.getRemoteDevice(address); - if (device == null) return; - - try { - mCallback.onExecuteWrite(device, transId, execWrite); - } catch (Exception ex) { - Log.w(TAG, "Unhandled exception in callback", ex); - } - } - - /** - * A notification/indication has been sent. - * @hide - */ - @Override - public void onNotificationSent(String address, int status) { - if (VDBG) { - Log.d(TAG, "onNotificationSent() - " - + "device=" + address + ", status=" + status); - } - - BluetoothDevice device = mAdapter.getRemoteDevice(address); - if (device == null) return; - - try { - mCallback.onNotificationSent(device, status); - } catch (Exception ex) { - Log.w(TAG, "Unhandled exception: " + ex); - } - } - - /** - * The MTU for a connection has changed - * @hide - */ - @Override - public void onMtuChanged(String address, int mtu) { - if (DBG) { - Log.d(TAG, "onMtuChanged() - " - + "device=" + address + ", mtu=" + mtu); - } - - BluetoothDevice device = mAdapter.getRemoteDevice(address); - if (device == null) return; - - try { - mCallback.onMtuChanged(device, mtu); - } catch (Exception ex) { - Log.w(TAG, "Unhandled exception: " + ex); - } - } - - /** - * The PHY for a connection was updated - * @hide - */ - @Override - public void onPhyUpdate(String address, int txPhy, int rxPhy, int status) { - if (DBG) { - Log.d(TAG, - "onPhyUpdate() - " + "device=" + address + ", txPHy=" + txPhy - + ", rxPHy=" + rxPhy); - } - - BluetoothDevice device = mAdapter.getRemoteDevice(address); - if (device == null) return; - - try { - mCallback.onPhyUpdate(device, txPhy, rxPhy, status); - } catch (Exception ex) { - Log.w(TAG, "Unhandled exception: " + ex); - } - } - - /** - * The PHY for a connection was read - * @hide - */ - @Override - public void onPhyRead(String address, int txPhy, int rxPhy, int status) { - if (DBG) { - Log.d(TAG, - "onPhyUpdate() - " + "device=" + address + ", txPHy=" + txPhy - + ", rxPHy=" + rxPhy); - } - - BluetoothDevice device = mAdapter.getRemoteDevice(address); - if (device == null) return; - - try { - mCallback.onPhyRead(device, txPhy, rxPhy, status); - } catch (Exception ex) { - Log.w(TAG, "Unhandled exception: " + ex); - } - } - - /** - * Callback invoked when the given connection is updated - * @hide - */ - @Override - public void onConnectionUpdated(String address, int interval, int latency, - int timeout, int status) { - if (DBG) { - Log.d(TAG, "onConnectionUpdated() - Device=" + address - + " interval=" + interval + " latency=" + latency - + " timeout=" + timeout + " status=" + status); - } - BluetoothDevice device = mAdapter.getRemoteDevice(address); - if (device == null) return; - - try { - mCallback.onConnectionUpdated(device, interval, latency, - timeout, status); - } catch (Exception ex) { - Log.w(TAG, "Unhandled exception: " + ex); - } - } - - }; - - /** - * Create a BluetoothGattServer proxy object. - */ - /* package */ BluetoothGattServer(IBluetoothGatt iGatt, int transport, - BluetoothAdapter adapter) { - mService = iGatt; - mAdapter = adapter; - mAttributionSource = adapter.getAttributionSource(); - mCallback = null; - mServerIf = 0; - mTransport = transport; - mServices = new ArrayList(); - } - - /** - * Returns a characteristic with given handle. - * - * @hide - */ - /*package*/ BluetoothGattCharacteristic getCharacteristicByHandle(int handle) { - for (BluetoothGattService svc : mServices) { - for (BluetoothGattCharacteristic charac : svc.getCharacteristics()) { - if (charac.getInstanceId() == handle) { - return charac; - } - } - } - return null; - } - - /** - * Returns a descriptor with given handle. - * - * @hide - */ - /*package*/ BluetoothGattDescriptor getDescriptorByHandle(int handle) { - for (BluetoothGattService svc : mServices) { - for (BluetoothGattCharacteristic charac : svc.getCharacteristics()) { - for (BluetoothGattDescriptor desc : charac.getDescriptors()) { - if (desc.getInstanceId() == handle) { - return desc; - } - } - } - } - return null; - } - - /** - * Close this GATT server instance. - * - * 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()"); - unregisterCallback(); - } - - /** - * Register an application callback to start using GattServer. - * - *

This is an asynchronous call. The callback is used to notify - * success or failure if the function returns true. - * - * @param callback GATT callback handler that will receive asynchronous callbacks. - * @return true, the callback will be called to notify success or failure, false on immediate - * error - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - /*package*/ boolean registerCallback(BluetoothGattServerCallback callback) { - return registerCallback(callback, false); - } - - /** - * Register an application callback to start using GattServer. - * - *

This is an asynchronous call. The callback is used to notify - * success or failure if the function returns true. - * - * @param callback GATT callback handler that will receive asynchronous callbacks. - * @param eatt_support indicates if server can use eatt - * @return true, the callback will be called to notify success or failure, false on immediate - * error - * @hide - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - /*package*/ boolean registerCallback(BluetoothGattServerCallback callback, - boolean eatt_support) { - if (DBG) Log.d(TAG, "registerCallback()"); - if (mService == null) { - Log.e(TAG, "GATT service not available"); - return false; - } - UUID uuid = UUID.randomUUID(); - if (DBG) Log.d(TAG, "registerCallback() - UUID=" + uuid); - - synchronized (mServerIfLock) { - if (mCallback != null) { - Log.e(TAG, "App can register callback only once"); - return false; - } - - mCallback = callback; - try { - mService.registerServer(new ParcelUuid(uuid), mBluetoothGattServerCallback, - eatt_support, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "", e); - mCallback = null; - return false; - } - - try { - mServerIfLock.wait(CALLBACK_REG_TIMEOUT); - } catch (InterruptedException e) { - Log.e(TAG, "" + e); - mCallback = null; - } - - if (mServerIf == 0) { - mCallback = null; - return false; - } else { - return true; - } - } - } - - /** - * Unregister the current application and callbacks. - */ - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - private void unregisterCallback() { - if (DBG) Log.d(TAG, "unregisterCallback() - mServerIf=" + mServerIf); - if (mService == null || mServerIf == 0) return; - - try { - mCallback = null; - mService.unregisterServer(mServerIf, mAttributionSource); - mServerIf = 0; - } catch (RemoteException e) { - Log.e(TAG, "", e); - } - } - - /** - * Returns a service by UUID, instance and type. - * - * @hide - */ - /*package*/ BluetoothGattService getService(UUID uuid, int instanceId, int type) { - for (BluetoothGattService svc : mServices) { - if (svc.getType() == type - && svc.getInstanceId() == instanceId - && svc.getUuid().equals(uuid)) { - return svc; - } - } - return null; - } - - /** - * Initiate a connection to a Bluetooth GATT capable device. - * - *

The connection may not be established right away, but will be - * completed when the remote device is available. A - * {@link BluetoothGattServerCallback#onConnectionStateChange} callback will be - * invoked when the connection state changes as a result of this function. - * - *

The autoConnect parameter determines whether to actively connect to - * the remote device, or rather passively scan and finalize the connection - * when the remote device is in range/available. Generally, the first ever - * connection to a device should be direct (autoConnect set to false) and - * subsequent connections to known devices should be invoked with the - * autoConnect parameter set to true. - * - * @param autoConnect Whether to directly connect to the remote device (false) or to - * automatically connect as soon as the remote device becomes available (true). - * @return true, if the connection attempt was initiated successfully - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public boolean connect(BluetoothDevice device, boolean autoConnect) { - if (DBG) { - Log.d(TAG, - "connect() - device: " + device.getAddress() + ", auto: " + autoConnect); - } - if (mService == null || mServerIf == 0) return false; - - try { - // autoConnect is inverse of "isDirect" - mService.serverConnect( - mServerIf, device.getAddress(), !autoConnect, mTransport, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "", e); - return false; - } - - return true; - } - - /** - * Disconnects an established connection, or cancels a connection attempt - * currently in progress. - * - * @param device Remote device - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public void cancelConnection(BluetoothDevice device) { - if (DBG) Log.d(TAG, "cancelConnection() - device: " + device.getAddress()); - if (mService == null || mServerIf == 0) return; - - try { - mService.serverDisconnect(mServerIf, device.getAddress(), mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "", e); - } - } - - /** - * Set the preferred connection PHY for this app. Please note that this is just a - * recommendation, whether the PHY change will happen depends on other applications peferences, - * local and remote controller capabilities. Controller can override these settings.

{@link - * BluetoothGattServerCallback#onPhyUpdate} will be triggered as a result of this call, even if - * no PHY change happens. It is also triggered when remote device updates the PHY. - * - * @param device The remote device to send this response to - * @param txPhy preferred transmitter PHY. Bitwise OR of any of {@link - * BluetoothDevice#PHY_LE_1M_MASK}, {@link BluetoothDevice#PHY_LE_2M_MASK}, and {@link - * BluetoothDevice#PHY_LE_CODED_MASK}. - * @param rxPhy preferred receiver PHY. Bitwise OR of any of {@link - * BluetoothDevice#PHY_LE_1M_MASK}, {@link BluetoothDevice#PHY_LE_2M_MASK}, and {@link - * BluetoothDevice#PHY_LE_CODED_MASK}. - * @param phyOptions preferred coding to use when transmitting on the LE Coded PHY. Can be one - * 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 { - mService.serverSetPreferredPhy(mServerIf, device.getAddress(), txPhy, rxPhy, - phyOptions, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "", e); - } - } - - /** - * Read the current transmitter PHY and receiver PHY of the connection. The values are returned - * in {@link BluetoothGattServerCallback#onPhyRead} - * - * @param device The remote device to send this response to - */ - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public void readPhy(BluetoothDevice device) { - try { - mService.serverReadPhy(mServerIf, device.getAddress(), mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "", e); - } - } - - /** - * Send a response to a read or write request to a remote device. - * - *

This function must be invoked in when a remote read/write request - * is received by one of these callback methods: - * - *

    - *
  • {@link BluetoothGattServerCallback#onCharacteristicReadRequest} - *
  • {@link BluetoothGattServerCallback#onCharacteristicWriteRequest} - *
  • {@link BluetoothGattServerCallback#onDescriptorReadRequest} - *
  • {@link BluetoothGattServerCallback#onDescriptorWriteRequest} - *
- * - * @param device The remote device to send this response to - * @param requestId The ID of the request that was received with the callback - * @param status The status of the request to be sent to the remote devices - * @param offset Value offset for partial read/write response - * @param value The value of the attribute that was read/written (optional) - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public boolean sendResponse(BluetoothDevice device, int requestId, - int status, int offset, byte[] value) { - if (VDBG) Log.d(TAG, "sendResponse() - device: " + device.getAddress()); - if (mService == null || mServerIf == 0) return false; - - try { - mService.sendResponse(mServerIf, device.getAddress(), requestId, - status, offset, value, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "", e); - return false; - } - return true; - } - - /** - * Send a notification or indication that a local characteristic has been - * updated. - * - *

A notification or indication is sent to the remote device to signal - * that the characteristic has been updated. This function should be invoked - * for every client that requests notifications/indications by writing - * to the "Client Configuration" descriptor for the given characteristic. - * - * @param device The remote device to receive the notification/indication - * @param characteristic The local characteristic that has been updated - * @param confirm true to request confirmation from the client (indication), false to send a - * notification - * @return true, if the notification has been triggered successfully - * @throws IllegalArgumentException - * - * @deprecated Use {@link BluetoothGattServer#notifyCharacteristicChanged(BluetoothDevice, - * BluetoothGattCharacteristic, boolean, byte[])} as this is not memory safe. - */ - @Deprecated - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public boolean notifyCharacteristicChanged(BluetoothDevice device, - BluetoothGattCharacteristic characteristic, boolean confirm) { - return notifyCharacteristicChanged(device, characteristic, confirm, - characteristic.getValue()) == BluetoothStatusCodes.SUCCESS; - } - - /** @hide */ - @Retention(RetentionPolicy.SOURCE) - @IntDef(value = { - BluetoothStatusCodes.SUCCESS, - BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION, - BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_PRIVILEGED_PERMISSION, - BluetoothStatusCodes.ERROR_DEVICE_NOT_CONNECTED, - BluetoothStatusCodes.ERROR_PROFILE_SERVICE_NOT_BOUND, - BluetoothStatusCodes.ERROR_GATT_WRITE_NOT_ALLOWED, - BluetoothStatusCodes.ERROR_GATT_WRITE_REQUEST_BUSY, - BluetoothStatusCodes.ERROR_UNKNOWN - }) - public @interface NotifyCharacteristicReturnValues{} - - /** - * Send a notification or indication that a local characteristic has been - * updated. - * - *

A notification or indication is sent to the remote device to signal - * that the characteristic has been updated. This function should be invoked - * for every client that requests notifications/indications by writing - * to the "Client Configuration" descriptor for the given characteristic. - * - * @param device the remote device to receive the notification/indication - * @param characteristic the local characteristic that has been updated - * @param confirm {@code true} to request confirmation from the client (indication) or - * {@code false} to send a notification - * @param value the characteristic value - * @return whether the notification has been triggered successfully - * @throws IllegalArgumentException if the characteristic value or service is null - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - @NotifyCharacteristicReturnValues - public int notifyCharacteristicChanged(@NonNull BluetoothDevice device, - @NonNull BluetoothGattCharacteristic characteristic, boolean confirm, - @NonNull byte[] value) { - if (VDBG) Log.d(TAG, "notifyCharacteristicChanged() - device: " + device.getAddress()); - if (mService == null || mServerIf == 0) { - return BluetoothStatusCodes.ERROR_PROFILE_SERVICE_NOT_BOUND; - } - - if (characteristic == null) { - throw new IllegalArgumentException("characteristic must not be null"); - } - if (device == null) { - throw new IllegalArgumentException("device must not be null"); - } - BluetoothGattService service = characteristic.getService(); - if (service == null) { - throw new IllegalArgumentException("Characteristic must have a non-null service"); - } - if (value == null) { - throw new IllegalArgumentException("Characteristic value must not be null"); - } - - try { - return mService.sendNotification(mServerIf, device.getAddress(), - characteristic.getInstanceId(), confirm, - value, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "", e); - throw e.rethrowFromSystemServer(); - } - } - - /** - * Add a service to the list of services to be hosted. - * - *

Once a service has been addded to the list, the service and its - * included characteristics will be provided by the local device. - * - *

If the local device has already exposed services when this function - * is called, a service update notification will be sent to all clients. - * - *

The {@link BluetoothGattServerCallback#onServiceAdded} callback will indicate - * whether this service has been added successfully. Do not add another service - * before this callback. - * - * @param service Service to be added to the list of services provided by this device. - * @return true, if the request to add service has been initiated - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public boolean addService(BluetoothGattService service) { - if (DBG) Log.d(TAG, "addService() - service: " + service.getUuid()); - if (mService == null || mServerIf == 0) return false; - - mPendingService = service; - - try { - mService.addService(mServerIf, service, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "", e); - return false; - } - - return true; - } - - /** - * Removes a service from the list of services to be provided. - * - * @param service Service to be removed. - * @return true, if the service has been removed - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public boolean removeService(BluetoothGattService service) { - if (DBG) Log.d(TAG, "removeService() - service: " + service.getUuid()); - if (mService == null || mServerIf == 0) return false; - - BluetoothGattService intService = getService(service.getUuid(), - service.getInstanceId(), service.getType()); - if (intService == null) return false; - - try { - mService.removeService(mServerIf, service.getInstanceId(), mAttributionSource); - mServices.remove(intService); - } catch (RemoteException e) { - Log.e(TAG, "", e); - return false; - } - - return true; - } - - /** - * Remove all services from the list of provided services. - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public void clearServices() { - if (DBG) Log.d(TAG, "clearServices()"); - if (mService == null || mServerIf == 0) return; - - try { - mService.clearServices(mServerIf, mAttributionSource); - mServices.clear(); - } catch (RemoteException e) { - Log.e(TAG, "", e); - } - } - - /** - * Returns a list of GATT services offered by this device. - * - *

An application must call {@link #addService} to add a serice to the - * list of services offered by this device. - * - * @return List of services. Returns an empty list if no services have been added yet. - */ - @RequiresLegacyBluetoothPermission - @RequiresNoPermission - public List getServices() { - return mServices; - } - - /** - * Returns a {@link BluetoothGattService} from the list of services offered - * by this device. - * - *

If multiple instances of the same service (as identified by UUID) - * exist, the first instance of the service is returned. - * - * @param uuid UUID of the requested service - * @return BluetoothGattService if supported, or null if the requested service is not offered by - * this device. - */ - @RequiresLegacyBluetoothPermission - @RequiresNoPermission - public BluetoothGattService getService(UUID uuid) { - for (BluetoothGattService service : mServices) { - if (service.getUuid().equals(uuid)) { - return service; - } - } - - return null; - } - - - /** - * Not supported - please use {@link BluetoothManager#getConnectedDevices(int)} - * with {@link BluetoothProfile#GATT} as argument - * - * @throws UnsupportedOperationException - */ - @Override - @RequiresNoPermission - public int getConnectionState(BluetoothDevice device) { - throw new UnsupportedOperationException("Use BluetoothManager#getConnectionState instead."); - } - - /** - * Not supported - please use {@link BluetoothManager#getConnectedDevices(int)} - * with {@link BluetoothProfile#GATT} as argument - * - * @throws UnsupportedOperationException - */ - @Override - @RequiresNoPermission - public List getConnectedDevices() { - throw new UnsupportedOperationException( - "Use BluetoothManager#getConnectedDevices instead."); - } - - /** - * Not supported - please use - * {@link BluetoothManager#getDevicesMatchingConnectionStates(int, int[])} - * with {@link BluetoothProfile#GATT} as first argument - * - * @throws UnsupportedOperationException - */ - @Override - @RequiresNoPermission - public List getDevicesMatchingConnectionStates(int[] states) { - throw new UnsupportedOperationException( - "Use BluetoothManager#getDevicesMatchingConnectionStates instead."); - } -} diff --git a/core/java/android/bluetooth/BluetoothGattServerCallback.java b/core/java/android/bluetooth/BluetoothGattServerCallback.java deleted file mode 100644 index 0ead5f57e86cfd75cf7c6defa4ff7e3abc7a8c37..0000000000000000000000000000000000000000 --- a/core/java/android/bluetooth/BluetoothGattServerCallback.java +++ /dev/null @@ -1,202 +0,0 @@ -/* - * Copyright (C) 2017 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.bluetooth; - -/** - * This abstract class is used to implement {@link BluetoothGattServer} callbacks. - */ -public abstract class BluetoothGattServerCallback { - - /** - * Callback indicating when a remote device has been connected or disconnected. - * - * @param device Remote device that has been connected or disconnected. - * @param status Status of the connect or disconnect operation. - * @param newState Returns the new connection state. Can be one of {@link - * BluetoothProfile#STATE_DISCONNECTED} or {@link BluetoothProfile#STATE_CONNECTED} - */ - public void onConnectionStateChange(BluetoothDevice device, int status, - int newState) { - } - - /** - * Indicates whether a local service has been added successfully. - * - * @param status Returns {@link BluetoothGatt#GATT_SUCCESS} if the service was added - * successfully. - * @param service The service that has been added - */ - public void onServiceAdded(int status, BluetoothGattService service) { - } - - /** - * A remote client has requested to read a local characteristic. - * - *

An application must call {@link BluetoothGattServer#sendResponse} - * to complete the request. - * - * @param device The remote device that has requested the read operation - * @param requestId The Id of the request - * @param offset Offset into the value of the characteristic - * @param characteristic Characteristic to be read - */ - public void onCharacteristicReadRequest(BluetoothDevice device, int requestId, - int offset, BluetoothGattCharacteristic characteristic) { - } - - /** - * A remote client has requested to write to a local characteristic. - * - *

An application must call {@link BluetoothGattServer#sendResponse} - * to complete the request. - * - * @param device The remote device that has requested the write operation - * @param requestId The Id of the request - * @param characteristic Characteristic to be written to. - * @param preparedWrite true, if this write operation should be queued for later execution. - * @param responseNeeded true, if the remote device requires a response - * @param offset The offset given for the value - * @param value The value the client wants to assign to the characteristic - */ - public void onCharacteristicWriteRequest(BluetoothDevice device, int requestId, - BluetoothGattCharacteristic characteristic, - boolean preparedWrite, boolean responseNeeded, - int offset, byte[] value) { - } - - /** - * A remote client has requested to read a local descriptor. - * - *

An application must call {@link BluetoothGattServer#sendResponse} - * to complete the request. - * - * @param device The remote device that has requested the read operation - * @param requestId The Id of the request - * @param offset Offset into the value of the characteristic - * @param descriptor Descriptor to be read - */ - public void onDescriptorReadRequest(BluetoothDevice device, int requestId, - int offset, BluetoothGattDescriptor descriptor) { - } - - /** - * A remote client has requested to write to a local descriptor. - * - *

An application must call {@link BluetoothGattServer#sendResponse} - * to complete the request. - * - * @param device The remote device that has requested the write operation - * @param requestId The Id of the request - * @param descriptor Descriptor to be written to. - * @param preparedWrite true, if this write operation should be queued for later execution. - * @param responseNeeded true, if the remote device requires a response - * @param offset The offset given for the value - * @param value The value the client wants to assign to the descriptor - */ - public void onDescriptorWriteRequest(BluetoothDevice device, int requestId, - BluetoothGattDescriptor descriptor, - boolean preparedWrite, boolean responseNeeded, - int offset, byte[] value) { - } - - /** - * Execute all pending write operations for this device. - * - *

An application must call {@link BluetoothGattServer#sendResponse} - * to complete the request. - * - * @param device The remote device that has requested the write operations - * @param requestId The Id of the request - * @param execute Whether the pending writes should be executed (true) or cancelled (false) - */ - public void onExecuteWrite(BluetoothDevice device, int requestId, boolean execute) { - } - - /** - * Callback invoked when a notification or indication has been sent to - * a remote device. - * - *

When multiple notifications are to be sent, an application must - * wait for this callback to be received before sending additional - * notifications. - * - * @param device The remote device the notification has been sent to - * @param status {@link BluetoothGatt#GATT_SUCCESS} if the operation was successful - */ - public void onNotificationSent(BluetoothDevice device, int status) { - } - - /** - * Callback indicating the MTU for a given device connection has changed. - * - *

This callback will be invoked if a remote client has requested to change - * the MTU for a given connection. - * - * @param device The remote device that requested the MTU change - * @param mtu The new MTU size - */ - public void onMtuChanged(BluetoothDevice device, int mtu) { - } - - /** - * Callback triggered as result of {@link BluetoothGattServer#setPreferredPhy}, or as a result - * of remote device changing the PHY. - * - * @param device The remote device - * @param txPhy the transmitter PHY in use. One of {@link BluetoothDevice#PHY_LE_1M}, {@link - * BluetoothDevice#PHY_LE_2M}, and {@link BluetoothDevice#PHY_LE_CODED} - * @param rxPhy the receiver PHY in use. One of {@link BluetoothDevice#PHY_LE_1M}, {@link - * BluetoothDevice#PHY_LE_2M}, and {@link BluetoothDevice#PHY_LE_CODED} - * @param status Status of the PHY update operation. {@link BluetoothGatt#GATT_SUCCESS} if the - * operation succeeds. - */ - public void onPhyUpdate(BluetoothDevice device, int txPhy, int rxPhy, int status) { - } - - /** - * Callback triggered as result of {@link BluetoothGattServer#readPhy} - * - * @param device The remote device that requested the PHY read - * @param txPhy the transmitter PHY in use. One of {@link BluetoothDevice#PHY_LE_1M}, {@link - * BluetoothDevice#PHY_LE_2M}, and {@link BluetoothDevice#PHY_LE_CODED} - * @param rxPhy the receiver PHY in use. One of {@link BluetoothDevice#PHY_LE_1M}, {@link - * BluetoothDevice#PHY_LE_2M}, and {@link BluetoothDevice#PHY_LE_CODED} - * @param status Status of the PHY read operation. {@link BluetoothGatt#GATT_SUCCESS} if the - * operation succeeds. - */ - public void onPhyRead(BluetoothDevice device, int txPhy, int rxPhy, int status) { - } - - /** - * Callback indicating the connection parameters were updated. - * - * @param device The remote device involved - * @param interval Connection interval used on this connection, 1.25ms unit. Valid range is from - * 6 (7.5ms) to 3200 (4000ms). - * @param latency Worker latency for the connection in number of connection events. Valid range - * is from 0 to 499 - * @param timeout Supervision timeout for this connection, in 10ms unit. Valid range is from 10 - * (0.1s) to 3200 (32s) - * @param status {@link BluetoothGatt#GATT_SUCCESS} if the connection has been updated - * successfully - * @hide - */ - public void onConnectionUpdated(BluetoothDevice device, int interval, int latency, int timeout, - int status) { - } - -} diff --git a/core/java/android/bluetooth/BluetoothGattService.java b/core/java/android/bluetooth/BluetoothGattService.java deleted file mode 100644 index f64d09fc30d93115e468d18f09ca99ad7eba85e6..0000000000000000000000000000000000000000 --- a/core/java/android/bluetooth/BluetoothGattService.java +++ /dev/null @@ -1,395 +0,0 @@ -/* - * Copyright (C) 2013 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.bluetooth; - -import android.annotation.RequiresPermission; -import android.bluetooth.annotations.RequiresBluetoothConnectPermission; -import android.bluetooth.annotations.RequiresLegacyBluetoothPermission; -import android.compat.annotation.UnsupportedAppUsage; -import android.os.Build; -import android.os.Parcel; -import android.os.ParcelUuid; -import android.os.Parcelable; - -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; - -/** - * Represents a Bluetooth GATT Service - * - *

Gatt Service contains a collection of {@link BluetoothGattCharacteristic}, - * as well as referenced services. - */ -public class BluetoothGattService implements Parcelable { - - /** - * Primary service - */ - public static final int SERVICE_TYPE_PRIMARY = 0; - - /** - * Secondary service (included by primary services) - */ - public static final int SERVICE_TYPE_SECONDARY = 1; - - - /** - * The remote device this service is associated with. - * This applies to client applications only. - * - * @hide - */ - @UnsupportedAppUsage - protected BluetoothDevice mDevice; - - /** - * The UUID of this service. - * - * @hide - */ - protected UUID mUuid; - - /** - * Instance ID for this service. - * - * @hide - */ - protected int mInstanceId; - - /** - * Handle counter override (for conformance testing). - * - * @hide - */ - protected int mHandles = 0; - - /** - * Service type (Primary/Secondary). - * - * @hide - */ - protected int mServiceType; - - /** - * List of characteristics included in this service. - */ - protected List mCharacteristics; - - /** - * List of included services for this service. - */ - protected List mIncludedServices; - - /** - * Whether the service uuid should be advertised. - */ - private boolean mAdvertisePreferred; - - /** - * Create a new BluetoothGattService. - * - * @param uuid The UUID for this service - * @param serviceType The type of this service, - * {@link BluetoothGattService#SERVICE_TYPE_PRIMARY} - * or {@link BluetoothGattService#SERVICE_TYPE_SECONDARY} - */ - public BluetoothGattService(UUID uuid, int serviceType) { - mDevice = null; - mUuid = uuid; - mInstanceId = 0; - mServiceType = serviceType; - mCharacteristics = new ArrayList(); - mIncludedServices = new ArrayList(); - } - - /** - * Create a new BluetoothGattService - * - * @hide - */ - /*package*/ BluetoothGattService(BluetoothDevice device, UUID uuid, - int instanceId, int serviceType) { - mDevice = device; - mUuid = uuid; - mInstanceId = instanceId; - mServiceType = serviceType; - mCharacteristics = new ArrayList(); - mIncludedServices = new ArrayList(); - } - - /** - * Create a new BluetoothGattService - * - * @hide - */ - public BluetoothGattService(UUID uuid, int instanceId, int serviceType) { - mDevice = null; - mUuid = uuid; - mInstanceId = instanceId; - mServiceType = serviceType; - mCharacteristics = new ArrayList(); - mIncludedServices = new ArrayList(); - } - - /** - * @hide - */ - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel out, int flags) { - out.writeParcelable(new ParcelUuid(mUuid), 0); - out.writeInt(mInstanceId); - out.writeInt(mServiceType); - out.writeTypedList(mCharacteristics); - - ArrayList includedServices = - new ArrayList(mIncludedServices.size()); - for (BluetoothGattService s : mIncludedServices) { - includedServices.add(new BluetoothGattIncludedService(s.getUuid(), - s.getInstanceId(), s.getType())); - } - out.writeTypedList(includedServices); - } - - public static final @android.annotation.NonNull Parcelable.Creator CREATOR = - new Parcelable.Creator() { - public BluetoothGattService createFromParcel(Parcel in) { - return new BluetoothGattService(in); - } - - public BluetoothGattService[] newArray(int size) { - return new BluetoothGattService[size]; - } - }; - - private BluetoothGattService(Parcel in) { - mUuid = ((ParcelUuid) in.readParcelable(null)).getUuid(); - mInstanceId = in.readInt(); - mServiceType = in.readInt(); - - mCharacteristics = new ArrayList(); - - ArrayList chrcs = - in.createTypedArrayList(BluetoothGattCharacteristic.CREATOR); - if (chrcs != null) { - for (BluetoothGattCharacteristic chrc : chrcs) { - chrc.setService(this); - mCharacteristics.add(chrc); - } - } - - mIncludedServices = new ArrayList(); - - ArrayList inclSvcs = - in.createTypedArrayList(BluetoothGattIncludedService.CREATOR); - if (chrcs != null) { - for (BluetoothGattIncludedService isvc : inclSvcs) { - mIncludedServices.add(new BluetoothGattService(null, isvc.getUuid(), - isvc.getInstanceId(), isvc.getType())); - } - } - } - - /** - * Returns the device associated with this service. - * - * @hide - */ - /*package*/ BluetoothDevice getDevice() { - return mDevice; - } - - /** - * Returns the device associated with this service. - * - * @hide - */ - /*package*/ void setDevice(BluetoothDevice device) { - mDevice = device; - } - - /** - * Add an included service to this service. - * - * @param service The service to be added - * @return true, if the included service was added to the service - */ - @RequiresLegacyBluetoothPermission - public boolean addService(BluetoothGattService service) { - mIncludedServices.add(service); - return true; - } - - /** - * Add a characteristic to this service. - * - * @param characteristic The characteristics to be added - * @return true, if the characteristic was added to the service - */ - @RequiresLegacyBluetoothPermission - public boolean addCharacteristic(BluetoothGattCharacteristic characteristic) { - mCharacteristics.add(characteristic); - characteristic.setService(this); - return true; - } - - /** - * Get characteristic by UUID and instanceId. - * - * @hide - */ - /*package*/ BluetoothGattCharacteristic getCharacteristic(UUID uuid, int instanceId) { - for (BluetoothGattCharacteristic characteristic : mCharacteristics) { - if (uuid.equals(characteristic.getUuid()) - && characteristic.getInstanceId() == instanceId) { - return characteristic; - } - } - return null; - } - - /** - * Force the instance ID. - * - * @hide - */ - @UnsupportedAppUsage - public void setInstanceId(int instanceId) { - mInstanceId = instanceId; - } - - /** - * Get the handle count override (conformance testing. - * - * @hide - */ - /*package*/ int getHandles() { - return mHandles; - } - - /** - * Force the number of handles to reserve for this service. - * This is needed for conformance testing only. - * - * @hide - */ - public void setHandles(int handles) { - mHandles = handles; - } - - /** - * Add an included service to the internal map. - * - * @hide - */ - public void addIncludedService(BluetoothGattService includedService) { - mIncludedServices.add(includedService); - } - - /** - * Returns the UUID of this service - * - * @return UUID of this service - */ - public UUID getUuid() { - return mUuid; - } - - /** - * Returns the instance ID for this service - * - *

If a remote device offers multiple services with the same UUID - * (ex. multiple battery services for different batteries), the instance - * ID is used to distuinguish services. - * - * @return Instance ID of this service - */ - public int getInstanceId() { - return mInstanceId; - } - - /** - * Get the type of this service (primary/secondary) - */ - public int getType() { - return mServiceType; - } - - /** - * Get the list of included GATT services for this service. - * - * @return List of included services or empty list if no included services were discovered. - */ - public List getIncludedServices() { - return mIncludedServices; - } - - /** - * Returns a list of characteristics included in this service. - * - * @return Characteristics included in this service - */ - public List getCharacteristics() { - return mCharacteristics; - } - - /** - * Returns a characteristic with a given UUID out of the list of - * characteristics offered by this service. - * - *

This is a convenience function to allow access to a given characteristic - * without enumerating over the list returned by {@link #getCharacteristics} - * manually. - * - *

If a remote service offers multiple characteristics with the same - * UUID, the first instance of a characteristic with the given UUID - * is returned. - * - * @return GATT characteristic object or null if no characteristic with the given UUID was - * found. - */ - public BluetoothGattCharacteristic getCharacteristic(UUID uuid) { - for (BluetoothGattCharacteristic characteristic : mCharacteristics) { - if (uuid.equals(characteristic.getUuid())) { - return characteristic; - } - } - return null; - } - - /** - * Returns whether the uuid of the service should be advertised. - * - * @hide - */ - public boolean isAdvertisePreferred() { - return mAdvertisePreferred; - } - - /** - * Set whether the service uuid should be advertised. - * - * @hide - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public void setAdvertisePreferred(boolean advertisePreferred) { - mAdvertisePreferred = advertisePreferred; - } -} diff --git a/core/java/android/bluetooth/BluetoothHeadset.java b/core/java/android/bluetooth/BluetoothHeadset.java deleted file mode 100644 index 1b141c9afaca2458958046399bda463b81798b5b..0000000000000000000000000000000000000000 --- a/core/java/android/bluetooth/BluetoothHeadset.java +++ /dev/null @@ -1,1505 +0,0 @@ -/* - * 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.bluetooth; - -import static android.bluetooth.BluetoothUtils.getSyncTimeout; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.annotation.RequiresPermission; -import android.annotation.SdkConstant; -import android.annotation.SdkConstant.SdkConstantType; -import android.annotation.SuppressLint; -import android.annotation.SystemApi; -import android.bluetooth.annotations.RequiresBluetoothConnectPermission; -import android.bluetooth.annotations.RequiresLegacyBluetoothAdminPermission; -import android.bluetooth.annotations.RequiresLegacyBluetoothPermission; -import android.compat.annotation.UnsupportedAppUsage; -import android.content.AttributionSource; -import android.content.ComponentName; -import android.content.Context; -import android.content.pm.PackageManager; -import android.os.Build; -import android.os.Handler; -import android.os.IBinder; -import android.os.Looper; -import android.os.Message; -import android.os.RemoteException; -import android.util.CloseGuard; -import android.util.Log; - -import com.android.modules.utils.SynchronousResultReceiver; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.TimeoutException; - -/** - * Public API for controlling the Bluetooth Headset Service. This includes both - * Bluetooth Headset and Handsfree (v1.5) profiles. - * - *

BluetoothHeadset is a proxy object for controlling the Bluetooth Headset - * Service via IPC. - * - *

Use {@link BluetoothAdapter#getProfileProxy} to get - * the BluetoothHeadset proxy object. Use - * {@link BluetoothAdapter#closeProfileProxy} to close the service connection. - * - *

Android only supports one connected Bluetooth Headset at a time. - * Each method is protected with its appropriate permission. - */ -public final class BluetoothHeadset implements BluetoothProfile { - private static final String TAG = "BluetoothHeadset"; - private static final boolean DBG = true; - private static final boolean VDBG = false; - - /** - * Intent used to broadcast the change in connection state of the Headset - * profile. - * - *

This intent will have 3 extras: - *

    - *
  • {@link #EXTRA_STATE} - The current state of the profile.
  • - *
  • {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile.
  • - *
  • {@link BluetoothDevice#EXTRA_DEVICE} - The remote device.
  • - *
- *

{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of - * {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING}, - * {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}. - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - public static final String ACTION_CONNECTION_STATE_CHANGED = - "android.bluetooth.headset.profile.action.CONNECTION_STATE_CHANGED"; - - /** - * Intent used to broadcast the change in the Audio Connection state of the - * HFP profile. - * - *

This intent will have 3 extras: - *

    - *
  • {@link #EXTRA_STATE} - The current state of the profile.
  • - *
  • {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile.
  • - *
  • {@link BluetoothDevice#EXTRA_DEVICE} - The remote device.
  • - *
- *

{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of - * {@link #STATE_AUDIO_CONNECTED}, {@link #STATE_AUDIO_DISCONNECTED}, - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - public static final String ACTION_AUDIO_STATE_CHANGED = - "android.bluetooth.headset.profile.action.AUDIO_STATE_CHANGED"; - - /** - * Intent used to broadcast the selection of a connected device as active. - * - *

This intent will have one extra: - *

    - *
  • {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. It can - * be null if no device is active.
  • - *
- * - * @hide - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - @UnsupportedAppUsage(trackingBug = 171933273) - public static final String ACTION_ACTIVE_DEVICE_CHANGED = - "android.bluetooth.headset.profile.action.ACTIVE_DEVICE_CHANGED"; - - /** - * Intent used to broadcast that the headset has posted a - * vendor-specific event. - * - *

This intent will have 4 extras and 1 category. - *

    - *
  • {@link BluetoothDevice#EXTRA_DEVICE} - The remote Bluetooth Device - *
  • - *
  • {@link #EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_CMD} - The vendor - * specific command
  • - *
  • {@link #EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_CMD_TYPE} - The AT - * command type which can be one of {@link #AT_CMD_TYPE_READ}, - * {@link #AT_CMD_TYPE_TEST}, or {@link #AT_CMD_TYPE_SET}, - * {@link #AT_CMD_TYPE_BASIC},{@link #AT_CMD_TYPE_ACTION}.
  • - *
  • {@link #EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_ARGS} - Command - * arguments.
  • - *
- * - *

The category is the Company ID of the vendor defining the - * vendor-specific command. {@link BluetoothAssignedNumbers} - * - * For example, for Plantronics specific events - * Category will be {@link #VENDOR_SPECIFIC_HEADSET_EVENT_COMPANY_ID_CATEGORY}.55 - * - *

For example, an AT+XEVENT=foo,3 will get translated into - *

    - *
  • EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_CMD = +XEVENT
  • - *
  • EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_CMD_TYPE = AT_CMD_TYPE_SET
  • - *
  • EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_ARGS = foo, 3
  • - *
- */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - public static final String ACTION_VENDOR_SPECIFIC_HEADSET_EVENT = - "android.bluetooth.headset.action.VENDOR_SPECIFIC_HEADSET_EVENT"; - - /** - * A String extra field in {@link #ACTION_VENDOR_SPECIFIC_HEADSET_EVENT} - * intents that contains the name of the vendor-specific command. - */ - public static final String EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_CMD = - "android.bluetooth.headset.extra.VENDOR_SPECIFIC_HEADSET_EVENT_CMD"; - - /** - * An int extra field in {@link #ACTION_VENDOR_SPECIFIC_HEADSET_EVENT} - * intents that contains the AT command type of the vendor-specific command. - */ - public static final String EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_CMD_TYPE = - "android.bluetooth.headset.extra.VENDOR_SPECIFIC_HEADSET_EVENT_CMD_TYPE"; - - /** - * AT command type READ used with - * {@link #EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_CMD_TYPE} - * For example, AT+VGM?. There are no arguments for this command type. - */ - public static final int AT_CMD_TYPE_READ = 0; - - /** - * AT command type TEST used with - * {@link #EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_CMD_TYPE} - * For example, AT+VGM=?. There are no arguments for this command type. - */ - public static final int AT_CMD_TYPE_TEST = 1; - - /** - * AT command type SET used with - * {@link #EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_CMD_TYPE} - * For example, AT+VGM=. - */ - public static final int AT_CMD_TYPE_SET = 2; - - /** - * AT command type BASIC used with - * {@link #EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_CMD_TYPE} - * For example, ATD. Single character commands and everything following the - * character are arguments. - */ - public static final int AT_CMD_TYPE_BASIC = 3; - - /** - * AT command type ACTION used with - * {@link #EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_CMD_TYPE} - * For example, AT+CHUP. There are no arguments for action commands. - */ - public static final int AT_CMD_TYPE_ACTION = 4; - - /** - * A Parcelable String array extra field in - * {@link #ACTION_VENDOR_SPECIFIC_HEADSET_EVENT} intents that contains - * the arguments to the vendor-specific command. - */ - public static final String EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_ARGS = - "android.bluetooth.headset.extra.VENDOR_SPECIFIC_HEADSET_EVENT_ARGS"; - - /** - * The intent category to be used with {@link #ACTION_VENDOR_SPECIFIC_HEADSET_EVENT} - * for the companyId - */ - public static final String VENDOR_SPECIFIC_HEADSET_EVENT_COMPANY_ID_CATEGORY = - "android.bluetooth.headset.intent.category.companyid"; - - /** - * A vendor-specific command for unsolicited result code. - */ - public static final String VENDOR_RESULT_CODE_COMMAND_ANDROID = "+ANDROID"; - - /** - * A vendor-specific AT command - * - * @hide - */ - public static final String VENDOR_SPECIFIC_HEADSET_EVENT_XAPL = "+XAPL"; - - /** - * A vendor-specific AT command - * - * @hide - */ - public static final String VENDOR_SPECIFIC_HEADSET_EVENT_IPHONEACCEV = "+IPHONEACCEV"; - - /** - * Battery level indicator associated with - * {@link #VENDOR_SPECIFIC_HEADSET_EVENT_IPHONEACCEV} - * - * @hide - */ - public static final int VENDOR_SPECIFIC_HEADSET_EVENT_IPHONEACCEV_BATTERY_LEVEL = 1; - - /** - * A vendor-specific AT command - * - * @hide - */ - public static final String VENDOR_SPECIFIC_HEADSET_EVENT_XEVENT = "+XEVENT"; - - /** - * Battery level indicator associated with {@link #VENDOR_SPECIFIC_HEADSET_EVENT_XEVENT} - * - * @hide - */ - public static final String VENDOR_SPECIFIC_HEADSET_EVENT_XEVENT_BATTERY_LEVEL = "BATTERY"; - - /** - * Headset state when SCO audio is not connected. - * This state can be one of - * {@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} of - * {@link #ACTION_AUDIO_STATE_CHANGED} intent. - */ - public static final int STATE_AUDIO_DISCONNECTED = 10; - - /** - * Headset state when SCO audio is connecting. - * This state can be one of - * {@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} of - * {@link #ACTION_AUDIO_STATE_CHANGED} intent. - */ - public static final int STATE_AUDIO_CONNECTING = 11; - - /** - * Headset state when SCO audio is connected. - * This state can be one of - * {@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} of - * {@link #ACTION_AUDIO_STATE_CHANGED} intent. - */ - public static final int STATE_AUDIO_CONNECTED = 12; - - /** - * Intent used to broadcast the headset's indicator status - * - *

This intent will have 3 extras: - *

    - *
  • {@link #EXTRA_HF_INDICATORS_IND_ID} - The Assigned number of headset Indicator which - * is supported by the headset ( as indicated by AT+BIND command in the SLC - * sequence) or whose value is changed (indicated by AT+BIEV command)
  • - *
  • {@link #EXTRA_HF_INDICATORS_IND_VALUE} - Updated value of headset indicator.
  • - *
  • {@link BluetoothDevice#EXTRA_DEVICE} - Remote device.
  • - *
- *

{@link #EXTRA_HF_INDICATORS_IND_ID} is defined by Bluetooth SIG and each of the indicators - * are given an assigned number. Below shows the assigned number of Indicator added so far - * - Enhanced Safety - 1, Valid Values: 0 - Disabled, 1 - Enabled - * - Battery Level - 2, Valid Values: 0~100 - Remaining level of Battery - * - * @hide - */ - @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"; - - /** - * A int extra field in {@link #ACTION_HF_INDICATORS_VALUE_CHANGED} - * intents that contains the assigned number of the headset indicator as defined by - * Bluetooth SIG that is being sent. Value range is 0-65535 as defined in HFP 1.7 - * - * @hide - */ - public static final String EXTRA_HF_INDICATORS_IND_ID = - "android.bluetooth.headset.extra.HF_INDICATORS_IND_ID"; - - /** - * A int extra field in {@link #ACTION_HF_INDICATORS_VALUE_CHANGED} - * intents that contains the value of the Headset indicator that is being sent. - * - * @hide - */ - public static final String EXTRA_HF_INDICATORS_IND_VALUE = - "android.bluetooth.headset.extra.HF_INDICATORS_IND_VALUE"; - - private static final int MESSAGE_HEADSET_SERVICE_CONNECTED = 100; - private static final int MESSAGE_HEADSET_SERVICE_DISCONNECTED = 101; - - private final CloseGuard mCloseGuard = new CloseGuard(); - - private Context mContext; - private ServiceListener mServiceListener; - private volatile IBluetoothHeadset mService; - private final BluetoothAdapter mAdapter; - private final AttributionSource mAttributionSource; - - @SuppressLint("AndroidFrameworkBluetoothPermission") - private final IBluetoothStateChangeCallback mBluetoothStateChangeCallback = - new IBluetoothStateChangeCallback.Stub() { - public void onBluetoothStateChange(boolean up) { - if (DBG) Log.d(TAG, "onBluetoothStateChange: up=" + up); - if (!up) { - doUnbind(); - } else { - doBind(); - } - } - }; - - /** - * Create a BluetoothHeadset proxy object. - */ - /* package */ BluetoothHeadset(Context context, ServiceListener l, BluetoothAdapter adapter) { - mContext = context; - mServiceListener = l; - mAdapter = adapter; - mAttributionSource = adapter.getAttributionSource(); - - // Preserve legacy compatibility where apps were depending on - // registerStateChangeCallback() performing a permissions check which - // has been relaxed in modern platform versions - if (context.getApplicationInfo().targetSdkVersion <= Build.VERSION_CODES.R - && context.checkSelfPermission(android.Manifest.permission.BLUETOOTH) - != PackageManager.PERMISSION_GRANTED) { - throw new SecurityException("Need BLUETOOTH permission"); - } - - IBluetoothManager mgr = mAdapter.getBluetoothManager(); - if (mgr != null) { - try { - mgr.registerStateChangeCallback(mBluetoothStateChangeCallback); - } catch (RemoteException e) { - Log.e(TAG, "", e); - } - } - - doBind(); - mCloseGuard.open("close"); - } - - private boolean doBind() { - synchronized (mConnection) { - if (mService == null) { - if (VDBG) Log.d(TAG, "Binding service..."); - try { - return mAdapter.getBluetoothManager().bindBluetoothProfileService( - BluetoothProfile.HEADSET, mConnection); - } catch (RemoteException e) { - Log.e(TAG, "Unable to bind HeadsetService", e); - } - } - } - return false; - } - - private void doUnbind() { - synchronized (mConnection) { - if (mService != null) { - if (VDBG) Log.d(TAG, "Unbinding service..."); - try { - mAdapter.getBluetoothManager().unbindBluetoothProfileService( - BluetoothProfile.HEADSET, mConnection); - } catch (RemoteException e) { - Log.e(TAG, "Unable to unbind HeadsetService", e); - } finally { - mService = null; - } - } - } - } - - /** - * Close the connection to the backing service. - * Other public functions of BluetoothHeadset will return default error - * results once close() has been called. Multiple invocations of close() - * are ok. - */ - @UnsupportedAppUsage - /*package*/ void close() { - if (VDBG) log("close()"); - - IBluetoothManager mgr = mAdapter.getBluetoothManager(); - if (mgr != null) { - try { - mgr.unregisterStateChangeCallback(mBluetoothStateChangeCallback); - } catch (RemoteException re) { - Log.e(TAG, "", re); - } - } - mServiceListener = null; - doUnbind(); - mCloseGuard.close(); - } - - /** {@hide} */ - @Override - protected void finalize() throws Throwable { - mCloseGuard.warnIfOpen(); - close(); - } - - /** - * Initiate connection to a profile of the remote bluetooth device. - * - *

Currently, the system supports only 1 connection to the - * headset/handsfree profile. The API will automatically disconnect connected - * devices before connecting. - * - *

This API returns false in scenarios like the profile on the - * device is already connected or Bluetooth is not turned on. - * When this API returns true, it is guaranteed that - * connection state intent for the profile will be broadcasted with - * the state. Users can get the connection state of the profile - * from this intent. - * - * @param device Remote Bluetooth Device - * @return false on immediate error, true otherwise - * @hide - */ - @SystemApi - @RequiresLegacyBluetoothAdminPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.MODIFY_PHONE_STATE, - }) - public boolean connect(BluetoothDevice device) { - if (DBG) log("connect(" + device + ")"); - final IBluetoothHeadset service = mService; - final boolean defaultValue = false; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device)) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.connectWithAttribution(device, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Initiate disconnection from a profile - * - *

This API will return false in scenarios like the profile on the - * Bluetooth device is not in connected state etc. When this API returns, - * true, it is guaranteed that the connection state change - * intent will be broadcasted with the state. Users can get the - * disconnection state of the profile from this intent. - * - *

If the disconnection is initiated by a remote device, the state - * will transition from {@link #STATE_CONNECTED} to - * {@link #STATE_DISCONNECTED}. If the disconnect is initiated by the - * host (local) device the state will transition from - * {@link #STATE_CONNECTED} to state {@link #STATE_DISCONNECTING} to - * state {@link #STATE_DISCONNECTED}. The transition to - * {@link #STATE_DISCONNECTING} can be used to distinguish between the - * two scenarios. - * - * @param device Remote Bluetooth Device - * @return false on immediate error, true otherwise - * @hide - */ - @SystemApi - @RequiresLegacyBluetoothAdminPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public boolean disconnect(BluetoothDevice device) { - if (DBG) log("disconnect(" + device + ")"); - final IBluetoothHeadset service = mService; - final boolean defaultValue = false; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device)) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.disconnectWithAttribution(device, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * {@inheritDoc} - */ - @Override - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public List getConnectedDevices() { - if (VDBG) log("getConnectedDevices()"); - final IBluetoothHeadset service = mService; - final List defaultValue = new ArrayList(); - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled()) { - try { - final SynchronousResultReceiver> recv = - new SynchronousResultReceiver(); - service.getConnectedDevicesWithAttribution(mAttributionSource, recv); - return Attributable.setAttributionSource( - recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue), - mAttributionSource); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * {@inheritDoc} - */ - @Override - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public List getDevicesMatchingConnectionStates(int[] states) { - if (VDBG) log("getDevicesMatchingStates()"); - final IBluetoothHeadset service = mService; - final List defaultValue = new ArrayList(); - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled()) { - try { - final SynchronousResultReceiver> recv = - new SynchronousResultReceiver(); - service.getDevicesMatchingConnectionStates(states, mAttributionSource, recv); - return Attributable.setAttributionSource( - recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue), - mAttributionSource); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * {@inheritDoc} - */ - @Override - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public int getConnectionState(BluetoothDevice device) { - if (VDBG) log("getConnectionState(" + device + ")"); - final IBluetoothHeadset service = mService; - final int defaultValue = BluetoothProfile.STATE_DISCONNECTED; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device)) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.getConnectionStateWithAttribution(device, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Set priority of the profile - * - *

The device should already be paired. - * Priority can be one of {@link BluetoothProfile#PRIORITY_ON} or - * {@link BluetoothProfile#PRIORITY_OFF} - * - * @param device Paired bluetooth device - * @param priority - * @return true if priority is set, false on error - * @hide - * @deprecated Replaced with {@link #setConnectionPolicy(BluetoothDevice, int)} - * @removed - */ - @Deprecated - @SystemApi - @RequiresLegacyBluetoothAdminPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.MODIFY_PHONE_STATE, - }) - public boolean setPriority(BluetoothDevice device, int priority) { - if (DBG) log("setPriority(" + device + ", " + priority + ")"); - return setConnectionPolicy(device, BluetoothAdapter.priorityToConnectionPolicy(priority)); - } - - /** - * Set connection policy of the profile - * - *

The device should already be paired. - * Connection policy can be one of {@link #CONNECTION_POLICY_ALLOWED}, - * {@link #CONNECTION_POLICY_FORBIDDEN}, {@link #CONNECTION_POLICY_UNKNOWN} - * - * @param device Paired bluetooth device - * @param connectionPolicy is the connection policy to set to for this profile - * @return true if connectionPolicy is set, false on error - * @hide - */ - @SystemApi - @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - android.Manifest.permission.MODIFY_PHONE_STATE, - }) - public boolean setConnectionPolicy(@NonNull BluetoothDevice device, - @ConnectionPolicy int connectionPolicy) { - if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")"); - final IBluetoothHeadset service = mService; - final boolean defaultValue = false; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device) - && (connectionPolicy == BluetoothProfile.CONNECTION_POLICY_FORBIDDEN - || connectionPolicy == BluetoothProfile.CONNECTION_POLICY_ALLOWED)) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.setConnectionPolicy(device, connectionPolicy, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Get the priority of the profile. - * - *

The priority can be any of: - * {@link #PRIORITY_AUTO_CONNECT}, {@link #PRIORITY_OFF}, - * {@link #PRIORITY_ON}, {@link #PRIORITY_UNDEFINED} - * - * @param device Bluetooth device - * @return priority of the device - * @hide - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public int getPriority(BluetoothDevice device) { - if (VDBG) log("getPriority(" + device + ")"); - return BluetoothAdapter.connectionPolicyToPriority(getConnectionPolicy(device)); - } - - /** - * Get the connection policy of the profile. - * - *

The connection policy can be any of: - * {@link #CONNECTION_POLICY_ALLOWED}, {@link #CONNECTION_POLICY_FORBIDDEN}, - * {@link #CONNECTION_POLICY_UNKNOWN} - * - * @param device Bluetooth device - * @return connection policy of the device - * @hide - */ - @SystemApi - @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) - public @ConnectionPolicy int getConnectionPolicy(@NonNull BluetoothDevice device) { - if (VDBG) log("getConnectionPolicy(" + device + ")"); - final IBluetoothHeadset service = mService; - final int defaultValue = BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device)) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.getConnectionPolicy(device, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Checks whether the headset supports some form of noise reduction - * - * @param device Bluetooth device - * @return true if echo cancellation and/or noise reduction is supported, false otherwise - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public boolean isNoiseReductionSupported(@NonNull BluetoothDevice device) { - if (DBG) log("isNoiseReductionSupported()"); - final IBluetoothHeadset service = mService; - final boolean defaultValue = false; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device)) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.isNoiseReductionSupported(device, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Checks whether the headset supports voice recognition - * - * @param device Bluetooth device - * @return true if voice recognition is supported, false otherwise - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public boolean isVoiceRecognitionSupported(@NonNull BluetoothDevice device) { - if (DBG) log("isVoiceRecognitionSupported()"); - final IBluetoothHeadset service = mService; - final boolean defaultValue = false; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device)) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.isVoiceRecognitionSupported(device, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Start Bluetooth voice recognition. This methods sends the voice - * recognition AT command to the headset and establishes the - * audio connection. - * - *

Users can listen to {@link #ACTION_AUDIO_STATE_CHANGED}. - * If this function returns true, this intent will be broadcasted with - * {@link #EXTRA_STATE} set to {@link #STATE_AUDIO_CONNECTING}. - * - *

{@link #EXTRA_STATE} will transition from - * {@link #STATE_AUDIO_CONNECTING} to {@link #STATE_AUDIO_CONNECTED} when - * audio connection is established and to {@link #STATE_AUDIO_DISCONNECTED} - * in case of failure to establish the audio connection. - * - * @param device Bluetooth headset - * @return false if there is no headset connected, or the connected headset doesn't support - * voice recognition, or voice recognition is already started, or audio channel is occupied, - * or on error, true otherwise - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.MODIFY_PHONE_STATE, - }) - public boolean startVoiceRecognition(BluetoothDevice device) { - if (DBG) log("startVoiceRecognition()"); - final IBluetoothHeadset service = mService; - final boolean defaultValue = false; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device)) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.startVoiceRecognition(device, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Stop Bluetooth Voice Recognition mode, and shut down the - * Bluetooth audio path. - * - *

Users can listen to {@link #ACTION_AUDIO_STATE_CHANGED}. - * If this function returns true, this intent will be broadcasted with - * {@link #EXTRA_STATE} set to {@link #STATE_AUDIO_DISCONNECTED}. - * - * @param device Bluetooth headset - * @return false if there is no headset connected, or voice recognition has not started, - * or voice recognition has ended on this headset, or on error, true otherwise - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public boolean stopVoiceRecognition(BluetoothDevice device) { - if (DBG) log("stopVoiceRecognition()"); - final IBluetoothHeadset service = mService; - final boolean defaultValue = false; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device)) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.stopVoiceRecognition(device, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Check if Bluetooth SCO audio is connected. - * - * @param device Bluetooth headset - * @return true if SCO is connected, false otherwise or on error - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public boolean isAudioConnected(BluetoothDevice device) { - if (VDBG) log("isAudioConnected()"); - final IBluetoothHeadset service = mService; - final boolean defaultValue = false; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device)) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.isAudioConnected(device, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Indicates if current platform supports voice dialing over bluetooth SCO. - * - * @return true if voice dialing over bluetooth is supported, false otherwise. - * @hide - */ - public static boolean isBluetoothVoiceDialingEnabled(Context context) { - return context.getResources().getBoolean( - com.android.internal.R.bool.config_bluetooth_sco_off_call); - } - - /** - * Get the current audio state of the Headset. - * Note: This is an internal function and shouldn't be exposed - * - * @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"); - final IBluetoothHeadset service = mService; - final int defaultValue = BluetoothHeadset.STATE_AUDIO_DISCONNECTED; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (!isDisabled()) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.getAudioState(device, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Sets whether audio routing is allowed. When set to {@code false}, the AG will not route any - * audio to the HF unless explicitly told to. - * This method should be used in cases where the SCO channel is shared between multiple profiles - * and must be delegated by a source knowledgeable - * Note: This is an internal function and shouldn't be exposed - * - * @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"); - final IBluetoothHeadset service = mService; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled()) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.setAudioRouteAllowed(allowed, mAttributionSource, recv); - recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(null); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - } - - /** - * Returns whether audio routing is allowed. see {@link #setAudioRouteAllowed(boolean)}. - * Note: This is an internal function and shouldn't be exposed - * - * @hide - */ - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public boolean getAudioRouteAllowed() { - if (VDBG) log("getAudioRouteAllowed"); - final IBluetoothHeadset service = mService; - final boolean defaultValue = false; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled()) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.getAudioRouteAllowed(mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Force SCO audio to be opened regardless any other restrictions - * - * @param forced Whether or not SCO audio connection should be forced: True to force SCO audio - * 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)); - final IBluetoothHeadset service = mService; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled()) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.setForceScoAudio(forced, mAttributionSource, recv); - recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(null); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - } - - /** - * Check if at least one headset's SCO audio is connected or connecting - * - * @return true if at least one device's SCO audio is connected or connecting, false otherwise - * or on error - * @hide - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public boolean isAudioOn() { - if (VDBG) log("isAudioOn()"); - final IBluetoothHeadset service = mService; - final boolean defaultValue = false; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled()) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.isAudioOn(mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Initiates a connection of headset audio to the current active device - * - *

Users can listen to {@link #ACTION_AUDIO_STATE_CHANGED}. - * If this function returns true, this intent will be broadcasted with - * {@link #EXTRA_STATE} set to {@link #STATE_AUDIO_CONNECTING}. - * - *

{@link #EXTRA_STATE} will transition from - * {@link #STATE_AUDIO_CONNECTING} to {@link #STATE_AUDIO_CONNECTED} when - * audio connection is established and to {@link #STATE_AUDIO_DISCONNECTED} - * in case of failure to establish the audio connection. - * - * Note that this intent will not be sent if {@link BluetoothHeadset#isAudioOn()} is true - * before calling this method - * - * @return false if there was some error such as there is no active headset - * @hide - */ - @UnsupportedAppUsage - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public boolean connectAudio() { - if (VDBG) log("connectAudio()"); - final IBluetoothHeadset service = mService; - final boolean defaultValue = false; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled()) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.connectAudio(mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Initiates a disconnection of HFP SCO audio. - * Tear down voice recognition or virtual voice call if any. - * - *

Users can listen to {@link #ACTION_AUDIO_STATE_CHANGED}. - * If this function returns true, this intent will be broadcasted with - * {@link #EXTRA_STATE} set to {@link #STATE_AUDIO_DISCONNECTED}. - * - * @return false if audio is not connected, or on error, true otherwise - * @hide - */ - @UnsupportedAppUsage - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public boolean disconnectAudio() { - if (VDBG) log("disconnectAudio()"); - final IBluetoothHeadset service = mService; - final boolean defaultValue = false; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled()) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.disconnectAudio(mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Initiates a SCO channel connection as a virtual voice call to the current active device - * Active handsfree device will be notified of incoming call and connected call. - * - *

Users can listen to {@link #ACTION_AUDIO_STATE_CHANGED}. - * If this function returns true, this intent will be broadcasted with - * {@link #EXTRA_STATE} set to {@link #STATE_AUDIO_CONNECTING}. - * - *

{@link #EXTRA_STATE} will transition from - * {@link #STATE_AUDIO_CONNECTING} to {@link #STATE_AUDIO_CONNECTED} when - * audio connection is established and to {@link #STATE_AUDIO_DISCONNECTED} - * in case of failure to establish the audio connection. - * - * @return true if successful, false if one of the following case applies - * - SCO audio is not idle (connecting or connected) - * - virtual call has already started - * - there is no active device - * - a Telecom managed call is going on - * - binder is dead or Bluetooth is disabled or other error - * @hide - */ - @SystemApi - @RequiresLegacyBluetoothAdminPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.MODIFY_PHONE_STATE, - }) - public boolean startScoUsingVirtualVoiceCall() { - if (DBG) log("startScoUsingVirtualVoiceCall()"); - final IBluetoothHeadset service = mService; - final boolean defaultValue = false; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled()) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.startScoUsingVirtualVoiceCall(mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Terminates an ongoing SCO connection and the associated virtual call. - * - *

Users can listen to {@link #ACTION_AUDIO_STATE_CHANGED}. - * If this function returns true, this intent will be broadcasted with - * {@link #EXTRA_STATE} set to {@link #STATE_AUDIO_DISCONNECTED}. - * - * @return true if successful, false if one of the following case applies - * - virtual voice call is not started or has ended - * - binder is dead or Bluetooth is disabled or other error - * @hide - */ - @SystemApi - @RequiresLegacyBluetoothAdminPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.MODIFY_PHONE_STATE, - }) - public boolean stopScoUsingVirtualVoiceCall() { - if (DBG) log("stopScoUsingVirtualVoiceCall()"); - final IBluetoothHeadset service = mService; - final boolean defaultValue = false; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled()) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.stopScoUsingVirtualVoiceCall(mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Notify Headset of phone state change. - * This is a backdoor for phone app to call BluetoothHeadset since - * there is currently not a good way to get precise call state change outside - * of phone app. - * - * @hide - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.MODIFY_PHONE_STATE, - }) - public void phoneStateChanged(int numActive, int numHeld, int callState, String number, - int type, String name) { - final IBluetoothHeadset service = mService; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled()) { - try { - service.phoneStateChanged(numActive, numHeld, callState, number, type, name, - mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - } - - /** - * Send Headset of CLCC response - * - * @hide - */ - @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.MODIFY_PHONE_STATE, - }) - public void clccResponse(int index, int direction, int status, int mode, boolean mpty, - String number, int type) { - final IBluetoothHeadset service = mService; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled()) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.clccResponse(index, direction, status, mode, mpty, number, type, - mAttributionSource, recv); - recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(null); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - } - - /** - * Sends a vendor-specific unsolicited result code to the headset. - * - *

The actual string to be sent is command + ": " + arg. For example, if {@code - * command} is {@link #VENDOR_RESULT_CODE_COMMAND_ANDROID} and {@code arg} is {@code "0"}, the - * string "+ANDROID: 0" will be sent. - * - *

Currently only {@link #VENDOR_RESULT_CODE_COMMAND_ANDROID} is allowed as {@code command}. - * - * @param device Bluetooth headset. - * @param command A vendor-specific command. - * @param arg The argument that will be attached to the command. - * @return {@code false} if there is no headset connected, or if the command is not an allowed - * vendor-specific unsolicited result code, or on error. {@code true} otherwise. - * @throws IllegalArgumentException if {@code command} is {@code null}. - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public boolean sendVendorSpecificResultCode(BluetoothDevice device, String command, - String arg) { - if (DBG) { - log("sendVendorSpecificResultCode()"); - } - if (command == null) { - throw new IllegalArgumentException("command is null"); - } - final IBluetoothHeadset service = mService; - final boolean defaultValue = false; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device)) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.sendVendorSpecificResultCode(device, command, arg, - mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Select a connected device as active. - * - * The active device selection is per profile. An active device's - * purpose is profile-specific. For example, in HFP and HSP profiles, - * it is the device used for phone call audio. If a remote device is not - * connected, it cannot be selected as active. - * - *

This API returns false in scenarios like the profile on the - * device is not connected or Bluetooth is not turned on. - * When this API returns true, it is guaranteed that the - * {@link #ACTION_ACTIVE_DEVICE_CHANGED} intent will be broadcasted - * with the active device. - * - * @param device Remote Bluetooth Device, could be null if phone call audio should not be - * streamed to a headset - * @return false on immediate error, true otherwise - * @hide - */ - @RequiresLegacyBluetoothAdminPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.MODIFY_PHONE_STATE, - }) - @UnsupportedAppUsage(trackingBug = 171933273) - public boolean setActiveDevice(@Nullable BluetoothDevice device) { - if (DBG) { - Log.d(TAG, "setActiveDevice: " + device); - } - final IBluetoothHeadset service = mService; - final boolean defaultValue = false; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && (device == null || isValidDevice(device))) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.setActiveDevice(device, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Get the connected device that is active. - * - * @return the connected device that is active or null if no device - * is active. - * @hide - */ - @UnsupportedAppUsage(trackingBug = 171933273) - @Nullable - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public BluetoothDevice getActiveDevice() { - if (VDBG) Log.d(TAG, "getActiveDevice"); - final IBluetoothHeadset service = mService; - final BluetoothDevice defaultValue = null; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled()) { - try { - final SynchronousResultReceiver recv = - new SynchronousResultReceiver(); - service.getActiveDevice(mAttributionSource, recv); - return Attributable.setAttributionSource( - recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue), - mAttributionSource); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Check if in-band ringing is currently enabled. In-band ringing could be disabled during an - * active connection. - * - * @return true if in-band ringing is enabled, false if in-band ringing is disabled - * @hide - */ - @SystemApi - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) - public boolean isInbandRingingEnabled() { - if (DBG) log("isInbandRingingEnabled()"); - final IBluetoothHeadset service = mService; - final boolean defaultValue = false; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled()) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.isInbandRingingEnabled(mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Check if in-band ringing is supported for this platform. - * - * @return true if in-band ringing is supported, false if in-band ringing is not supported - * @hide - */ - public static boolean isInbandRingingSupported(Context context) { - return context.getResources().getBoolean( - com.android.internal.R.bool.config_bluetooth_hfp_inband_ringing_support); - } - - @SuppressLint("AndroidFrameworkBluetoothPermission") - private final IBluetoothProfileServiceConnection mConnection = - new IBluetoothProfileServiceConnection.Stub() { - @Override - public void onServiceConnected(ComponentName className, IBinder service) { - if (DBG) Log.d(TAG, "Proxy object connected"); - mService = IBluetoothHeadset.Stub.asInterface(service); - mHandler.sendMessage(mHandler.obtainMessage( - MESSAGE_HEADSET_SERVICE_CONNECTED)); - } - - @Override - public void onServiceDisconnected(ComponentName className) { - if (DBG) Log.d(TAG, "Proxy object disconnected"); - doUnbind(); - mHandler.sendMessage(mHandler.obtainMessage( - MESSAGE_HEADSET_SERVICE_DISCONNECTED)); - } - }; - - @UnsupportedAppUsage - private boolean isEnabled() { - return mAdapter.getState() == BluetoothAdapter.STATE_ON; - } - - private boolean isDisabled() { - return mAdapter.getState() == BluetoothAdapter.STATE_OFF; - } - - private static boolean isValidDevice(BluetoothDevice device) { - return device != null && BluetoothAdapter.checkBluetoothAddress(device.getAddress()); - } - - private static void log(String msg) { - Log.d(TAG, msg); - } - - @SuppressLint("AndroidFrameworkBluetoothPermission") - private final Handler mHandler = new Handler(Looper.getMainLooper()) { - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case MESSAGE_HEADSET_SERVICE_CONNECTED: { - if (mServiceListener != null) { - mServiceListener.onServiceConnected(BluetoothProfile.HEADSET, - BluetoothHeadset.this); - } - break; - } - case MESSAGE_HEADSET_SERVICE_DISCONNECTED: { - if (mServiceListener != null) { - mServiceListener.onServiceDisconnected(BluetoothProfile.HEADSET); - } - break; - } - } - } - }; -} diff --git a/core/java/android/bluetooth/BluetoothHeadsetClient.java b/core/java/android/bluetooth/BluetoothHeadsetClient.java deleted file mode 100644 index 7d7a7f798bb9e7a8b9e4adab7cb045e52f271495..0000000000000000000000000000000000000000 --- a/core/java/android/bluetooth/BluetoothHeadsetClient.java +++ /dev/null @@ -1,1356 +0,0 @@ -/* - * Copyright (C) 2014 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.bluetooth; - -import static android.bluetooth.BluetoothUtils.getSyncTimeout; - -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; -import android.content.AttributionSource; -import android.content.Context; -import android.os.Build; -import android.os.Bundle; -import android.os.IBinder; -import android.os.RemoteException; -import android.util.Log; - -import com.android.modules.utils.SynchronousResultReceiver; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.TimeoutException; - -/** - * Public API to control Hands Free Profile (HFP role only). - *

- * This class defines methods that shall be used by application to manage profile - * connection, calls states and calls actions. - *

- * - * @hide - */ -public final class BluetoothHeadsetClient implements BluetoothProfile { - private static final String TAG = "BluetoothHeadsetClient"; - private static final boolean DBG = true; - private static final boolean VDBG = false; - - /** - * Intent sent whenever connection to remote changes. - * - *

It includes two extras: - * BluetoothProfile.EXTRA_PREVIOUS_STATE - * and BluetoothProfile.EXTRA_STATE, which - * are mandatory. - *

There are also non mandatory feature extras: - * {@link #EXTRA_AG_FEATURE_3WAY_CALLING}, - * {@link #EXTRA_AG_FEATURE_VOICE_RECOGNITION}, - * {@link #EXTRA_AG_FEATURE_ATTACH_NUMBER_TO_VT}, - * {@link #EXTRA_AG_FEATURE_REJECT_CALL}, - * {@link #EXTRA_AG_FEATURE_ECC}, - * {@link #EXTRA_AG_FEATURE_RESPONSE_AND_HOLD}, - * {@link #EXTRA_AG_FEATURE_ACCEPT_HELD_OR_WAITING_CALL}, - * {@link #EXTRA_AG_FEATURE_RELEASE_HELD_OR_WAITING_CALL}, - * {@link #EXTRA_AG_FEATURE_RELEASE_AND_ACCEPT}, - * {@link #EXTRA_AG_FEATURE_MERGE}, - * {@link #EXTRA_AG_FEATURE_MERGE_AND_DETACH}, - * sent as boolean values only when EXTRA_STATE - * is set to STATE_CONNECTED.

- * - *

Note that features supported by AG are being sent as - * booleans with value true, - * and not supported ones are not being sent at all.

- */ - @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"; - - /** - * Intent sent whenever audio state changes. - * - *

It includes two mandatory extras: - * {@link BluetoothProfile#EXTRA_STATE}, - * {@link BluetoothProfile#EXTRA_PREVIOUS_STATE}, - * with possible values: - * {@link #STATE_AUDIO_CONNECTING}, - * {@link #STATE_AUDIO_CONNECTED}, - * {@link #STATE_AUDIO_DISCONNECTED}

- *

When EXTRA_STATE is set - * to STATE_AUDIO_CONNECTED, - * it also includes {@link #EXTRA_AUDIO_WBS} - * indicating wide band speech support.

- */ - @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"; - - /** - * Intent sending updates of the Audio Gateway state. - * Each extra is being sent only when value it - * represents has been changed recently on AG. - *

It can contain one or more of the following extras: - * {@link #EXTRA_NETWORK_STATUS}, - * {@link #EXTRA_NETWORK_SIGNAL_STRENGTH}, - * {@link #EXTRA_NETWORK_ROAMING}, - * {@link #EXTRA_BATTERY_LEVEL}, - * {@link #EXTRA_OPERATOR_NAME}, - * {@link #EXTRA_VOICE_RECOGNITION}, - * {@link #EXTRA_IN_BAND_RING}

- */ - @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"; - - /** - * Intent sent whenever state of a call changes. - * - *

It includes: - * {@link #EXTRA_CALL}, - * with value of {@link BluetoothHeadsetClientCall} instance, - * representing actual call state.

- */ - @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"; - - /** - * Intent that notifies about the result of the last issued action. - * Please note that not every action results in explicit action result code being sent. - * Instead other notifications about new Audio Gateway state might be sent, - * like ACTION_AG_EVENT with EXTRA_VOICE_RECOGNITION 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"; - - /** - * Intent that notifies about vendor specific event arrival. Events not defined in - * HFP spec will be matched with supported vendor event list and this intent will - * be broadcasted upon a match. Supported vendor events are of format of - * of "+eventCode" or "+eventCode=xxxx" or "+eventCode:=xxxx". - * 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"; - - /** - * Intent that notifies about the number attached to the last voice tag - * recorded on AG. - * - *

It contains: - * {@link #EXTRA_NUMBER}, - * with a String value representing phone number.

- */ - @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"; - - public static final int STATE_AUDIO_DISCONNECTED = 0; - public static final int STATE_AUDIO_CONNECTING = 1; - public static final int STATE_AUDIO_CONNECTED = 2; - - /** - * Extra with information if connected audio is WBS. - *

Possible values: true, - * false.

- */ - public static final String EXTRA_AUDIO_WBS = - "android.bluetooth.headsetclient.extra.AUDIO_WBS"; - - /** - * Extra for AG_EVENT indicates network status. - *

Value: 0 - network unavailable, - * 1 - network available

- */ - public static final String EXTRA_NETWORK_STATUS = - "android.bluetooth.headsetclient.extra.NETWORK_STATUS"; - /** - * Extra for AG_EVENT intent indicates network signal strength. - *

Value: Integer representing signal strength.

- */ - public static final String EXTRA_NETWORK_SIGNAL_STRENGTH = - "android.bluetooth.headsetclient.extra.NETWORK_SIGNAL_STRENGTH"; - /** - * Extra for AG_EVENT intent indicates roaming state. - *

Value: 0 - no roaming - * 1 - active roaming

- */ - public static final String EXTRA_NETWORK_ROAMING = - "android.bluetooth.headsetclient.extra.NETWORK_ROAMING"; - /** - * Extra for AG_EVENT intent indicates the battery level. - *

Value: Integer representing signal strength.

- */ - public static final String EXTRA_BATTERY_LEVEL = - "android.bluetooth.headsetclient.extra.BATTERY_LEVEL"; - /** - * Extra for AG_EVENT intent indicates operator name. - *

Value: String representing operator name.

- */ - public static final String EXTRA_OPERATOR_NAME = - "android.bluetooth.headsetclient.extra.OPERATOR_NAME"; - /** - * Extra for AG_EVENT intent indicates voice recognition state. - *

Value: - * 0 - voice recognition stopped, - * 1 - voice recognition started.

- */ - public static final String EXTRA_VOICE_RECOGNITION = - "android.bluetooth.headsetclient.extra.VOICE_RECOGNITION"; - /** - * Extra for AG_EVENT intent indicates in band ring state. - *

Value: - * 0 - in band ring tone not supported, or - * 1 - in band ring tone supported.

- */ - public static final String EXTRA_IN_BAND_RING = - "android.bluetooth.headsetclient.extra.IN_BAND_RING"; - - /** - * Extra for AG_EVENT intent indicates subscriber info. - *

Value: String containing subscriber information.

- */ - public static final String EXTRA_SUBSCRIBER_INFO = - "android.bluetooth.headsetclient.extra.SUBSCRIBER_INFO"; - - /** - * Extra for AG_CALL_CHANGED intent indicates the - * {@link BluetoothHeadsetClientCall} object that has changed. - */ - public static final String EXTRA_CALL = - "android.bluetooth.headsetclient.extra.CALL"; - - /** - * Extra for ACTION_LAST_VTAG intent. - *

Value: String representing phone number - * corresponding to last voice tag recorded on AG

- */ - public static final String EXTRA_NUMBER = - "android.bluetooth.headsetclient.extra.NUMBER"; - - /** - * Extra for ACTION_RESULT intent that shows the result code of - * last issued action. - *

Possible results: - * {@link #ACTION_RESULT_OK}, - * {@link #ACTION_RESULT_ERROR}, - * {@link #ACTION_RESULT_ERROR_NO_CARRIER}, - * {@link #ACTION_RESULT_ERROR_BUSY}, - * {@link #ACTION_RESULT_ERROR_NO_ANSWER}, - * {@link #ACTION_RESULT_ERROR_DELAYED}, - * {@link #ACTION_RESULT_ERROR_BLACKLISTED}, - * {@link #ACTION_RESULT_ERROR_CME}

- */ - public static final String EXTRA_RESULT_CODE = - "android.bluetooth.headsetclient.extra.RESULT_CODE"; - - /** - * Extra for ACTION_RESULT intent that shows the extended result code of - * last issued action. - *

Value: Integer - error code.

- */ - public static final String EXTRA_CME_CODE = - "android.bluetooth.headsetclient.extra.CME_CODE"; - - /** - * Extra for VENDOR_SPECIFIC_HEADSETCLIENT_EVENT intent that - * indicates vendor ID. - */ - public static final String EXTRA_VENDOR_ID = - "android.bluetooth.headsetclient.extra.VENDOR_ID"; - - /** - * Extra for VENDOR_SPECIFIC_HEADSETCLIENT_EVENT intent that - * indicates vendor event code. - */ - public static final String EXTRA_VENDOR_EVENT_CODE = - "android.bluetooth.headsetclient.extra.VENDOR_EVENT_CODE"; - - /** - * Extra for VENDOR_SPECIFIC_HEADSETCLIENT_EVENT intent that - * contains full vendor event including event code and full arguments. - */ - public static final String EXTRA_VENDOR_EVENT_FULL_ARGS = - "android.bluetooth.headsetclient.extra.VENDOR_EVENT_FULL_ARGS"; - - - /* Extras for AG_FEATURES, extras type is boolean */ - // TODO verify if all of those are actually useful - /** - * AG feature: three way calling. - */ - public static final String EXTRA_AG_FEATURE_3WAY_CALLING = - "android.bluetooth.headsetclient.extra.EXTRA_AG_FEATURE_3WAY_CALLING"; - /** - * AG feature: voice recognition. - */ - public static final String EXTRA_AG_FEATURE_VOICE_RECOGNITION = - "android.bluetooth.headsetclient.extra.EXTRA_AG_FEATURE_VOICE_RECOGNITION"; - /** - * AG feature: fetching phone number for voice tagging procedure. - */ - public static final String EXTRA_AG_FEATURE_ATTACH_NUMBER_TO_VT = - "android.bluetooth.headsetclient.extra.EXTRA_AG_FEATURE_ATTACH_NUMBER_TO_VT"; - /** - * AG feature: ability to reject incoming call. - */ - public static final String EXTRA_AG_FEATURE_REJECT_CALL = - "android.bluetooth.headsetclient.extra.EXTRA_AG_FEATURE_REJECT_CALL"; - /** - * AG feature: enhanced call handling (terminate specific call, private consultation). - */ - public static final String EXTRA_AG_FEATURE_ECC = - "android.bluetooth.headsetclient.extra.EXTRA_AG_FEATURE_ECC"; - /** - * AG feature: response and hold. - */ - public static final String EXTRA_AG_FEATURE_RESPONSE_AND_HOLD = - "android.bluetooth.headsetclient.extra.EXTRA_AG_FEATURE_RESPONSE_AND_HOLD"; - /** - * AG call handling feature: accept held or waiting call in three way calling scenarios. - */ - public static final String EXTRA_AG_FEATURE_ACCEPT_HELD_OR_WAITING_CALL = - "android.bluetooth.headsetclient.extra.EXTRA_AG_FEATURE_ACCEPT_HELD_OR_WAITING_CALL"; - /** - * AG call handling feature: release held or waiting call in three way calling scenarios. - */ - public static final String EXTRA_AG_FEATURE_RELEASE_HELD_OR_WAITING_CALL = - "android.bluetooth.headsetclient.extra.EXTRA_AG_FEATURE_RELEASE_HELD_OR_WAITING_CALL"; - /** - * AG call handling feature: release active call and accept held or waiting call in three way - * calling scenarios. - */ - public static final String EXTRA_AG_FEATURE_RELEASE_AND_ACCEPT = - "android.bluetooth.headsetclient.extra.EXTRA_AG_FEATURE_RELEASE_AND_ACCEPT"; - /** - * AG call handling feature: merge two calls, held and active - multi party conference mode. - */ - public static final String EXTRA_AG_FEATURE_MERGE = - "android.bluetooth.headsetclient.extra.EXTRA_AG_FEATURE_MERGE"; - /** - * AG call handling feature: merge calls and disconnect from multi party - * conversation leaving peers connected to each other. - * Note that this feature needs to be supported by mobile network operator - * as it requires connection and billing transfer. - */ - public static final String EXTRA_AG_FEATURE_MERGE_AND_DETACH = - "android.bluetooth.headsetclient.extra.EXTRA_AG_FEATURE_MERGE_AND_DETACH"; - - /* Action result codes */ - public static final int ACTION_RESULT_OK = 0; - public static final int ACTION_RESULT_ERROR = 1; - public static final int ACTION_RESULT_ERROR_NO_CARRIER = 2; - public static final int ACTION_RESULT_ERROR_BUSY = 3; - public static final int ACTION_RESULT_ERROR_NO_ANSWER = 4; - public static final int ACTION_RESULT_ERROR_DELAYED = 5; - public static final int ACTION_RESULT_ERROR_BLACKLISTED = 6; - public static final int ACTION_RESULT_ERROR_CME = 7; - - /* Detailed CME error codes */ - public static final int CME_PHONE_FAILURE = 0; - public static final int CME_NO_CONNECTION_TO_PHONE = 1; - public static final int CME_OPERATION_NOT_ALLOWED = 3; - public static final int CME_OPERATION_NOT_SUPPORTED = 4; - public static final int CME_PHSIM_PIN_REQUIRED = 5; - public static final int CME_PHFSIM_PIN_REQUIRED = 6; - public static final int CME_PHFSIM_PUK_REQUIRED = 7; - public static final int CME_SIM_NOT_INSERTED = 10; - public static final int CME_SIM_PIN_REQUIRED = 11; - public static final int CME_SIM_PUK_REQUIRED = 12; - public static final int CME_SIM_FAILURE = 13; - public static final int CME_SIM_BUSY = 14; - public static final int CME_SIM_WRONG = 15; - public static final int CME_INCORRECT_PASSWORD = 16; - public static final int CME_SIM_PIN2_REQUIRED = 17; - public static final int CME_SIM_PUK2_REQUIRED = 18; - public static final int CME_MEMORY_FULL = 20; - public static final int CME_INVALID_INDEX = 21; - public static final int CME_NOT_FOUND = 22; - public static final int CME_MEMORY_FAILURE = 23; - public static final int CME_TEXT_STRING_TOO_LONG = 24; - public static final int CME_INVALID_CHARACTER_IN_TEXT_STRING = 25; - public static final int CME_DIAL_STRING_TOO_LONG = 26; - public static final int CME_INVALID_CHARACTER_IN_DIAL_STRING = 27; - public static final int CME_NO_NETWORK_SERVICE = 30; - public static final int CME_NETWORK_TIMEOUT = 31; - public static final int CME_EMERGENCY_SERVICE_ONLY = 32; - public static final int CME_NO_SIMULTANOUS_VOIP_CS_CALLS = 33; - public static final int CME_NOT_SUPPORTED_FOR_VOIP = 34; - public static final int CME_SIP_RESPONSE_CODE = 35; - public static final int CME_NETWORK_PERSONALIZATION_PIN_REQUIRED = 40; - public static final int CME_NETWORK_PERSONALIZATION_PUK_REQUIRED = 41; - public static final int CME_NETWORK_SUBSET_PERSONALIZATION_PIN_REQUIRED = 42; - public static final int CME_NETWORK_SUBSET_PERSONALIZATION_PUK_REQUIRED = 43; - public static final int CME_SERVICE_PROVIDER_PERSONALIZATION_PIN_REQUIRED = 44; - public static final int CME_SERVICE_PROVIDER_PERSONALIZATION_PUK_REQUIRED = 45; - public static final int CME_CORPORATE_PERSONALIZATION_PIN_REQUIRED = 46; - public static final int CME_CORPORATE_PERSONALIZATION_PUK_REQUIRED = 47; - public static final int CME_HIDDEN_KEY_REQUIRED = 48; - public static final int CME_EAP_NOT_SUPPORTED = 49; - public static final int CME_INCORRECT_PARAMETERS = 50; - - /* Action policy for other calls when accepting call */ - public static final int CALL_ACCEPT_NONE = 0; - public static final int CALL_ACCEPT_HOLD = 1; - public static final int CALL_ACCEPT_TERMINATE = 2; - - private final BluetoothAdapter mAdapter; - private final AttributionSource mAttributionSource; - private final BluetoothProfileConnector mProfileConnector = - new BluetoothProfileConnector(this, BluetoothProfile.HEADSET_CLIENT, - "BluetoothHeadsetClient", IBluetoothHeadsetClient.class.getName()) { - @Override - public IBluetoothHeadsetClient getServiceInterface(IBinder service) { - return IBluetoothHeadsetClient.Stub.asInterface(service); - } - }; - - /** - * Create a BluetoothHeadsetClient proxy object. - */ - /* package */ BluetoothHeadsetClient(Context context, ServiceListener listener, - BluetoothAdapter adapter) { - mAdapter = adapter; - mAttributionSource = adapter.getAttributionSource(); - mProfileConnector.connect(context, listener); - } - - /** - * Close the connection to the backing service. - * Other public functions of BluetoothHeadsetClient will return default error - * results once close() has been called. Multiple invocations of close() - * are ok. - */ - /*package*/ void close() { - if (VDBG) log("close()"); - mProfileConnector.disconnect(); - } - - private IBluetoothHeadsetClient getService() { - return mProfileConnector.getService(); - } - - /** - * Connects to remote device. - * - * Currently, the system supports only 1 connection. So, in case of the - * second connection, this implementation will disconnect already connected - * device automatically and will process the new one. - * - * @param device a remote device we want connect to - * @return true if command has been issued successfully; false - * otherwise; upon completion HFP sends {@link #ACTION_CONNECTION_STATE_CHANGED} intent. - * - * @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 + ")"); - final IBluetoothHeadsetClient service = getService(); - final boolean defaultValue = false; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device)) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.connect(device, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Disconnects remote device - * - * @param device a remote device we want disconnect - * @return true if command has been issued successfully; false - * otherwise; upon completion HFP sends {@link #ACTION_CONNECTION_STATE_CHANGED} intent. - * - * @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 + ")"); - final IBluetoothHeadsetClient service = getService(); - final boolean defaultValue = false; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device)) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.disconnect(device, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Return the list of connected remote devices - * - * @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()"); - final IBluetoothHeadsetClient service = getService(); - final List defaultValue = new ArrayList(); - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled()) { - try { - final SynchronousResultReceiver> recv = - new SynchronousResultReceiver(); - service.getConnectedDevices(mAttributionSource, recv); - return Attributable.setAttributionSource( - recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue), - mAttributionSource); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Returns list of remote devices in a particular state - * - * @param states collection of states - * @return list of devices that state matches the states listed in states; empty - * list if nothing matches the states - */ - @Override - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public List getDevicesMatchingConnectionStates(int[] states) { - if (VDBG) log("getDevicesMatchingStates()"); - final IBluetoothHeadsetClient service = getService(); - final List defaultValue = new ArrayList(); - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled()) { - try { - final SynchronousResultReceiver> recv = - new SynchronousResultReceiver(); - service.getDevicesMatchingConnectionStates(states, mAttributionSource, recv); - return Attributable.setAttributionSource( - recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue), - mAttributionSource); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Returns state of the device - * - * @param device a remote device - * @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 + ")"); - final IBluetoothHeadsetClient service = getService(); - final int defaultValue = BluetoothProfile.STATE_DISCONNECTED; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device)) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.getConnectionState(device, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Set priority of the profile - * - *

The device should already be paired. - * Priority can be one of {@link #PRIORITY_ON} or {@link #PRIORITY_OFF} - * - * @param device Paired bluetooth device - * @param priority - * @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 + ")"); - return setConnectionPolicy(device, BluetoothAdapter.priorityToConnectionPolicy(priority)); - } - - /** - * Set connection policy of the profile - * - *

The device should already be paired. - * Connection policy can be one of {@link #CONNECTION_POLICY_ALLOWED}, - * {@link #CONNECTION_POLICY_FORBIDDEN}, {@link #CONNECTION_POLICY_UNKNOWN} - * - * @param device Paired bluetooth device - * @param connectionPolicy is the connection policy to set to for this profile - * @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) { - if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")"); - final IBluetoothHeadsetClient service = getService(); - final boolean defaultValue = false; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device) - && (connectionPolicy == BluetoothProfile.CONNECTION_POLICY_FORBIDDEN - || connectionPolicy == BluetoothProfile.CONNECTION_POLICY_ALLOWED)) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.setConnectionPolicy(device, connectionPolicy, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Get the priority of the profile. - * - *

The priority can be any of: - * {@link #PRIORITY_OFF}, {@link #PRIORITY_ON}, {@link #PRIORITY_UNDEFINED} - * - * @param device Bluetooth device - * @return priority of the device - * @hide - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public int getPriority(BluetoothDevice device) { - if (VDBG) log("getPriority(" + device + ")"); - return BluetoothAdapter.connectionPolicyToPriority(getConnectionPolicy(device)); - } - - /** - * Get the connection policy of the profile. - * - *

The connection policy can be any of: - * {@link #CONNECTION_POLICY_ALLOWED}, {@link #CONNECTION_POLICY_FORBIDDEN}, - * {@link #CONNECTION_POLICY_UNKNOWN} - * - * @param device Bluetooth device - * @return connection policy of the device - * @hide - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public @ConnectionPolicy int getConnectionPolicy(@NonNull BluetoothDevice device) { - if (VDBG) log("getConnectionPolicy(" + device + ")"); - final IBluetoothHeadsetClient service = getService(); - final @ConnectionPolicy int defaultValue = BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device)) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.getConnectionPolicy(device, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Starts voice recognition. - * - * @param device remote device - * @return true if command has been issued successfully; false - * otherwise; upon completion HFP sends {@link #ACTION_AG_EVENT} intent. - * - *

Feature required for successful execution is being reported by: {@link - * #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()"); - final IBluetoothHeadsetClient service = getService(); - final boolean defaultValue = false; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device)) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.startVoiceRecognition(device, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Send vendor specific AT command. - * - * @param device remote device - * @param vendorId vendor number by Bluetooth SIG - * @param atCommand command to be sent. It start with + prefix and only one command at one time. - * @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) { - if (DBG) log("sendVendorSpecificCommand()"); - final IBluetoothHeadsetClient service = getService(); - final boolean defaultValue = false; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device)) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.sendVendorAtCommand(device, vendorId, atCommand, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Stops voice recognition. - * - * @param device remote device - * @return true if command has been issued successfully; false - * otherwise; upon completion HFP sends {@link #ACTION_AG_EVENT} intent. - * - *

Feature required for successful execution is being reported by: {@link - * #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()"); - final IBluetoothHeadsetClient service = getService(); - final boolean defaultValue = false; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device)) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.stopVoiceRecognition(device, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Returns list of all calls in any state. - * - * @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()"); - final IBluetoothHeadsetClient service = getService(); - final List defaultValue = null; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device)) { - try { - final SynchronousResultReceiver> recv = - new SynchronousResultReceiver(); - service.getCurrentCalls(device, mAttributionSource, recv); - return Attributable.setAttributionSource( - recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue), - mAttributionSource); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Returns list of current values of AG indicators. - * - * @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("getCurrentAgEvents()"); - final IBluetoothHeadsetClient service = getService(); - final Bundle defaultValue = null; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device)) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.getCurrentAgEvents(device, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Accepts a call - * - * @param device remote device - * @param flag action policy while accepting a call. Possible values {@link #CALL_ACCEPT_NONE}, - * {@link #CALL_ACCEPT_HOLD}, {@link #CALL_ACCEPT_TERMINATE} - * @return true if command has been issued successfully; false - * 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()"); - final IBluetoothHeadsetClient service = getService(); - final boolean defaultValue = false; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device)) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.acceptCall(device, flag, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Holds a call. - * - * @param device remote device - * @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()"); - final IBluetoothHeadsetClient service = getService(); - final boolean defaultValue = false; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device)) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.holdCall(device, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Rejects a call. - * - * @param device remote device - * @return true if command has been issued successfully; false - * otherwise; upon completion HFP sends {@link #ACTION_CALL_CHANGED} intent. - * - *

Feature required for successful execution is being reported by: {@link - * #EXTRA_AG_FEATURE_REJECT_CALL}. This method invocation will fail silently when feature is not - * 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()"); - final IBluetoothHeadsetClient service = getService(); - final boolean defaultValue = false; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device)) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.rejectCall(device, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Terminates a specified call. - * - * Works only when Extended Call Control is supported by Audio Gateway. - * - * @param device remote device - * @param call Handle of call obtained in {@link #dial(BluetoothDevice, String)} or obtained via - * {@link #ACTION_CALL_CHANGED}. {@code call} may be null in which case we will hangup all active - * calls. - * @return true if command has been issued successfully; false - * otherwise; upon completion HFP sends {@link #ACTION_CALL_CHANGED} intent. - * - *

Feature required for successful execution is being reported by: {@link - * #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()"); - final IBluetoothHeadsetClient service = getService(); - final boolean defaultValue = false; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device)) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.terminateCall(device, call, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Enters private mode with a specified call. - * - * Works only when Extended Call Control is supported by Audio Gateway. - * - * @param device remote device - * @param index index of the call to connect in private mode - * @return true if command has been issued successfully; false - * otherwise; upon completion HFP sends {@link #ACTION_CALL_CHANGED} intent. - * - *

Feature required for successful execution is being reported by: {@link - * #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()"); - final IBluetoothHeadsetClient service = getService(); - final boolean defaultValue = false; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device)) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.enterPrivateMode(device, index, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Performs explicit call transfer. - * - * That means connect other calls and disconnect. - * - * @param device remote device - * @return true if command has been issued successfully; false - * otherwise; upon completion HFP sends {@link #ACTION_CALL_CHANGED} intent. - * - *

Feature required for successful execution is being reported by: {@link - * #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()"); - final IBluetoothHeadsetClient service = getService(); - final boolean defaultValue = false; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device)) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.explicitCallTransfer(device, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Places a call with specified number. - * - * @param device remote device - * @param number valid phone number - * @return {@link BluetoothHeadsetClientCall} call if command has been issued - * 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()"); - final IBluetoothHeadsetClient service = getService(); - final BluetoothHeadsetClientCall defaultValue = null; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device)) { - try { - final SynchronousResultReceiver recv = - new SynchronousResultReceiver(); - service.dial(device, number, mAttributionSource, recv); - return Attributable.setAttributionSource( - recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue), - mAttributionSource); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Sends DTMF code. - * - * Possible code values : 0,1,2,3,4,5,6,7,8,9,A,B,C,D,*,# - * - * @param device remote device - * @param code ASCII code - * @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()"); - final IBluetoothHeadsetClient service = getService(); - final boolean defaultValue = false; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device)) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.sendDTMF(device, code, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Get a number corresponding to last voice tag recorded on AG. - * - * @param device remote device - * @return true if command has been issued successfully; false - * otherwise; upon completion HFP sends {@link #ACTION_LAST_VTAG} or {@link #ACTION_RESULT} - * intent; - * - *

Feature required for successful execution is being reported by: {@link - * #EXTRA_AG_FEATURE_ATTACH_NUMBER_TO_VT}. This method invocation will fail silently when - * feature is not supported.

- */ - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public boolean getLastVoiceTagNumber(BluetoothDevice device) { - if (DBG) log("getLastVoiceTagNumber()"); - final IBluetoothHeadsetClient service = getService(); - final boolean defaultValue = false; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device)) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.getLastVoiceTagNumber(device, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Returns current audio state of Audio Gateway. - * - * Note: This is an internal function and shouldn't be exposed - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public int getAudioState(BluetoothDevice device) { - if (VDBG) log("getAudioState"); - final IBluetoothHeadsetClient service = getService(); - final int defaultValue = BluetoothHeadsetClient.STATE_AUDIO_DISCONNECTED; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled()) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.getAudioState(device, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } else { - return defaultValue; - } - return BluetoothHeadsetClient.STATE_AUDIO_DISCONNECTED; - } - - /** - * Sets whether audio routing is allowed. - * - * @param device remote device - * @param allowed if routing is allowed to the device Note: This is an internal function and - * shouldn't be exposed - */ - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public void setAudioRouteAllowed(BluetoothDevice device, boolean allowed) { - if (VDBG) log("setAudioRouteAllowed"); - final IBluetoothHeadsetClient service = getService(); - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled()) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.setAudioRouteAllowed(device, allowed, mAttributionSource, recv); - recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(null); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - } - - /** - * Returns whether audio routing is allowed. - * - * @param device remote device - * @return whether the command succeeded Note: This is an internal function and shouldn't be - * exposed - */ - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public boolean getAudioRouteAllowed(BluetoothDevice device) { - if (VDBG) log("getAudioRouteAllowed"); - final IBluetoothHeadsetClient service = getService(); - final boolean defaultValue = false; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled()) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.getAudioRouteAllowed(device, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Initiates a connection of audio channel. - * - * It setup SCO channel with remote connected Handsfree AG device. - * - * @param device remote device - * @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) { - if (VDBG) log("connectAudio"); - final IBluetoothHeadsetClient service = getService(); - final boolean defaultValue = false; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled()) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.connectAudio(device, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Disconnects audio channel. - * - * It tears down the SCO channel from remote AG device. - * - * @param device remote device - * @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) { - if (VDBG) log("disconnectAudio"); - final IBluetoothHeadsetClient service = getService(); - final boolean defaultValue = false; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled()) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.disconnectAudio(device, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Get Audio Gateway features - * - * @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) { - if (VDBG) log("getCurrentAgFeatures"); - final IBluetoothHeadsetClient service = getService(); - final Bundle defaultValue = null; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled()) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.getCurrentAgFeatures(device, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - private boolean isEnabled() { - return mAdapter.getState() == BluetoothAdapter.STATE_ON; - } - - private static boolean isValidDevice(BluetoothDevice device) { - return device != null && BluetoothAdapter.checkBluetoothAddress(device.getAddress()); - } - - private static void log(String msg) { - Log.d(TAG, msg); - } -} diff --git a/core/java/android/bluetooth/BluetoothHeadsetClientCall.java b/core/java/android/bluetooth/BluetoothHeadsetClientCall.java deleted file mode 100644 index 032b507f5d3cf33c66ee31dec0da3202354a233e..0000000000000000000000000000000000000000 --- a/core/java/android/bluetooth/BluetoothHeadsetClientCall.java +++ /dev/null @@ -1,323 +0,0 @@ -/* - * Copyright (C) 2014 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.bluetooth; - -import android.annotation.NonNull; -import android.compat.annotation.UnsupportedAppUsage; -import android.content.AttributionSource; -import android.os.Build; -import android.os.Parcel; -import android.os.Parcelable; -import android.os.SystemClock; - -import java.util.UUID; - -/** - * This class represents a single call, its state and properties. - * It implements {@link Parcelable} for inter-process message passing. - * - * @hide - */ -public final class BluetoothHeadsetClientCall implements Parcelable, Attributable { - - /* Call state */ - /** - * Call is active. - */ - public static final int CALL_STATE_ACTIVE = 0; - /** - * Call is in held state. - */ - public static final int CALL_STATE_HELD = 1; - /** - * Outgoing call that is being dialed right now. - */ - public static final int CALL_STATE_DIALING = 2; - /** - * Outgoing call that remote party has already been alerted about. - */ - public static final int CALL_STATE_ALERTING = 3; - /** - * Incoming call that can be accepted or rejected. - */ - public static final int CALL_STATE_INCOMING = 4; - /** - * Waiting call state when there is already an active call. - */ - public static final int CALL_STATE_WAITING = 5; - /** - * Call that has been held by response and hold - * (see Bluetooth specification for further references). - */ - public static final int CALL_STATE_HELD_BY_RESPONSE_AND_HOLD = 6; - /** - * Call that has been already terminated and should not be referenced as a valid call. - */ - public static final int CALL_STATE_TERMINATED = 7; - - private final BluetoothDevice mDevice; - private final int mId; - private int mState; - private String mNumber; - private boolean mMultiParty; - private final boolean mOutgoing; - private final UUID mUUID; - private final long mCreationElapsedMilli; - private final boolean mInBandRing; - - /** - * Creates BluetoothHeadsetClientCall instance. - */ - public BluetoothHeadsetClientCall(BluetoothDevice device, int id, int state, String number, - boolean multiParty, boolean outgoing, boolean inBandRing) { - this(device, id, UUID.randomUUID(), state, number, multiParty, outgoing, inBandRing); - } - - public BluetoothHeadsetClientCall(BluetoothDevice device, int id, UUID uuid, int state, - String number, boolean multiParty, boolean outgoing, boolean inBandRing) { - mDevice = device; - mId = id; - mUUID = uuid; - mState = state; - mNumber = number != null ? number : ""; - mMultiParty = multiParty; - mOutgoing = outgoing; - mInBandRing = inBandRing; - mCreationElapsedMilli = SystemClock.elapsedRealtime(); - } - - /** {@hide} */ - public void setAttributionSource(@NonNull AttributionSource attributionSource) { - Attributable.setAttributionSource(mDevice, attributionSource); - } - - /** - * Sets call's state. - * - *

Note: This is an internal function and shouldn't be exposed

- * - * @param state new call state. - */ - public void setState(int state) { - mState = state; - } - - /** - * Sets call's number. - * - *

Note: This is an internal function and shouldn't be exposed

- * - * @param number String representing phone number. - */ - public void setNumber(String number) { - mNumber = number; - } - - /** - * Sets this call as multi party call. - * - *

Note: This is an internal function and shouldn't be exposed

- * - * @param multiParty if true sets this call as a part of multi party conference. - */ - public void setMultiParty(boolean multiParty) { - mMultiParty = multiParty; - } - - /** - * Gets call's device. - * - * @return call device. - */ - public BluetoothDevice getDevice() { - return mDevice; - } - - /** - * Gets call's Id. - * - * @return call id. - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public int getId() { - return mId; - } - - /** - * Gets call's UUID. - * - * @return call uuid - * @hide - */ - public UUID getUUID() { - return mUUID; - } - - /** - * Gets call's current state. - * - * @return state of this particular phone call. - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public int getState() { - return mState; - } - - /** - * Gets call's number. - * - * @return string representing phone number. - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public String getNumber() { - return mNumber; - } - - /** - * Gets call's creation time in millis since epoch. - * - * @return long representing the creation time. - */ - public long getCreationElapsedMilli() { - return mCreationElapsedMilli; - } - - /** - * Checks if call is an active call in a conference mode (aka multi party). - * - * @return true if call is a multi party call, false otherwise. - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public boolean isMultiParty() { - return mMultiParty; - } - - /** - * Checks if this call is an outgoing call. - * - * @return true if its outgoing call, false otherwise. - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public boolean isOutgoing() { - return mOutgoing; - } - - /** - * Checks if the ringtone will be generated by the connected phone - * - * @return true if in band ring is enabled, false otherwise. - */ - public boolean isInBandRing() { - return mInBandRing; - } - - - @Override - public String toString() { - return toString(false); - } - - /** - * Generate a log string for this call - * @param loggable whether device address should be logged - * @return log string - */ - public String toString(boolean loggable) { - StringBuilder builder = new StringBuilder("BluetoothHeadsetClientCall{mDevice: "); - builder.append(loggable ? mDevice : mDevice.hashCode()); - builder.append(", mId: "); - builder.append(mId); - builder.append(", mUUID: "); - builder.append(mUUID); - builder.append(", mState: "); - switch (mState) { - case CALL_STATE_ACTIVE: - builder.append("ACTIVE"); - break; - case CALL_STATE_HELD: - builder.append("HELD"); - break; - case CALL_STATE_DIALING: - builder.append("DIALING"); - break; - case CALL_STATE_ALERTING: - builder.append("ALERTING"); - break; - case CALL_STATE_INCOMING: - builder.append("INCOMING"); - break; - case CALL_STATE_WAITING: - builder.append("WAITING"); - break; - case CALL_STATE_HELD_BY_RESPONSE_AND_HOLD: - builder.append("HELD_BY_RESPONSE_AND_HOLD"); - break; - case CALL_STATE_TERMINATED: - builder.append("TERMINATED"); - break; - default: - builder.append(mState); - break; - } - builder.append(", mNumber: "); - builder.append(loggable ? mNumber : mNumber.hashCode()); - builder.append(", mMultiParty: "); - builder.append(mMultiParty); - builder.append(", mOutgoing: "); - builder.append(mOutgoing); - builder.append(", mInBandRing: "); - builder.append(mInBandRing); - builder.append("}"); - return builder.toString(); - } - - /** - * {@link Parcelable.Creator} interface implementation. - */ - public static final @android.annotation.NonNull Parcelable.Creator CREATOR = - new Parcelable.Creator() { - @Override - public BluetoothHeadsetClientCall createFromParcel(Parcel in) { - return new BluetoothHeadsetClientCall((BluetoothDevice) in.readParcelable(null), - in.readInt(), UUID.fromString(in.readString()), in.readInt(), - in.readString(), in.readInt() == 1, in.readInt() == 1, - in.readInt() == 1); - } - - @Override - public BluetoothHeadsetClientCall[] newArray(int size) { - return new BluetoothHeadsetClientCall[size]; - } - }; - - @Override - public void writeToParcel(Parcel out, int flags) { - out.writeParcelable(mDevice, 0); - out.writeInt(mId); - out.writeString(mUUID.toString()); - out.writeInt(mState); - out.writeString(mNumber); - out.writeInt(mMultiParty ? 1 : 0); - out.writeInt(mOutgoing ? 1 : 0); - out.writeInt(mInBandRing ? 1 : 0); - } - - @Override - public int describeContents() { - return 0; - } -} diff --git a/core/java/android/bluetooth/BluetoothHealth.java b/core/java/android/bluetooth/BluetoothHealth.java deleted file mode 100644 index 65f68a943e08422015517fed87502d247a2d9610..0000000000000000000000000000000000000000 --- a/core/java/android/bluetooth/BluetoothHealth.java +++ /dev/null @@ -1,386 +0,0 @@ -/* - * Copyright (C) 2011 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.bluetooth; - -import android.annotation.RequiresPermission; -import android.annotation.SuppressLint; -import android.bluetooth.annotations.RequiresBluetoothConnectPermission; -import android.bluetooth.annotations.RequiresLegacyBluetoothPermission; -import android.os.ParcelFileDescriptor; -import android.util.Log; - -import java.util.ArrayList; -import java.util.List; - -/** - * Public API for Bluetooth Health Profile. - * - *

BluetoothHealth is a proxy object for controlling the Bluetooth - * Service via IPC. - * - *

How to connect to a health device which is acting in the source role. - *

  • Use {@link BluetoothAdapter#getProfileProxy} to get - * the BluetoothHealth proxy object.
  • - *
  • Create an {@link BluetoothHealth} callback and call - * {@link #registerSinkAppConfiguration} to register an application - * configuration
  • - *
  • Pair with the remote device. This currently needs to be done manually - * from Bluetooth Settings
  • - *
  • Connect to a health device using {@link #connectChannelToSource}. Some - * devices will connect the channel automatically. The {@link BluetoothHealth} - * callback will inform the application of channel state change.
  • - *
  • Use the file descriptor provided with a connected channel to read and - * write data to the health channel.
  • - *
  • The received data needs to be interpreted using a health manager which - * implements the IEEE 11073-xxxxx specifications. - *
  • When done, close the health channel by calling {@link #disconnectChannel} - * and unregister the application configuration calling - * {@link #unregisterAppConfiguration} - * - * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New apps - * should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt}, - * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or - * {@link BluetoothDevice#createL2capChannel(int)} - */ -@Deprecated -public final class BluetoothHealth implements BluetoothProfile { - private static final String TAG = "BluetoothHealth"; - /** - * Health Profile Source Role - the health device. - * - * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New - * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt}, - * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or - * {@link BluetoothDevice#createL2capChannel(int)} - */ - @Deprecated - public static final int SOURCE_ROLE = 1 << 0; - - /** - * Health Profile Sink Role the device talking to the health device. - * - * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New - * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt}, - * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or - * {@link BluetoothDevice#createL2capChannel(int)} - */ - @Deprecated - public static final int SINK_ROLE = 1 << 1; - - /** - * Health Profile - Channel Type used - Reliable - * - * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New - * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt}, - * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or - * {@link BluetoothDevice#createL2capChannel(int)} - */ - @Deprecated - public static final int CHANNEL_TYPE_RELIABLE = 10; - - /** - * Health Profile - Channel Type used - Streaming - * - * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New - * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt}, - * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or - * {@link BluetoothDevice#createL2capChannel(int)} - */ - @Deprecated - public static final int CHANNEL_TYPE_STREAMING = 11; - - /** - * Hide auto-created default constructor - * @hide - */ - BluetoothHealth() {} - - /** - * Register an application configuration that acts as a Health SINK. - * This is the configuration that will be used to communicate with health devices - * which will act as the {@link #SOURCE_ROLE}. This is an asynchronous call and so - * the callback is used to notify success or failure if the function returns true. - * - * @param name The friendly name associated with the application or configuration. - * @param dataType The dataType of the Source role of Health Profile to which the sink wants to - * connect to. - * @param callback A callback to indicate success or failure of the registration and all - * operations done on this application configuration. - * @return If true, callback will be called. - * - * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New - * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt}, - * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or - * {@link BluetoothDevice#createL2capChannel(int)} - */ - @Deprecated - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - @SuppressLint("AndroidFrameworkRequiresPermission") - public boolean registerSinkAppConfiguration(String name, int dataType, - BluetoothHealthCallback callback) { - Log.e(TAG, "registerSinkAppConfiguration(): BluetoothHealth is deprecated"); - return false; - } - - /** - * Unregister an application configuration that has been registered using - * {@link #registerSinkAppConfiguration} - * - * @param config The health app configuration - * @return Success or failure. - * - * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New - * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt}, - * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or - * {@link BluetoothDevice#createL2capChannel(int)} - */ - @Deprecated - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - @SuppressLint("AndroidFrameworkRequiresPermission") - public boolean unregisterAppConfiguration(BluetoothHealthAppConfiguration config) { - Log.e(TAG, "unregisterAppConfiguration(): BluetoothHealth is deprecated"); - return false; - } - - /** - * Connect to a health device which has the {@link #SOURCE_ROLE}. - * This is an asynchronous call. If this function returns true, the callback - * associated with the application configuration will be called. - * - * @param device The remote Bluetooth device. - * @param config The application configuration which has been registered using {@link - * #registerSinkAppConfiguration(String, int, BluetoothHealthCallback) } - * @return If true, the callback associated with the application config will be called. - * - * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New - * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt}, - * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or - * {@link BluetoothDevice#createL2capChannel(int)} - */ - @Deprecated - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - @SuppressLint("AndroidFrameworkRequiresPermission") - public boolean connectChannelToSource(BluetoothDevice device, - BluetoothHealthAppConfiguration config) { - Log.e(TAG, "connectChannelToSource(): BluetoothHealth is deprecated"); - return false; - } - - /** - * Disconnect a connected health channel. - * This is an asynchronous call. If this function returns true, the callback - * associated with the application configuration will be called. - * - * @param device The remote Bluetooth device. - * @param config The application configuration which has been registered using {@link - * #registerSinkAppConfiguration(String, int, BluetoothHealthCallback) } - * @param channelId The channel id associated with the channel - * @return If true, the callback associated with the application config will be called. - * - * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New - * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt}, - * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or - * {@link BluetoothDevice#createL2capChannel(int)} - */ - @Deprecated - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - @SuppressLint("AndroidFrameworkRequiresPermission") - public boolean disconnectChannel(BluetoothDevice device, - BluetoothHealthAppConfiguration config, int channelId) { - Log.e(TAG, "disconnectChannel(): BluetoothHealth is deprecated"); - return false; - } - - /** - * Get the file descriptor of the main channel associated with the remote device - * and application configuration. - * - *

    Its the responsibility of the caller to close the ParcelFileDescriptor - * when done. - * - * @param device The remote Bluetooth health device - * @param config The application configuration - * @return null on failure, ParcelFileDescriptor on success. - * - * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New - * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt}, - * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or - * {@link BluetoothDevice#createL2capChannel(int)} - */ - @Deprecated - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - @SuppressLint("AndroidFrameworkRequiresPermission") - public ParcelFileDescriptor getMainChannelFd(BluetoothDevice device, - BluetoothHealthAppConfiguration config) { - Log.e(TAG, "getMainChannelFd(): BluetoothHealth is deprecated"); - return null; - } - - /** - * Get the current connection state of the profile. - * - * This is not specific to any application configuration but represents the connection - * state of the local Bluetooth adapter with the remote device. This can be used - * by applications like status bar which would just like to know the state of the - * local adapter. - * - * @param device Remote bluetooth device. - * @return State of the profile connection. One of {@link #STATE_CONNECTED}, {@link - * #STATE_CONNECTING}, {@link #STATE_DISCONNECTED}, {@link #STATE_DISCONNECTING} - */ - @Override - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - @SuppressLint("AndroidFrameworkRequiresPermission") - public int getConnectionState(BluetoothDevice device) { - Log.e(TAG, "getConnectionState(): BluetoothHealth is deprecated"); - return STATE_DISCONNECTED; - } - - /** - * Get connected devices for the health profile. - * - *

    Return the set of devices which are in state {@link #STATE_CONNECTED} - * - * This is not specific to any application configuration but represents the connection - * state of the local Bluetooth adapter for this profile. This can be used - * by applications like status bar which would just like to know the state of the - * local adapter. - * - * @return List of devices. The list will be empty on error. - */ - @Override - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - @SuppressLint("AndroidFrameworkRequiresPermission") - public List getConnectedDevices() { - Log.e(TAG, "getConnectedDevices(): BluetoothHealth is deprecated"); - return new ArrayList<>(); - } - - /** - * Get a list of devices that match any of the given connection - * states. - * - *

    If none of the devices match any of the given states, - * an empty list will be returned. - * - *

    This is not specific to any application configuration but represents the connection - * state of the local Bluetooth adapter for this profile. This can be used - * by applications like status bar which would just like to know the state of the - * local adapter. - * - * @param states Array of states. States can be one of {@link #STATE_CONNECTED}, {@link - * #STATE_CONNECTING}, {@link #STATE_DISCONNECTED}, {@link #STATE_DISCONNECTING}, - * @return List of devices. The list will be empty on error. - */ - @Override - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - @SuppressLint("AndroidFrameworkRequiresPermission") - public List getDevicesMatchingConnectionStates(int[] states) { - Log.e(TAG, "getDevicesMatchingConnectionStates(): BluetoothHealth is deprecated"); - return new ArrayList<>(); - } - - /** Health Channel Connection State - Disconnected - * - * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New - * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt}, - * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or - * {@link BluetoothDevice#createL2capChannel(int)} - */ - @Deprecated - public static final int STATE_CHANNEL_DISCONNECTED = 0; - /** Health Channel Connection State - Connecting - * - * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New - * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt}, - * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or - * {@link BluetoothDevice#createL2capChannel(int)} - */ - @Deprecated - public static final int STATE_CHANNEL_CONNECTING = 1; - /** Health Channel Connection State - Connected - * - * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New - * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt}, - * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or - * {@link BluetoothDevice#createL2capChannel(int)} - */ - @Deprecated - public static final int STATE_CHANNEL_CONNECTED = 2; - /** Health Channel Connection State - Disconnecting - * - * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New - * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt}, - * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or - * {@link BluetoothDevice#createL2capChannel(int)} - */ - @Deprecated - public static final int STATE_CHANNEL_DISCONNECTING = 3; - - /** Health App Configuration registration success - * - * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New - * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt}, - * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or - * {@link BluetoothDevice#createL2capChannel(int)} - */ - @Deprecated - public static final int APP_CONFIG_REGISTRATION_SUCCESS = 0; - /** Health App Configuration registration failure - * - * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New - * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt}, - * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or - * {@link BluetoothDevice#createL2capChannel(int)} - */ - @Deprecated - public static final int APP_CONFIG_REGISTRATION_FAILURE = 1; - /** Health App Configuration un-registration success - * - * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New - * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt}, - * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or - * {@link BluetoothDevice#createL2capChannel(int)} - */ - @Deprecated - public static final int APP_CONFIG_UNREGISTRATION_SUCCESS = 2; - /** Health App Configuration un-registration failure - * - * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New - * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt}, - * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or - * {@link BluetoothDevice#createL2capChannel(int)} - */ - @Deprecated - public static final int APP_CONFIG_UNREGISTRATION_FAILURE = 3; -} diff --git a/core/java/android/bluetooth/BluetoothHealthAppConfiguration.java b/core/java/android/bluetooth/BluetoothHealthAppConfiguration.java deleted file mode 100644 index 2f66df258b537dc4c2596c23586e0776662eb9cf..0000000000000000000000000000000000000000 --- a/core/java/android/bluetooth/BluetoothHealthAppConfiguration.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright (C) 2011 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.bluetooth; - -import android.os.Parcel; -import android.os.Parcelable; - -/** - * The Bluetooth Health Application Configuration that is used in conjunction with - * the {@link BluetoothHealth} class. This class represents an application configuration - * that the Bluetooth Health third party application will register to communicate with the - * remote Bluetooth health device. - * - * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New - * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt}, - * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or - * {@link BluetoothDevice#createL2capChannel(int)} - */ -@Deprecated -public final class BluetoothHealthAppConfiguration implements Parcelable { - - /** - * Hide auto-created default constructor - * @hide - */ - BluetoothHealthAppConfiguration() {} - - @Override - public int describeContents() { - return 0; - } - - /** - * Return the data type associated with this application configuration. - * - * @return dataType - * - * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New - * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt}, - * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or - * {@link BluetoothDevice#createL2capChannel(int)} - */ - @Deprecated - public int getDataType() { - return 0; - } - - /** - * Return the name of the application configuration. - * - * @return String name - * - * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New - * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt}, - * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or - * {@link BluetoothDevice#createL2capChannel(int)} - */ - @Deprecated - public String getName() { - return null; - } - - /** - * Return the role associated with this application configuration. - * - * @return One of {@link BluetoothHealth#SOURCE_ROLE} or {@link BluetoothHealth#SINK_ROLE} - * - * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New - * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt}, - * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or - * {@link BluetoothDevice#createL2capChannel(int)} - */ - @Deprecated - public int getRole() { - return 0; - } - - /** - * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New - * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt}, - * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or - * {@link BluetoothDevice#createL2capChannel(int)} - */ - @Deprecated - public static final @android.annotation.NonNull Parcelable.Creator CREATOR = - new Parcelable.Creator() { - @Override - public BluetoothHealthAppConfiguration createFromParcel(Parcel in) { - return new BluetoothHealthAppConfiguration(); - } - - @Override - public BluetoothHealthAppConfiguration[] newArray(int size) { - return new BluetoothHealthAppConfiguration[size]; - } - }; - - @Override - public void writeToParcel(Parcel out, int flags) {} -} diff --git a/core/java/android/bluetooth/BluetoothHealthCallback.java b/core/java/android/bluetooth/BluetoothHealthCallback.java deleted file mode 100644 index 4769212c536154ff5d9cf299b83fe377fee8c71f..0000000000000000000000000000000000000000 --- a/core/java/android/bluetooth/BluetoothHealthCallback.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (C) 2011 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.bluetooth; - -import android.annotation.BinderThread; -import android.os.ParcelFileDescriptor; -import android.util.Log; - -/** - * This abstract class is used to implement {@link BluetoothHealth} callbacks. - * - * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New - * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt}, - * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or - * {@link BluetoothDevice#createL2capChannel(int)} - */ -@Deprecated -public abstract class BluetoothHealthCallback { - private static final String TAG = "BluetoothHealthCallback"; - - /** - * Callback to inform change in registration state of the health - * application. - *

    This callback is called on the binder thread (not on the UI thread) - * - * @param config Bluetooth Health app configuration - * @param status Success or failure of the registration or unregistration calls. Can be one of - * {@link BluetoothHealth#APP_CONFIG_REGISTRATION_SUCCESS} or {@link - * BluetoothHealth#APP_CONFIG_REGISTRATION_FAILURE} or - * {@link BluetoothHealth#APP_CONFIG_UNREGISTRATION_SUCCESS} - * or {@link BluetoothHealth#APP_CONFIG_UNREGISTRATION_FAILURE} - * - * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New - * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt}, - * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or - * {@link BluetoothDevice#createL2capChannel(int)} - */ - @BinderThread - @Deprecated - public void onHealthAppConfigurationStatusChange(BluetoothHealthAppConfiguration config, - int status) { - Log.d(TAG, "onHealthAppConfigurationStatusChange: " + config + "Status: " + status); - } - - /** - * Callback to inform change in channel state. - *

    Its the responsibility of the implementor of this callback to close the - * parcel file descriptor when done. This callback is called on the Binder - * thread (not the UI thread) - * - * @param config The Health app configutation - * @param device The Bluetooth Device - * @param prevState The previous state of the channel - * @param newState The new state of the channel. - * @param fd The Parcel File Descriptor when the channel state is connected. - * @param channelId The id associated with the channel. This id will be used in future calls - * like when disconnecting the channel. - * - * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New - * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt}, - * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or - * {@link BluetoothDevice#createL2capChannel(int)} - */ - @BinderThread - @Deprecated - public void onHealthChannelStateChange(BluetoothHealthAppConfiguration config, - BluetoothDevice device, int prevState, int newState, ParcelFileDescriptor fd, - int channelId) { - Log.d(TAG, "onHealthChannelStateChange: " + config + "Device: " + device - + "prevState:" + prevState + "newState:" + newState + "ParcelFd:" + fd - + "ChannelId:" + channelId); - } -} diff --git a/core/java/android/bluetooth/BluetoothHearingAid.java b/core/java/android/bluetooth/BluetoothHearingAid.java deleted file mode 100644 index 339a75fe0fbe4d21eccbac01ecc9c6527d5bc994..0000000000000000000000000000000000000000 --- a/core/java/android/bluetooth/BluetoothHearingAid.java +++ /dev/null @@ -1,691 +0,0 @@ -/* - * Copyright 2018 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.bluetooth; - -import static android.bluetooth.BluetoothUtils.getSyncTimeout; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.annotation.RequiresPermission; -import android.annotation.SdkConstant; -import android.annotation.SdkConstant.SdkConstantType; -import android.annotation.SystemApi; -import android.bluetooth.annotations.RequiresBluetoothConnectPermission; -import android.bluetooth.annotations.RequiresLegacyBluetoothAdminPermission; -import android.bluetooth.annotations.RequiresLegacyBluetoothPermission; -import android.compat.annotation.UnsupportedAppUsage; -import android.content.AttributionSource; -import android.content.Context; -import android.os.Build; -import android.os.IBinder; -import android.os.RemoteException; -import android.util.Log; - -import com.android.modules.utils.SynchronousResultReceiver; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.TimeoutException; - -/** - * This class provides the public APIs to control the Hearing Aid profile. - * - *

    BluetoothHearingAid is a proxy object for controlling the Bluetooth Hearing Aid - * Service via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get - * the BluetoothHearingAid proxy object. - * - *

    Android only supports one set of connected Bluetooth Hearing Aid device at a time. Each - * method is protected with its appropriate permission. - */ -public final class BluetoothHearingAid implements BluetoothProfile { - private static final String TAG = "BluetoothHearingAid"; - private static final boolean DBG = true; - private static final boolean VDBG = false; - - /** - * Intent used to broadcast the change in connection state of the Hearing Aid - * profile. Please note that in the binaural case, there will be two different LE devices for - * the left and right side and each device will have their own connection state changes.S - * - *

    This intent will have 3 extras: - *

      - *
    • {@link #EXTRA_STATE} - The current state of the profile.
    • - *
    • {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile.
    • - *
    • {@link BluetoothDevice#EXTRA_DEVICE} - The remote device.
    • - *
    - * - *

    {@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of - * {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING}, - * {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}. - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - public static final String ACTION_CONNECTION_STATE_CHANGED = - "android.bluetooth.hearingaid.profile.action.CONNECTION_STATE_CHANGED"; - - /** - * Intent used to broadcast the selection of a connected device as active. - * - *

    This intent will have one extra: - *

      - *
    • {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. It can - * be null if no device is active.
    • - *
    - * - * @hide - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - public static final String ACTION_ACTIVE_DEVICE_CHANGED = - "android.bluetooth.hearingaid.profile.action.ACTIVE_DEVICE_CHANGED"; - - /** - * This device represents Left Hearing Aid. - * - * @hide - */ - public static final int SIDE_LEFT = IBluetoothHearingAid.SIDE_LEFT; - - /** - * This device represents Right Hearing Aid. - * - * @hide - */ - public static final int SIDE_RIGHT = IBluetoothHearingAid.SIDE_RIGHT; - - /** - * This device is Monaural. - * - * @hide - */ - public static final int MODE_MONAURAL = IBluetoothHearingAid.MODE_MONAURAL; - - /** - * This device is Binaural (should receive only left or right audio). - * - * @hide - */ - public static final int MODE_BINAURAL = IBluetoothHearingAid.MODE_BINAURAL; - - /** - * Indicates the HiSyncID could not be read and is unavailable. - * - * @hide - */ - public static final long HI_SYNC_ID_INVALID = IBluetoothHearingAid.HI_SYNC_ID_INVALID; - - private final BluetoothAdapter mAdapter; - private final AttributionSource mAttributionSource; - private final BluetoothProfileConnector mProfileConnector = - new BluetoothProfileConnector(this, BluetoothProfile.HEARING_AID, - "BluetoothHearingAid", IBluetoothHearingAid.class.getName()) { - @Override - public IBluetoothHearingAid getServiceInterface(IBinder service) { - return IBluetoothHearingAid.Stub.asInterface(service); - } - }; - - /** - * Create a BluetoothHearingAid proxy object for interacting with the local - * Bluetooth Hearing Aid service. - */ - /* package */ BluetoothHearingAid(Context context, ServiceListener listener, - BluetoothAdapter adapter) { - mAdapter = adapter; - mAttributionSource = adapter.getAttributionSource(); - mProfileConnector.connect(context, listener); - } - - /*package*/ void close() { - mProfileConnector.disconnect(); - } - - private IBluetoothHearingAid getService() { - return mProfileConnector.getService(); - } - - /** - * Initiate connection to a profile of the remote bluetooth device. - * - *

    This API returns false in scenarios like the profile on the - * device is already connected or Bluetooth is not turned on. - * When this API returns true, it is guaranteed that - * connection state intent for the profile will be broadcasted with - * the state. Users can get the connection state of the profile - * from this intent. - * - * @param device Remote Bluetooth Device - * @return false on immediate error, true otherwise - * @hide - */ - @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) - public boolean connect(BluetoothDevice device) { - if (DBG) log("connect(" + device + ")"); - final IBluetoothHearingAid service = getService(); - final boolean defaultValue = false; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device)) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.connect(device, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Initiate disconnection from a profile - * - *

    This API will return false in scenarios like the profile on the - * Bluetooth device is not in connected state etc. When this API returns, - * true, it is guaranteed that the connection state change - * intent will be broadcasted with the state. Users can get the - * disconnection state of the profile from this intent. - * - *

    If the disconnection is initiated by a remote device, the state - * will transition from {@link #STATE_CONNECTED} to - * {@link #STATE_DISCONNECTED}. If the disconnect is initiated by the - * host (local) device the state will transition from - * {@link #STATE_CONNECTED} to state {@link #STATE_DISCONNECTING} to - * state {@link #STATE_DISCONNECTED}. The transition to - * {@link #STATE_DISCONNECTING} can be used to distinguish between the - * two scenarios. - * - * @param device Remote Bluetooth Device - * @return false on immediate error, true otherwise - * @hide - */ - @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) - public boolean disconnect(BluetoothDevice device) { - if (DBG) log("disconnect(" + device + ")"); - final IBluetoothHearingAid service = getService(); - final boolean defaultValue = false; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device)) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.disconnect(device, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * {@inheritDoc} - */ - @Override - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public @NonNull List getConnectedDevices() { - if (VDBG) log("getConnectedDevices()"); - final IBluetoothHearingAid service = getService(); - final List defaultValue = new ArrayList(); - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled()) { - try { - final SynchronousResultReceiver> recv = - new SynchronousResultReceiver(); - service.getConnectedDevices(mAttributionSource, recv); - return Attributable.setAttributionSource( - recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue), - mAttributionSource); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * {@inheritDoc} - */ - @Override - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public @NonNull List getDevicesMatchingConnectionStates( - @NonNull int[] states) { - if (VDBG) log("getDevicesMatchingStates()"); - final IBluetoothHearingAid service = getService(); - final List defaultValue = new ArrayList(); - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled()) { - try { - final SynchronousResultReceiver> recv = - new SynchronousResultReceiver(); - service.getDevicesMatchingConnectionStates(states, mAttributionSource, recv); - return Attributable.setAttributionSource( - recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue), - mAttributionSource); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * {@inheritDoc} - */ - @Override - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public @BluetoothProfile.BtProfileState int getConnectionState( - @NonNull BluetoothDevice device) { - if (VDBG) log("getState(" + device + ")"); - final IBluetoothHearingAid service = getService(); - final int defaultValue = BluetoothProfile.STATE_DISCONNECTED; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device)) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.getConnectionState(device, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Select a connected device as active. - * - * The active device selection is per profile. An active device's - * purpose is profile-specific. For example, Hearing Aid audio - * streaming is to the active Hearing Aid device. If a remote device - * is not connected, it cannot be selected as active. - * - *

    This API returns false in scenarios like the profile on the - * device is not connected or Bluetooth is not turned on. - * When this API returns true, it is guaranteed that the - * {@link #ACTION_ACTIVE_DEVICE_CHANGED} intent will be broadcasted - * with the active device. - * - * @param device the remote Bluetooth device. Could be null to clear - * the active device and stop streaming audio to a Bluetooth device. - * @return false on immediate error, true otherwise - * @hide - */ - @RequiresLegacyBluetoothAdminPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public boolean setActiveDevice(@Nullable BluetoothDevice device) { - if (DBG) log("setActiveDevice(" + device + ")"); - final IBluetoothHearingAid service = getService(); - final boolean defaultValue = false; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && ((device == null) || isValidDevice(device))) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.setActiveDevice(device, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Get the connected physical Hearing Aid devices that are active - * - * @return the list of active devices. The first element is the left active - * device; the second element is the right active device. If either or both side - * is not active, it will be null on that position. Returns empty list on error. - * @hide - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public @NonNull List getActiveDevices() { - if (VDBG) log("getActiveDevices()"); - final IBluetoothHearingAid service = getService(); - final List defaultValue = new ArrayList<>(); - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled()) { - try { - final SynchronousResultReceiver> recv = - new SynchronousResultReceiver(); - service.getActiveDevices(mAttributionSource, recv); - return Attributable.setAttributionSource( - recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue), - mAttributionSource); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Set priority of the profile - * - *

    The device should already be paired. - * Priority can be one of {@link #PRIORITY_ON} or {@link #PRIORITY_OFF}, - * - * @param device Paired bluetooth device - * @param priority - * @return true if priority is set, false on error - * @hide - */ - @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) - public boolean setPriority(BluetoothDevice device, int priority) { - if (DBG) log("setPriority(" + device + ", " + priority + ")"); - return setConnectionPolicy(device, BluetoothAdapter.priorityToConnectionPolicy(priority)); - } - - /** - * Set connection policy of the profile - * - *

    The device should already be paired. - * Connection policy can be one of {@link #CONNECTION_POLICY_ALLOWED}, - * {@link #CONNECTION_POLICY_FORBIDDEN}, {@link #CONNECTION_POLICY_UNKNOWN} - * - * @param device Paired bluetooth device - * @param connectionPolicy is the connection policy to set to for this profile - * @return true if connectionPolicy is set, false on error - * @hide - */ - @SystemApi - @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) - public boolean setConnectionPolicy(@NonNull BluetoothDevice device, - @ConnectionPolicy int connectionPolicy) { - if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")"); - verifyDeviceNotNull(device, "setConnectionPolicy"); - final IBluetoothHearingAid service = getService(); - final boolean defaultValue = false; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device) - && (connectionPolicy == BluetoothProfile.CONNECTION_POLICY_FORBIDDEN - || connectionPolicy == BluetoothProfile.CONNECTION_POLICY_ALLOWED)) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.setConnectionPolicy(device, connectionPolicy, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Get the priority of the profile. - * - *

    The priority can be any of: - * {@link #PRIORITY_OFF}, {@link #PRIORITY_ON}, {@link #PRIORITY_UNDEFINED} - * - * @param device Bluetooth device - * @return priority of the device - * @hide - */ - @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) - public int getPriority(BluetoothDevice device) { - if (VDBG) log("getPriority(" + device + ")"); - return BluetoothAdapter.connectionPolicyToPriority(getConnectionPolicy(device)); - } - - /** - * Get the connection policy of the profile. - * - *

    The connection policy can be any of: - * {@link #CONNECTION_POLICY_ALLOWED}, {@link #CONNECTION_POLICY_FORBIDDEN}, - * {@link #CONNECTION_POLICY_UNKNOWN} - * - * @param device Bluetooth device - * @return connection policy of the device - * @hide - */ - @SystemApi - @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) - public @ConnectionPolicy int getConnectionPolicy(@NonNull BluetoothDevice device) { - if (VDBG) log("getConnectionPolicy(" + device + ")"); - verifyDeviceNotNull(device, "getConnectionPolicy"); - final IBluetoothHearingAid service = getService(); - final int defaultValue = BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device)) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.getConnectionPolicy(device, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Helper for converting a state to a string. - * - * For debug use only - strings are not internationalized. - * - * @hide - */ - public static String stateToString(int state) { - switch (state) { - case STATE_DISCONNECTED: - return "disconnected"; - case STATE_CONNECTING: - return "connecting"; - case STATE_CONNECTED: - return "connected"; - case STATE_DISCONNECTING: - return "disconnecting"; - default: - return ""; - } - } - - /** - * Tells remote device to set an absolute volume. - * - * @param volume Absolute volume to be set on remote - * @hide - */ - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public void setVolume(int volume) { - if (DBG) Log.d(TAG, "setVolume(" + volume + ")"); - final IBluetoothHearingAid service = getService(); - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled()) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.setVolume(volume, mAttributionSource, recv); - recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(null); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - } - - /** - * Get the HiSyncId (unique hearing aid device identifier) of the device. - * - * HiSyncId documentation - * can be found here - * - * @param device Bluetooth device - * @return the HiSyncId of the device - * @hide - */ - @SystemApi - @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) - public long getHiSyncId(@NonNull BluetoothDevice device) { - if (VDBG) log("getHiSyncId(" + device + ")"); - verifyDeviceNotNull(device, "getConnectionPolicy"); - final IBluetoothHearingAid service = getService(); - final long defaultValue = HI_SYNC_ID_INVALID; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device)) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.getHiSyncId(device, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Get the side of the device. - * - * @param device Bluetooth device. - * @return SIDE_LEFT or SIDE_RIGHT - * @hide - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public int getDeviceSide(BluetoothDevice device) { - if (VDBG) log("getDeviceSide(" + device + ")"); - final IBluetoothHearingAid service = getService(); - final int defaultValue = SIDE_LEFT; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device)) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.getDeviceSide(device, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Get the mode of the device. - * - * @param device Bluetooth device - * @return MODE_MONAURAL or MODE_BINAURAL - * @hide - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public int getDeviceMode(BluetoothDevice device) { - if (VDBG) log("getDeviceMode(" + device + ")"); - final IBluetoothHearingAid service = getService(); - final int defaultValue = MODE_MONAURAL; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device)) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.getDeviceMode(device, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - private boolean isEnabled() { - if (mAdapter.getState() == BluetoothAdapter.STATE_ON) return true; - return false; - } - - private void verifyDeviceNotNull(BluetoothDevice device, String methodName) { - if (device == null) { - Log.e(TAG, methodName + ": device param is null"); - throw new IllegalArgumentException("Device cannot be null"); - } - } - - private boolean isValidDevice(BluetoothDevice device) { - if (device == null) return false; - - if (BluetoothAdapter.checkBluetoothAddress(device.getAddress())) return true; - return false; - } - - private static void log(String msg) { - Log.d(TAG, msg); - } -} diff --git a/core/java/android/bluetooth/BluetoothHidDevice.java b/core/java/android/bluetooth/BluetoothHidDevice.java deleted file mode 100644 index 44a355b5f75c2b1514e9ace95b98e795bb45bf97..0000000000000000000000000000000000000000 --- a/core/java/android/bluetooth/BluetoothHidDevice.java +++ /dev/null @@ -1,848 +0,0 @@ -/* - * Copyright (C) 2016 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.bluetooth; - -import static android.bluetooth.BluetoothUtils.getSyncTimeout; - -import android.Manifest; -import android.annotation.NonNull; -import android.annotation.RequiresPermission; -import android.annotation.SdkConstant; -import android.annotation.SdkConstant.SdkConstantType; -import android.annotation.SystemApi; -import android.bluetooth.annotations.RequiresBluetoothConnectPermission; -import android.bluetooth.annotations.RequiresLegacyBluetoothPermission; -import android.content.AttributionSource; -import android.content.Context; -import android.os.IBinder; -import android.os.RemoteException; -import android.util.Log; - -import com.android.modules.utils.SynchronousResultReceiver; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.Executor; -import java.util.concurrent.TimeoutException; - -/** - * Provides the public APIs to control the Bluetooth HID Device profile. - * - *

    BluetoothHidDevice is a proxy object for controlling the Bluetooth HID Device Service via IPC. - * Use {@link BluetoothAdapter#getProfileProxy} to get the BluetoothHidDevice proxy object. - */ -public final class BluetoothHidDevice implements BluetoothProfile { - private static final String TAG = BluetoothHidDevice.class.getSimpleName(); - private static final boolean DBG = false; - - /** - * Intent used to broadcast the change in connection state of the Input Host profile. - * - *

    This intent will have 3 extras: - * - *

      - *
    • {@link #EXTRA_STATE} - The current state of the profile. - *
    • {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile. - *
    • {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. - *
    - * - *

    {@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of {@link - * #STATE_DISCONNECTED}, {@link #STATE_CONNECTING}, {@link #STATE_CONNECTED}, {@link - * #STATE_DISCONNECTING}. - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - public static final String ACTION_CONNECTION_STATE_CHANGED = - "android.bluetooth.hiddevice.profile.action.CONNECTION_STATE_CHANGED"; - - /** - * Constant representing unspecified HID device subclass. - * - * @see #registerApp (BluetoothHidDeviceAppQosSettings, BluetoothHidDeviceAppQosSettings, - * BluetoothHidDeviceAppQosSettings, Executor, Callback) - */ - public static final byte SUBCLASS1_NONE = (byte) 0x00; - /** - * Constant representing keyboard subclass. - * - * @see #registerApp (BluetoothHidDeviceAppQosSettings, BluetoothHidDeviceAppQosSettings, - * BluetoothHidDeviceAppQosSettings, Executor, Callback) - */ - public static final byte SUBCLASS1_KEYBOARD = (byte) 0x40; - /** - * Constant representing mouse subclass. - * - * @see #registerApp (BluetoothHidDeviceAppQosSettings, BluetoothHidDeviceAppQosSettings, - * BluetoothHidDeviceAppQosSettings, Executor, Callback) - */ - public static final byte SUBCLASS1_MOUSE = (byte) 0x80; - /** - * Constant representing combo keyboard and mouse subclass. - * - * @see #registerApp (BluetoothHidDeviceAppQosSettings, BluetoothHidDeviceAppQosSettings, - * BluetoothHidDeviceAppQosSettings, Executor, Callback) - */ - public static final byte SUBCLASS1_COMBO = (byte) 0xC0; - - /** - * Constant representing uncategorized HID device subclass. - * - * @see #registerApp (BluetoothHidDeviceAppQosSettings, BluetoothHidDeviceAppQosSettings, - * BluetoothHidDeviceAppQosSettings, Executor, Callback) - */ - public static final byte SUBCLASS2_UNCATEGORIZED = (byte) 0x00; - /** - * Constant representing joystick subclass. - * - * @see #registerApp (BluetoothHidDeviceAppQosSettings, BluetoothHidDeviceAppQosSettings, - * BluetoothHidDeviceAppQosSettings, Executor, Callback) - */ - public static final byte SUBCLASS2_JOYSTICK = (byte) 0x01; - /** - * Constant representing gamepad subclass. - * - * @see #registerApp (BluetoothHidDeviceAppQosSettings, BluetoothHidDeviceAppQosSettings, - * BluetoothHidDeviceAppQosSettings, Executor, Callback) - */ - public static final byte SUBCLASS2_GAMEPAD = (byte) 0x02; - /** - * Constant representing remote control subclass. - * - * @see #registerApp (BluetoothHidDeviceAppQosSettings, BluetoothHidDeviceAppQosSettings, - * BluetoothHidDeviceAppQosSettings, Executor, Callback) - */ - public static final byte SUBCLASS2_REMOTE_CONTROL = (byte) 0x03; - /** - * Constant representing sensing device subclass. - * - * @see #registerApp (BluetoothHidDeviceAppQosSettings, BluetoothHidDeviceAppQosSettings, - * BluetoothHidDeviceAppQosSettings, Executor, Callback) - */ - public static final byte SUBCLASS2_SENSING_DEVICE = (byte) 0x04; - /** - * Constant representing digitizer tablet subclass. - * - * @see #registerApp (BluetoothHidDeviceAppQosSettings, BluetoothHidDeviceAppQosSettings, - * BluetoothHidDeviceAppQosSettings, Executor, Callback) - */ - public static final byte SUBCLASS2_DIGITIZER_TABLET = (byte) 0x05; - /** - * Constant representing card reader subclass. - * - * @see #registerApp (BluetoothHidDeviceAppQosSettings, BluetoothHidDeviceAppQosSettings, - * BluetoothHidDeviceAppQosSettings, Executor, Callback) - */ - public static final byte SUBCLASS2_CARD_READER = (byte) 0x06; - - /** - * Constant representing HID Input Report type. - * - * @see Callback#onGetReport(BluetoothDevice, byte, byte, int) - * @see Callback#onSetReport(BluetoothDevice, byte, byte, byte[]) - * @see Callback#onInterruptData(BluetoothDevice, byte, byte[]) - */ - public static final byte REPORT_TYPE_INPUT = (byte) 1; - /** - * Constant representing HID Output Report type. - * - * @see Callback#onGetReport(BluetoothDevice, byte, byte, int) - * @see Callback#onSetReport(BluetoothDevice, byte, byte, byte[]) - * @see Callback#onInterruptData(BluetoothDevice, byte, byte[]) - */ - public static final byte REPORT_TYPE_OUTPUT = (byte) 2; - /** - * Constant representing HID Feature Report type. - * - * @see Callback#onGetReport(BluetoothDevice, byte, byte, int) - * @see Callback#onSetReport(BluetoothDevice, byte, byte, byte[]) - * @see Callback#onInterruptData(BluetoothDevice, byte, byte[]) - */ - public static final byte REPORT_TYPE_FEATURE = (byte) 3; - - /** - * Constant representing success response for Set Report. - * - * @see Callback#onSetReport(BluetoothDevice, byte, byte, byte[]) - */ - public static final byte ERROR_RSP_SUCCESS = (byte) 0; - /** - * Constant representing error response for Set Report due to "not ready". - * - * @see Callback#onSetReport(BluetoothDevice, byte, byte, byte[]) - */ - public static final byte ERROR_RSP_NOT_READY = (byte) 1; - /** - * Constant representing error response for Set Report due to "invalid report ID". - * - * @see Callback#onSetReport(BluetoothDevice, byte, byte, byte[]) - */ - public static final byte ERROR_RSP_INVALID_RPT_ID = (byte) 2; - /** - * Constant representing error response for Set Report due to "unsupported request". - * - * @see Callback#onSetReport(BluetoothDevice, byte, byte, byte[]) - */ - public static final byte ERROR_RSP_UNSUPPORTED_REQ = (byte) 3; - /** - * Constant representing error response for Set Report due to "invalid parameter". - * - * @see Callback#onSetReport(BluetoothDevice, byte, byte, byte[]) - */ - public static final byte ERROR_RSP_INVALID_PARAM = (byte) 4; - /** - * Constant representing error response for Set Report with unknown reason. - * - * @see Callback#onSetReport(BluetoothDevice, byte, byte, byte[]) - */ - public static final byte ERROR_RSP_UNKNOWN = (byte) 14; - - /** - * Constant representing boot protocol mode used set by host. Default is always {@link - * #PROTOCOL_REPORT_MODE} unless notified otherwise. - * - * @see Callback#onSetProtocol(BluetoothDevice, byte) - */ - public static final byte PROTOCOL_BOOT_MODE = (byte) 0; - /** - * Constant representing report protocol mode used set by host. Default is always {@link - * #PROTOCOL_REPORT_MODE} unless notified otherwise. - * - * @see Callback#onSetProtocol(BluetoothDevice, byte) - */ - public static final byte PROTOCOL_REPORT_MODE = (byte) 1; - - /** - * The template class that applications use to call callback functions on events from the HID - * host. Callback functions are wrapped in this class and registered to the Android system - * during app registration. - */ - public abstract static class Callback { - - private static final String TAG = "BluetoothHidDevCallback"; - - /** - * Callback called when application registration state changes. Usually it's called due to - * either {@link BluetoothHidDevice#registerApp (String, String, String, byte, byte[], - * Executor, Callback)} or {@link BluetoothHidDevice#unregisterApp()} , but can be also - * unsolicited in case e.g. Bluetooth was turned off in which case application is - * unregistered automatically. - * - * @param pluggedDevice {@link BluetoothDevice} object which represents host that currently - * has Virtual Cable established with device. Only valid when application is registered, - * can be null. - * @param registered true if application is registered, false - * otherwise. - */ - public void onAppStatusChanged(BluetoothDevice pluggedDevice, boolean registered) { - Log.d( - TAG, - "onAppStatusChanged: pluggedDevice=" - + pluggedDevice - + " registered=" - + registered); - } - - /** - * Callback called when connection state with remote host was changed. Application can - * assume than Virtual Cable is established when called with {@link - * BluetoothProfile#STATE_CONNECTED} state. - * - * @param device {@link BluetoothDevice} object representing host device which connection - * state was changed. - * @param state Connection state as defined in {@link BluetoothProfile}. - */ - public void onConnectionStateChanged(BluetoothDevice device, int state) { - Log.d(TAG, "onConnectionStateChanged: device=" + device + " state=" + state); - } - - /** - * Callback called when GET_REPORT is received from remote host. Should be replied by - * application using {@link BluetoothHidDevice#replyReport(BluetoothDevice, byte, byte, - * byte[])}. - * - * @param type Requested Report Type. - * @param id Requested Report Id, can be 0 if no Report Id are defined in descriptor. - * @param bufferSize Requested buffer size, application shall respond with at least given - * number of bytes. - */ - public void onGetReport(BluetoothDevice device, byte type, byte id, int bufferSize) { - Log.d( - TAG, - "onGetReport: device=" - + device - + " type=" - + type - + " id=" - + id - + " bufferSize=" - + bufferSize); - } - - /** - * Callback called when SET_REPORT is received from remote host. In case received data are - * invalid, application shall respond with {@link - * BluetoothHidDevice#reportError(BluetoothDevice, byte)}. - * - * @param type Report Type. - * @param id Report Id. - * @param data Report data. - */ - public void onSetReport(BluetoothDevice device, byte type, byte id, byte[] data) { - Log.d(TAG, "onSetReport: device=" + device + " type=" + type + " id=" + id); - } - - /** - * Callback called when SET_PROTOCOL is received from remote host. Application shall use - * this information to send only reports valid for given protocol mode. By default, {@link - * BluetoothHidDevice#PROTOCOL_REPORT_MODE} shall be assumed. - * - * @param protocol Protocol Mode. - */ - public void onSetProtocol(BluetoothDevice device, byte protocol) { - Log.d(TAG, "onSetProtocol: device=" + device + " protocol=" + protocol); - } - - /** - * Callback called when report data is received over interrupt channel. Report Type is - * assumed to be {@link BluetoothHidDevice#REPORT_TYPE_OUTPUT}. - * - * @param reportId Report Id. - * @param data Report data. - */ - public void onInterruptData(BluetoothDevice device, byte reportId, byte[] data) { - Log.d(TAG, "onInterruptData: device=" + device + " reportId=" + reportId); - } - - /** - * Callback called when Virtual Cable is removed. After this callback is received connection - * will be disconnected automatically. - */ - public void onVirtualCableUnplug(BluetoothDevice device) { - Log.d(TAG, "onVirtualCableUnplug: device=" + device); - } - } - - private static class CallbackWrapper extends IBluetoothHidDeviceCallback.Stub { - - private final Executor mExecutor; - private final Callback mCallback; - private final AttributionSource mAttributionSource; - - CallbackWrapper(Executor executor, Callback callback, AttributionSource attributionSource) { - mExecutor = executor; - mCallback = callback; - mAttributionSource = attributionSource; - } - - @Override - public void onAppStatusChanged(BluetoothDevice pluggedDevice, boolean registered) { - Attributable.setAttributionSource(pluggedDevice, mAttributionSource); - final long token = clearCallingIdentity(); - try { - mExecutor.execute(() -> mCallback.onAppStatusChanged(pluggedDevice, registered)); - } finally { - restoreCallingIdentity(token); - } - } - - @Override - public void onConnectionStateChanged(BluetoothDevice device, int state) { - Attributable.setAttributionSource(device, mAttributionSource); - final long token = clearCallingIdentity(); - try { - mExecutor.execute(() -> mCallback.onConnectionStateChanged(device, state)); - } finally { - restoreCallingIdentity(token); - } - } - - @Override - public void onGetReport(BluetoothDevice device, byte type, byte id, int bufferSize) { - Attributable.setAttributionSource(device, mAttributionSource); - final long token = clearCallingIdentity(); - try { - mExecutor.execute(() -> mCallback.onGetReport(device, type, id, bufferSize)); - } finally { - restoreCallingIdentity(token); - } - } - - @Override - public void onSetReport(BluetoothDevice device, byte type, byte id, byte[] data) { - Attributable.setAttributionSource(device, mAttributionSource); - final long token = clearCallingIdentity(); - try { - mExecutor.execute(() -> mCallback.onSetReport(device, type, id, data)); - } finally { - restoreCallingIdentity(token); - } - } - - @Override - public void onSetProtocol(BluetoothDevice device, byte protocol) { - Attributable.setAttributionSource(device, mAttributionSource); - final long token = clearCallingIdentity(); - try { - mExecutor.execute(() -> mCallback.onSetProtocol(device, protocol)); - } finally { - restoreCallingIdentity(token); - } - } - - @Override - public void onInterruptData(BluetoothDevice device, byte reportId, byte[] data) { - Attributable.setAttributionSource(device, mAttributionSource); - final long token = clearCallingIdentity(); - try { - mExecutor.execute(() -> mCallback.onInterruptData(device, reportId, data)); - } finally { - restoreCallingIdentity(token); - } - } - - @Override - public void onVirtualCableUnplug(BluetoothDevice device) { - Attributable.setAttributionSource(device, mAttributionSource); - final long token = clearCallingIdentity(); - try { - mExecutor.execute(() -> mCallback.onVirtualCableUnplug(device)); - } finally { - restoreCallingIdentity(token); - } - } - } - - private final BluetoothAdapter mAdapter; - private final AttributionSource mAttributionSource; - private final BluetoothProfileConnector mProfileConnector = - new BluetoothProfileConnector(this, BluetoothProfile.HID_DEVICE, - "BluetoothHidDevice", IBluetoothHidDevice.class.getName()) { - @Override - public IBluetoothHidDevice getServiceInterface(IBinder service) { - return IBluetoothHidDevice.Stub.asInterface(service); - } - }; - - BluetoothHidDevice(Context context, ServiceListener listener, BluetoothAdapter adapter) { - mAdapter = adapter; - mAttributionSource = adapter.getAttributionSource(); - mProfileConnector.connect(context, listener); - } - - void close() { - mProfileConnector.disconnect(); - } - - private IBluetoothHidDevice getService() { - return mProfileConnector.getService(); - } - - /** {@inheritDoc} */ - @Override - @RequiresBluetoothConnectPermission - @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT) - public List getConnectedDevices() { - final IBluetoothHidDevice service = getService(); - final List defaultValue = new ArrayList<>(); - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled()) { - try { - final SynchronousResultReceiver> recv = - new SynchronousResultReceiver(); - service.getConnectedDevices(mAttributionSource, recv); - return Attributable.setAttributionSource( - recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue), - mAttributionSource); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** {@inheritDoc} */ - @Override - @RequiresBluetoothConnectPermission - @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT) - public List getDevicesMatchingConnectionStates(int[] states) { - final IBluetoothHidDevice service = getService(); - final List defaultValue = new ArrayList<>(); - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled()) { - try { - final SynchronousResultReceiver> recv = - new SynchronousResultReceiver(); - service.getDevicesMatchingConnectionStates(states, mAttributionSource, recv); - return Attributable.setAttributionSource( - recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue), - mAttributionSource); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** {@inheritDoc} */ - @Override - @RequiresBluetoothConnectPermission - @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT) - public int getConnectionState(BluetoothDevice device) { - final IBluetoothHidDevice service = getService(); - final int defaultValue = STATE_DISCONNECTED; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled()) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.getConnectionState(device, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Registers application to be used for HID device. Connections to HID Device are only possible - * when application is registered. Only one application can be registered at one time. When an - * application is registered, the HID Host service will be disabled until it is unregistered. - * When no longer used, application should be unregistered using {@link #unregisterApp()}. The - * app will be automatically unregistered if it is not foreground. The registration status - * should be tracked by the application by handling callback from Callback#onAppStatusChanged. - * The app registration status is not related to the return value of this method. - * - * @param sdp {@link BluetoothHidDeviceAppSdpSettings} object of HID Device SDP record. The HID - * Device SDP record is required. - * @param inQos {@link BluetoothHidDeviceAppQosSettings} object of Incoming QoS Settings. The - * Incoming QoS Settings is not required. Use null or default - * BluetoothHidDeviceAppQosSettings.Builder for default values. - * @param outQos {@link BluetoothHidDeviceAppQosSettings} object of Outgoing QoS Settings. The - * Outgoing QoS Settings is not required. Use null or default - * BluetoothHidDeviceAppQosSettings.Builder for default values. - * @param executor {@link Executor} object on which callback will be executed. The Executor - * object is required. - * @param callback {@link Callback} object to which callback messages will be sent. The Callback - * 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, - BluetoothHidDeviceAppQosSettings inQos, - BluetoothHidDeviceAppQosSettings outQos, - Executor executor, - Callback callback) { - boolean result = false; - - if (sdp == null) { - throw new IllegalArgumentException("sdp parameter cannot be null"); - } - - if (executor == null) { - throw new IllegalArgumentException("executor parameter cannot be null"); - } - - if (callback == null) { - throw new IllegalArgumentException("callback parameter cannot be null"); - } - - final IBluetoothHidDevice service = getService(); - final boolean defaultValue = result; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled()) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - CallbackWrapper cbw = new CallbackWrapper(executor, callback, mAttributionSource); - service.registerApp(sdp, inQos, outQos, cbw, mAttributionSource, recv); - result = recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Unregisters application. Active connection will be disconnected and no new connections will - * be allowed until registered again using {@link #registerApp - * (BluetoothHidDeviceAppQosSettings, BluetoothHidDeviceAppQosSettings, - * BluetoothHidDeviceAppQosSettings, Executor, Callback)}. The registration status should be - * tracked by the application by handling callback from Callback#onAppStatusChanged. The app - * registration status is not related to the return value of this method. - * - * @return true if the command is successfully sent; otherwise false. - */ - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public boolean unregisterApp() { - final IBluetoothHidDevice service = getService(); - final boolean defaultValue = false; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled()) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.unregisterApp(mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Sends report to remote host using interrupt channel. - * - * @param id Report Id, as defined in descriptor. Can be 0 in case Report Id are not defined in - * descriptor. - * @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) { - final IBluetoothHidDevice service = getService(); - final boolean defaultValue = false; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled()) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.sendReport(device, id, data, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Sends report to remote host as reply for GET_REPORT request from {@link - * Callback#onGetReport(BluetoothDevice, byte, byte, int)}. - * - * @param type Report Type, as in request. - * @param id Report Id, as in request. - * @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) { - final IBluetoothHidDevice service = getService(); - final boolean defaultValue = false; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled()) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.replyReport(device, type, id, data, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Sends error handshake message as reply for invalid SET_REPORT request from {@link - * Callback#onSetReport(BluetoothDevice, byte, byte, byte[])}. - * - * @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) { - final IBluetoothHidDevice service = getService(); - final boolean defaultValue = false; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled()) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.reportError(device, error, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Gets the application name of the current HidDeviceService user. - * - * @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(); - final String defaultValue = ""; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled()) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.getUserAppName(mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Initiates connection to host which is currently paired with this device. If the application - * is not registered, #connect(BluetoothDevice) will fail. The connection state should be - * tracked by the application by handling callback from Callback#onConnectionStateChanged. The - * connection state is not related to the return value of this method. - * - * @return true if the command is successfully sent; otherwise false. - */ - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public boolean connect(BluetoothDevice device) { - final IBluetoothHidDevice service = getService(); - final boolean defaultValue = false; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device)) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.connect(device, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Disconnects from currently connected host. The connection state should be tracked by the - * application by handling callback from Callback#onConnectionStateChanged. The connection state - * is not related to the return value of this method. - * - * @return true if the command is successfully sent; otherwise false. - */ - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public boolean disconnect(BluetoothDevice device) { - final IBluetoothHidDevice service = getService(); - final boolean defaultValue = false; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled()) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.disconnect(device, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Connects Hid Device if connectionPolicy is {@link BluetoothProfile#CONNECTION_POLICY_ALLOWED} - * and disconnects Hid device if connectionPolicy is - * {@link BluetoothProfile#CONNECTION_POLICY_FORBIDDEN}. - * - *

    The device should already be paired. - * Connection policy can be one of: - * {@link BluetoothProfile#CONNECTION_POLICY_ALLOWED}, - * {@link BluetoothProfile#CONNECTION_POLICY_FORBIDDEN}, - * {@link BluetoothProfile#CONNECTION_POLICY_UNKNOWN} - * - * @param device Paired bluetooth device - * @param connectionPolicy determines whether hid device should be connected or disconnected - * @return true if hid device is connected or disconnected, false otherwise - * - * @hide - */ - @SystemApi - @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) - public boolean setConnectionPolicy(@NonNull BluetoothDevice device, - @ConnectionPolicy int connectionPolicy) { - if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")"); - final IBluetoothHidDevice service = getService(); - final boolean defaultValue = false; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device) - && (connectionPolicy == BluetoothProfile.CONNECTION_POLICY_FORBIDDEN - || connectionPolicy == BluetoothProfile.CONNECTION_POLICY_ALLOWED)) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.setConnectionPolicy(device, connectionPolicy, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - private boolean isEnabled() { - if (mAdapter.getState() == BluetoothAdapter.STATE_ON) return true; - return false; - } - - private boolean isValidDevice(BluetoothDevice device) { - if (device == null) return false; - - if (BluetoothAdapter.checkBluetoothAddress(device.getAddress())) return true; - return false; - } - - private static void log(String msg) { - if (DBG) { - Log.d(TAG, msg); - } - } -} diff --git a/core/java/android/bluetooth/BluetoothHidDeviceAppQosSettings.java b/core/java/android/bluetooth/BluetoothHidDeviceAppQosSettings.java deleted file mode 100644 index b21ebe59d816964ffa52a2b8a2f8263a3c602b7d..0000000000000000000000000000000000000000 --- a/core/java/android/bluetooth/BluetoothHidDeviceAppQosSettings.java +++ /dev/null @@ -1,131 +0,0 @@ -/* - * Copyright (C) 2016 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.bluetooth; - -import android.os.Parcel; -import android.os.Parcelable; - -/** - * Represents the Quality of Service (QoS) settings for a Bluetooth HID Device application. - * - *

    The BluetoothHidDevice framework will update the L2CAP QoS settings for the app during - * registration. - * - *

    {@see BluetoothHidDevice} - */ -public final class BluetoothHidDeviceAppQosSettings implements Parcelable { - - private final int mServiceType; - private final int mTokenRate; - private final int mTokenBucketSize; - private final int mPeakBandwidth; - private final int mLatency; - private final int mDelayVariation; - - public static final int SERVICE_NO_TRAFFIC = 0x00; - public static final int SERVICE_BEST_EFFORT = 0x01; - public static final int SERVICE_GUARANTEED = 0x02; - - public static final int MAX = (int) 0xffffffff; - - /** - * Create a BluetoothHidDeviceAppQosSettings object for the Bluetooth L2CAP channel. The QoS - * Settings is optional. Please refer to Bluetooth HID Specfication v1.1.1 Section 5.2 and - * Appendix D for parameters. - * - * @param serviceType L2CAP service type, default = SERVICE_BEST_EFFORT - * @param tokenRate L2CAP token rate, default = 0 - * @param tokenBucketSize L2CAP token bucket size, default = 0 - * @param peakBandwidth L2CAP peak bandwidth, default = 0 - * @param latency L2CAP latency, default = MAX - * @param delayVariation L2CAP delay variation, default = MAX - */ - public BluetoothHidDeviceAppQosSettings( - int serviceType, - int tokenRate, - int tokenBucketSize, - int peakBandwidth, - int latency, - int delayVariation) { - mServiceType = serviceType; - mTokenRate = tokenRate; - mTokenBucketSize = tokenBucketSize; - mPeakBandwidth = peakBandwidth; - mLatency = latency; - mDelayVariation = delayVariation; - } - - public int getServiceType() { - return mServiceType; - } - - public int getTokenRate() { - return mTokenRate; - } - - public int getTokenBucketSize() { - return mTokenBucketSize; - } - - public int getPeakBandwidth() { - return mPeakBandwidth; - } - - public int getLatency() { - return mLatency; - } - - public int getDelayVariation() { - return mDelayVariation; - } - - @Override - public int describeContents() { - return 0; - } - - public static final @android.annotation.NonNull Parcelable.Creator CREATOR = - new Parcelable.Creator() { - - @Override - public BluetoothHidDeviceAppQosSettings createFromParcel(Parcel in) { - - return new BluetoothHidDeviceAppQosSettings( - in.readInt(), - in.readInt(), - in.readInt(), - in.readInt(), - in.readInt(), - in.readInt()); - } - - @Override - public BluetoothHidDeviceAppQosSettings[] newArray(int size) { - return new BluetoothHidDeviceAppQosSettings[size]; - } - }; - - @Override - public void writeToParcel(Parcel out, int flags) { - out.writeInt(mServiceType); - out.writeInt(mTokenRate); - out.writeInt(mTokenBucketSize); - out.writeInt(mPeakBandwidth); - out.writeInt(mLatency); - out.writeInt(mDelayVariation); - } -} diff --git a/core/java/android/bluetooth/BluetoothHidDeviceAppSdpSettings.java b/core/java/android/bluetooth/BluetoothHidDeviceAppSdpSettings.java deleted file mode 100644 index 4e1a2aaedcf0b7f46aa867cd1ddc7679994b84ea..0000000000000000000000000000000000000000 --- a/core/java/android/bluetooth/BluetoothHidDeviceAppSdpSettings.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright (C) 2016 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.bluetooth; - -import android.os.Parcel; -import android.os.Parcelable; -import android.util.EventLog; - - -/** - * Represents the Service Discovery Protocol (SDP) settings for a Bluetooth HID Device application. - * - *

    The BluetoothHidDevice framework adds the SDP record during app registration, so that the - * Android device can be discovered as a Bluetooth HID Device. - * - *

    {@see BluetoothHidDevice} - */ -public final class BluetoothHidDeviceAppSdpSettings implements Parcelable { - - private static final int MAX_DESCRIPTOR_SIZE = 2048; - - private final String mName; - private final String mDescription; - private final String mProvider; - private final byte mSubclass; - private final byte[] mDescriptors; - - /** - * Create a BluetoothHidDeviceAppSdpSettings object for the Bluetooth SDP record. - * - * @param name Name of this Bluetooth HID device. Maximum length is 50 bytes. - * @param description Description for this Bluetooth HID device. Maximum length is 50 bytes. - * @param provider Provider of this Bluetooth HID device. Maximum length is 50 bytes. - * @param subclass Subclass of this Bluetooth HID device. See - * www.usb.org/developers/hidpage/HID1_11.pdf Section 4.2 - * @param descriptors Descriptors of this Bluetooth HID device. See - * www.usb.org/developers/hidpage/HID1_11.pdf Chapter 6 Maximum length is 2048 bytes. - */ - public BluetoothHidDeviceAppSdpSettings( - String name, String description, String provider, byte subclass, byte[] descriptors) { - mName = name; - mDescription = description; - mProvider = provider; - mSubclass = subclass; - - if (descriptors == null || descriptors.length > MAX_DESCRIPTOR_SIZE) { - EventLog.writeEvent(0x534e4554, "119819889", -1, ""); - throw new IllegalArgumentException("descriptors must be not null and shorter than " - + MAX_DESCRIPTOR_SIZE); - } - mDescriptors = descriptors.clone(); - } - - public String getName() { - return mName; - } - - public String getDescription() { - return mDescription; - } - - public String getProvider() { - return mProvider; - } - - public byte getSubclass() { - return mSubclass; - } - - public byte[] getDescriptors() { - return mDescriptors; - } - - @Override - public int describeContents() { - return 0; - } - - public static final @android.annotation.NonNull Parcelable.Creator CREATOR = - new Parcelable.Creator() { - - @Override - public BluetoothHidDeviceAppSdpSettings createFromParcel(Parcel in) { - - return new BluetoothHidDeviceAppSdpSettings( - in.readString(), - in.readString(), - in.readString(), - in.readByte(), - in.createByteArray()); - } - - @Override - public BluetoothHidDeviceAppSdpSettings[] newArray(int size) { - return new BluetoothHidDeviceAppSdpSettings[size]; - } - }; - - @Override - public void writeToParcel(Parcel out, int flags) { - out.writeString(mName); - out.writeString(mDescription); - out.writeString(mProvider); - out.writeByte(mSubclass); - out.writeByteArray(mDescriptors); - } -} diff --git a/core/java/android/bluetooth/BluetoothHidHost.java b/core/java/android/bluetooth/BluetoothHidHost.java deleted file mode 100644 index ecbeddf2b85321fb8641c071f9578b111d8e96de..0000000000000000000000000000000000000000 --- a/core/java/android/bluetooth/BluetoothHidHost.java +++ /dev/null @@ -1,831 +0,0 @@ -/* - * Copyright (C) 2011 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.bluetooth; - -import static android.bluetooth.BluetoothUtils.getSyncTimeout; - -import android.Manifest; -import android.annotation.NonNull; -import android.annotation.RequiresPermission; -import android.annotation.SdkConstant; -import android.annotation.SdkConstant.SdkConstantType; -import android.annotation.SuppressLint; -import android.annotation.SystemApi; -import android.bluetooth.annotations.RequiresBluetoothConnectPermission; -import android.bluetooth.annotations.RequiresLegacyBluetoothAdminPermission; -import android.bluetooth.annotations.RequiresLegacyBluetoothPermission; -import android.content.AttributionSource; -import android.content.Context; -import android.os.IBinder; -import android.os.RemoteException; -import android.util.Log; - -import com.android.modules.utils.SynchronousResultReceiver; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.TimeoutException; - - -/** - * This class provides the public APIs to control the Bluetooth Input - * Device Profile. - * - *

    BluetoothHidHost is a proxy object for controlling the Bluetooth - * Service via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get - * the BluetoothHidHost proxy object. - * - *

    Each method is protected with its appropriate permission. - * - * @hide - */ -@SystemApi -public final class BluetoothHidHost implements BluetoothProfile { - private static final String TAG = "BluetoothHidHost"; - private static final boolean DBG = true; - private static final boolean VDBG = false; - - /** - * Intent used to broadcast the change in connection state of the Input - * Device profile. - * - *

    This intent will have 3 extras: - *

      - *
    • {@link #EXTRA_STATE} - The current state of the profile.
    • - *
    • {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile.
    • - *
    • {@link BluetoothDevice#EXTRA_DEVICE} - The remote device.
    • - *
    - * - *

    {@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of - * {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING}, - * {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}. - */ - @SuppressLint("ActionValue") - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - public static final String ACTION_CONNECTION_STATE_CHANGED = - "android.bluetooth.input.profile.action.CONNECTION_STATE_CHANGED"; - - /** - * @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"; - - /** - * @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"; - - /** - * @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"; - - /** - * @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"; - - /** - * @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"; - - /** - * Return codes for the connect and disconnect Bluez / Dbus calls. - * - * @hide - */ - public static final int INPUT_DISCONNECT_FAILED_NOT_CONNECTED = 5000; - - /** - * @hide - */ - public static final int INPUT_CONNECT_FAILED_ALREADY_CONNECTED = 5001; - - /** - * @hide - */ - public static final int INPUT_CONNECT_FAILED_ATTEMPT_FAILED = 5002; - - /** - * @hide - */ - public static final int INPUT_OPERATION_GENERIC_FAILURE = 5003; - - /** - * @hide - */ - public static final int INPUT_OPERATION_SUCCESS = 5004; - - /** - * @hide - */ - public static final int PROTOCOL_REPORT_MODE = 0; - - /** - * @hide - */ - public static final int PROTOCOL_BOOT_MODE = 1; - - /** - * @hide - */ - public static final int PROTOCOL_UNSUPPORTED_MODE = 255; - - /* int reportType, int reportType, int bufferSize */ - /** - * @hide - */ - public static final byte REPORT_TYPE_INPUT = 1; - - /** - * @hide - */ - public static final byte REPORT_TYPE_OUTPUT = 2; - - /** - * @hide - */ - public static final byte REPORT_TYPE_FEATURE = 3; - - /** - * @hide - */ - public static final int VIRTUAL_UNPLUG_STATUS_SUCCESS = 0; - - /** - * @hide - */ - public static final int VIRTUAL_UNPLUG_STATUS_FAIL = 1; - - /** - * @hide - */ - public static final String EXTRA_PROTOCOL_MODE = - "android.bluetooth.BluetoothHidHost.extra.PROTOCOL_MODE"; - - /** - * @hide - */ - public static final String EXTRA_REPORT_TYPE = - "android.bluetooth.BluetoothHidHost.extra.REPORT_TYPE"; - - /** - * @hide - */ - public static final String EXTRA_REPORT_ID = - "android.bluetooth.BluetoothHidHost.extra.REPORT_ID"; - - /** - * @hide - */ - public static final String EXTRA_REPORT_BUFFER_SIZE = - "android.bluetooth.BluetoothHidHost.extra.REPORT_BUFFER_SIZE"; - - /** - * @hide - */ - public static final String EXTRA_REPORT = "android.bluetooth.BluetoothHidHost.extra.REPORT"; - - /** - * @hide - */ - public static final String EXTRA_STATUS = "android.bluetooth.BluetoothHidHost.extra.STATUS"; - - /** - * @hide - */ - public static final String EXTRA_VIRTUAL_UNPLUG_STATUS = - "android.bluetooth.BluetoothHidHost.extra.VIRTUAL_UNPLUG_STATUS"; - - /** - * @hide - */ - public static final String EXTRA_IDLE_TIME = - "android.bluetooth.BluetoothHidHost.extra.IDLE_TIME"; - - private final BluetoothAdapter mAdapter; - private final AttributionSource mAttributionSource; - private final BluetoothProfileConnector mProfileConnector = - new BluetoothProfileConnector(this, BluetoothProfile.HID_HOST, - "BluetoothHidHost", IBluetoothHidHost.class.getName()) { - @Override - public IBluetoothHidHost getServiceInterface(IBinder service) { - return IBluetoothHidHost.Stub.asInterface(service); - } - }; - - /** - * Create a BluetoothHidHost proxy object for interacting with the local - * Bluetooth Service which handles the InputDevice profile - */ - /* package */ BluetoothHidHost(Context context, ServiceListener listener, - BluetoothAdapter adapter) { - mAdapter = adapter; - mAttributionSource = adapter.getAttributionSource(); - mProfileConnector.connect(context, listener); - } - - /*package*/ void close() { - if (VDBG) log("close()"); - mProfileConnector.disconnect(); - } - - private IBluetoothHidHost getService() { - return mProfileConnector.getService(); - } - - /** - * Initiate connection to a profile of the remote bluetooth device. - * - *

    The system supports connection to multiple input devices. - * - *

    This API returns false in scenarios like the profile on the - * device is already connected or Bluetooth is not turned on. - * When this API returns true, it is guaranteed that - * connection state intent for the profile will be broadcasted with - * the state. Users can get the connection state of the profile - * from this intent. - * - * @param device Remote Bluetooth Device - * @return false on immediate error, true otherwise - * @hide - */ - @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) - public boolean connect(BluetoothDevice device) { - if (DBG) log("connect(" + device + ")"); - final IBluetoothHidHost service = getService(); - final boolean defaultValue = false; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device)) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.connect(device, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Initiate disconnection from a profile - * - *

    This API will return false in scenarios like the profile on the - * Bluetooth device is not in connected state etc. When this API returns, - * true, it is guaranteed that the connection state change - * intent will be broadcasted with the state. Users can get the - * disconnection state of the profile from this intent. - * - *

    If the disconnection is initiated by a remote device, the state - * will transition from {@link #STATE_CONNECTED} to - * {@link #STATE_DISCONNECTED}. If the disconnect is initiated by the - * host (local) device the state will transition from - * {@link #STATE_CONNECTED} to state {@link #STATE_DISCONNECTING} to - * state {@link #STATE_DISCONNECTED}. The transition to - * {@link #STATE_DISCONNECTING} can be used to distinguish between the - * two scenarios. - * - * @param device Remote Bluetooth Device - * @return false on immediate error, true otherwise - * @hide - */ - @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) - public boolean disconnect(BluetoothDevice device) { - if (DBG) log("disconnect(" + device + ")"); - final IBluetoothHidHost service = getService(); - final boolean defaultValue = false; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device)) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.disconnect(device, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * {@inheritDoc} - * - * @hide - */ - @SystemApi - @Override - @RequiresBluetoothConnectPermission - @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT) - public @NonNull List getConnectedDevices() { - if (VDBG) log("getConnectedDevices()"); - final IBluetoothHidHost service = getService(); - final List defaultValue = new ArrayList(); - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled()) { - try { - final SynchronousResultReceiver> recv = - new SynchronousResultReceiver(); - service.getConnectedDevices(mAttributionSource, recv); - return Attributable.setAttributionSource( - recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue), - mAttributionSource); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * {@inheritDoc} - * - * @hide - */ - @Override - @RequiresBluetoothConnectPermission - @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT) - public List getDevicesMatchingConnectionStates(int[] states) { - if (VDBG) log("getDevicesMatchingStates()"); - final IBluetoothHidHost service = getService(); - final List defaultValue = new ArrayList(); - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled()) { - try { - final SynchronousResultReceiver> recv = - new SynchronousResultReceiver(); - service.getDevicesMatchingConnectionStates(states, mAttributionSource, recv); - return Attributable.setAttributionSource( - recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue), - mAttributionSource); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * {@inheritDoc} - * - * @hide - */ - @SystemApi - @Override - @RequiresBluetoothConnectPermission - @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT) - public int getConnectionState(@NonNull BluetoothDevice device) { - if (VDBG) log("getState(" + device + ")"); - if (device == null) { - throw new IllegalArgumentException("device must not be null"); - } - final IBluetoothHidHost service = getService(); - final int defaultValue = BluetoothProfile.STATE_DISCONNECTED; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device)) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.getConnectionState(device, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Set priority of the profile - * - *

    The device should already be paired. - * Priority can be one of {@link #PRIORITY_ON} or {@link #PRIORITY_OFF}, - * - * @param device Paired bluetooth device - * @param priority - * @return true if priority is set, false on error - * @hide - */ - @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) - public boolean setPriority(BluetoothDevice device, int priority) { - if (DBG) log("setPriority(" + device + ", " + priority + ")"); - return setConnectionPolicy(device, BluetoothAdapter.priorityToConnectionPolicy(priority)); - } - - /** - * Set connection policy of the profile - * - *

    The device should already be paired. - * Connection policy can be one of {@link #CONNECTION_POLICY_ALLOWED}, - * {@link #CONNECTION_POLICY_FORBIDDEN}, {@link #CONNECTION_POLICY_UNKNOWN} - * - * @param device Paired bluetooth device - * @param connectionPolicy is the connection policy to set to for this profile - * @return true if connectionPolicy is set, false on error - * @hide - */ - @SystemApi - @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) - public boolean setConnectionPolicy(@NonNull BluetoothDevice device, - @ConnectionPolicy int connectionPolicy) { - if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")"); - if (device == null) { - throw new IllegalArgumentException("device must not be null"); - } - final IBluetoothHidHost service = getService(); - final boolean defaultValue = false; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device) - && (connectionPolicy == BluetoothProfile.CONNECTION_POLICY_FORBIDDEN - || connectionPolicy == BluetoothProfile.CONNECTION_POLICY_ALLOWED)) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.setConnectionPolicy(device, connectionPolicy, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Get the priority of the profile. - * - *

    The priority can be any of: - * {@link #PRIORITY_OFF}, {@link #PRIORITY_ON}, {@link #PRIORITY_UNDEFINED} - * - * @param device Bluetooth device - * @return priority of the device - * @hide - */ - @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) - public int getPriority(BluetoothDevice device) { - if (VDBG) log("getPriority(" + device + ")"); - return BluetoothAdapter.connectionPolicyToPriority(getConnectionPolicy(device)); - } - - /** - * Get the connection policy of the profile. - * - *

    The connection policy can be any of: - * {@link #CONNECTION_POLICY_ALLOWED}, {@link #CONNECTION_POLICY_FORBIDDEN}, - * {@link #CONNECTION_POLICY_UNKNOWN} - * - * @param device Bluetooth device - * @return connection policy of the device - * @hide - */ - @SystemApi - @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) - public @ConnectionPolicy int getConnectionPolicy(@NonNull BluetoothDevice device) { - if (VDBG) log("getConnectionPolicy(" + device + ")"); - if (device == null) { - throw new IllegalArgumentException("device must not be null"); - } - final IBluetoothHidHost service = getService(); - final int defaultValue = BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device)) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.getConnectionPolicy(device, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - private boolean isEnabled() { - return mAdapter.getState() == BluetoothAdapter.STATE_ON; - } - - private static boolean isValidDevice(BluetoothDevice device) { - return device != null && BluetoothAdapter.checkBluetoothAddress(device.getAddress()); - } - - /** - * Initiate virtual unplug for a HID input device. - * - * @param device Remote Bluetooth Device - * @return false on immediate error, true otherwise - * @hide - */ - @RequiresLegacyBluetoothAdminPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public boolean virtualUnplug(BluetoothDevice device) { - if (DBG) log("virtualUnplug(" + device + ")"); - final IBluetoothHidHost service = getService(); - final boolean defaultValue = false; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device)) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.virtualUnplug(device, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Send Get_Protocol_Mode command to the connected HID input device. - * - * @param device Remote Bluetooth Device - * @return false on immediate error, true otherwise - * @hide - */ - @RequiresLegacyBluetoothAdminPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public boolean getProtocolMode(BluetoothDevice device) { - if (VDBG) log("getProtocolMode(" + device + ")"); - final IBluetoothHidHost service = getService(); - final boolean defaultValue = false; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device)) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.getProtocolMode(device, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Send Set_Protocol_Mode command to the connected HID input device. - * - * @param device Remote Bluetooth Device - * @return false on immediate error, true otherwise - * @hide - */ - @RequiresLegacyBluetoothAdminPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public boolean setProtocolMode(BluetoothDevice device, int protocolMode) { - if (DBG) log("setProtocolMode(" + device + ")"); - final IBluetoothHidHost service = getService(); - final boolean defaultValue = false; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device)) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.setProtocolMode(device, protocolMode, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Send Get_Report command to the connected HID input device. - * - * @param device Remote Bluetooth Device - * @param reportType Report type - * @param reportId Report ID - * @param bufferSize Report receiving buffer size - * @return false on immediate error, true otherwise - * @hide - */ - @RequiresLegacyBluetoothAdminPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public boolean getReport(BluetoothDevice device, byte reportType, byte reportId, - int bufferSize) { - if (VDBG) { - log("getReport(" + device + "), reportType=" + reportType + " reportId=" + reportId - + "bufferSize=" + bufferSize); - } - final IBluetoothHidHost service = getService(); - final boolean defaultValue = false; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device)) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.getReport(device, reportType, reportId, bufferSize, mAttributionSource, - recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Send Set_Report command to the connected HID input device. - * - * @param device Remote Bluetooth Device - * @param reportType Report type - * @param report Report receiving buffer size - * @return false on immediate error, true otherwise - * @hide - */ - @RequiresLegacyBluetoothAdminPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public boolean setReport(BluetoothDevice device, byte reportType, String report) { - if (VDBG) log("setReport(" + device + "), reportType=" + reportType + " report=" + report); - final IBluetoothHidHost service = getService(); - final boolean defaultValue = false; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device)) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.setReport(device, reportType, report, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Send Send_Data command to the connected HID input device. - * - * @param device Remote Bluetooth Device - * @param report Report to send - * @return false on immediate error, true otherwise - * @hide - */ - @RequiresLegacyBluetoothAdminPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public boolean sendData(BluetoothDevice device, String report) { - if (DBG) log("sendData(" + device + "), report=" + report); - final IBluetoothHidHost service = getService(); - final boolean defaultValue = false; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device)) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.sendData(device, report, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Send Get_Idle_Time command to the connected HID input device. - * - * @param device Remote Bluetooth Device - * @return false on immediate error, true otherwise - * @hide - */ - @RequiresLegacyBluetoothAdminPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public boolean getIdleTime(BluetoothDevice device) { - if (DBG) log("getIdletime(" + device + ")"); - final IBluetoothHidHost service = getService(); - final boolean defaultValue = false; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device)) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.getIdleTime(device, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Send Set_Idle_Time command to the connected HID input device. - * - * @param device Remote Bluetooth Device - * @param idleTime Idle time to be set on HID Device - * @return false on immediate error, true otherwise - * @hide - */ - @RequiresLegacyBluetoothAdminPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public boolean setIdleTime(BluetoothDevice device, byte idleTime) { - if (DBG) log("setIdletime(" + device + "), idleTime=" + idleTime); - final IBluetoothHidHost service = getService(); - final boolean defaultValue = false; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device)) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.setIdleTime(device, idleTime, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - private static void log(String msg) { - Log.d(TAG, msg); - } -} diff --git a/core/java/android/bluetooth/BluetoothInputStream.java b/core/java/android/bluetooth/BluetoothInputStream.java deleted file mode 100644 index 95f9229f0446ad07ca74b6a07fbc306cd079dcaa..0000000000000000000000000000000000000000 --- a/core/java/android/bluetooth/BluetoothInputStream.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright (C) 2009 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.bluetooth; - -import android.annotation.SuppressLint; - -import java.io.IOException; -import java.io.InputStream; - -/** - * BluetoothInputStream. - * - * Used to write to a Bluetooth socket. - * - * @hide - */ -@SuppressLint("AndroidFrameworkBluetoothPermission") -/*package*/ final class BluetoothInputStream extends InputStream { - private BluetoothSocket mSocket; - - /*package*/ BluetoothInputStream(BluetoothSocket s) { - mSocket = s; - } - - /** - * Return number of bytes available before this stream will block. - */ - public int available() throws IOException { - return mSocket.available(); - } - - public void close() throws IOException { - mSocket.close(); - } - - /** - * Reads a single byte from this stream and returns it as an integer in the - * range from 0 to 255. Returns -1 if the end of the stream has been - * reached. Blocks until one byte has been read, the end of the source - * stream is detected or an exception is thrown. - * - * @return the byte read or -1 if the end of stream has been reached. - * @throws IOException if the stream is closed or another IOException occurs. - * @since Android 1.5 - */ - public int read() throws IOException { - byte[] b = new byte[1]; - int ret = mSocket.read(b, 0, 1); - if (ret == 1) { - return (int) b[0] & 0xff; - } else { - return -1; - } - } - - /** - * Reads at most {@code length} bytes from this stream and stores them in - * the byte array {@code b} starting at {@code offset}. - * - * @param b the byte array in which to store the bytes read. - * @param offset the initial position in {@code buffer} to store the bytes read from this - * stream. - * @param length the maximum number of bytes to store in {@code b}. - * @return the number of bytes actually read or -1 if the end of the stream has been reached. - * @throws IndexOutOfBoundsException if {@code offset < 0} or {@code length < 0}, or if {@code - * offset + length} is greater than the length of {@code b}. - * @throws IOException if the stream is closed or another IOException occurs. - * @since Android 1.5 - */ - public int read(byte[] b, int offset, int length) throws IOException { - if (b == null) { - throw new NullPointerException("byte array is null"); - } - if ((offset | length) < 0 || length > b.length - offset) { - throw new ArrayIndexOutOfBoundsException("invalid offset or length"); - } - return mSocket.read(b, offset, length); - } -} diff --git a/core/java/android/bluetooth/BluetoothLeAudio.java b/core/java/android/bluetooth/BluetoothLeAudio.java deleted file mode 100644 index 15db686b3be4d62dada60156ec6db0908fcb2c69..0000000000000000000000000000000000000000 --- a/core/java/android/bluetooth/BluetoothLeAudio.java +++ /dev/null @@ -1,829 +0,0 @@ -/* - * Copyright 2020 HIMSA II K/S - www.himsa.com. - * Represented by EHIMA - www.ehima.com - * - * 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.bluetooth; - -import static android.bluetooth.BluetoothUtils.getSyncTimeout; - -import android.Manifest; -import android.annotation.NonNull; -import android.annotation.Nullable; -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.content.AttributionSource; -import android.content.Context; -import android.os.IBinder; -import android.os.RemoteException; -import android.util.CloseGuard; -import android.util.Log; - -import com.android.modules.utils.SynchronousResultReceiver; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.TimeoutException; - -/** - * This class provides the public APIs to control the LeAudio profile. - * - *

    BluetoothLeAudio is a proxy object for controlling the Bluetooth LE Audio - * Service via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get - * the BluetoothLeAudio proxy object. - * - *

    Android only supports one set of connected Bluetooth LeAudio device at a time. Each - * method is protected with its appropriate permission. - */ -public final class BluetoothLeAudio implements BluetoothProfile, AutoCloseable { - private static final String TAG = "BluetoothLeAudio"; - private static final boolean DBG = false; - private static final boolean VDBG = false; - - private CloseGuard mCloseGuard; - - /** - * Intent used to broadcast the change in connection state of the LeAudio - * profile. Please note that in the binaural case, there will be two different LE devices for - * the left and right side and each device will have their own connection state changes. - * - *

    This intent will have 3 extras: - *

      - *
    • {@link #EXTRA_STATE} - The current state of the profile.
    • - *
    • {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile.
    • - *
    • {@link BluetoothDevice#EXTRA_DEVICE} - The remote device.
    • - *
    - * - *

    {@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of - * {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING}, - * {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}. - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - public static final String ACTION_LE_AUDIO_CONNECTION_STATE_CHANGED = - "android.bluetooth.action.LE_AUDIO_CONNECTION_STATE_CHANGED"; - - /** - * Intent used to broadcast the selection of a connected device as active. - * - *

    This intent will have one extra: - *

      - *
    • {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. It can - * be null if no device is active.
    • - *
    - * - * @hide - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - public static final String ACTION_LE_AUDIO_ACTIVE_DEVICE_CHANGED = - "android.bluetooth.action.LE_AUDIO_ACTIVE_DEVICE_CHANGED"; - - /** - * Intent used to broadcast group node status information. - * - *

    This intent will have 3 extra: - *

      - *
    • {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. It can - * be null if no device is active.
    • - *
    • {@link #EXTRA_LE_AUDIO_GROUP_ID} - Group id.
    • - *
    • {@link #EXTRA_LE_AUDIO_GROUP_NODE_STATUS} - Group node status.
    • - *
    - * - * @hide - */ - @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - public static final String ACTION_LE_AUDIO_GROUP_NODE_STATUS_CHANGED = - "android.bluetooth.action.LE_AUDIO_GROUP_NODE_STATUS_CHANGED"; - - - /** - * Intent used to broadcast group status information. - * - *

    This intent will have 4 extra: - *

      - *
    • {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. It can - * be null if no device is active.
    • - *
    • {@link #EXTRA_LE_AUDIO_GROUP_ID} - Group id.
    • - *
    • {@link #EXTRA_LE_AUDIO_GROUP_STATUS} - Group status.
    • - *
    - * - * @hide - */ - @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - public static final String ACTION_LE_AUDIO_GROUP_STATUS_CHANGED = - "android.bluetooth.action.LE_AUDIO_GROUP_STATUS_CHANGED"; - - /** - * Intent used to broadcast group audio configuration changed information. - * - *

    This intent will have 5 extra: - *

      - *
    • {@link #EXTRA_LE_AUDIO_GROUP_ID} - Group id.
    • - *
    • {@link #EXTRA_LE_AUDIO_DIRECTION} - Direction as bit mask.
    • - *
    • {@link #EXTRA_LE_AUDIO_SINK_LOCATION} - Sink location as per Bluetooth Assigned - * Numbers
    • - *
    • {@link #EXTRA_LE_AUDIO_SOURCE_LOCATION} - Source location as per Bluetooth Assigned - * Numbers
    • - *
    • {@link #EXTRA_LE_AUDIO_AVAILABLE_CONTEXTS} - Available contexts for group as per - * Bluetooth Assigned Numbers
    • - *
    - * - * @hide - */ - @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - public static final String ACTION_LE_AUDIO_CONF_CHANGED = - "android.bluetooth.action.LE_AUDIO_CONF_CHANGED"; - - /** - * Indicates unspecified audio content. - * @hide - */ - public static final int CONTEXT_TYPE_UNSPECIFIED = 0x0001; - - /** - * Indicates conversation between humans as, for example, in telephony or video calls. - * @hide - */ - public static final int CONTEXT_TYPE_COMMUNICATION = 0x0002; - - /** - * Indicates media as, for example, in music, public radio, podcast or video soundtrack. - * @hide - */ - public static final int CONTEXT_TYPE_MEDIA = 0x0004; - - /** - * Indicates instructional audio as, for example, in navigation, traffic announcements - * or user guidance. - * @hide - */ - public static final int CONTEXT_TYPE_INSTRUCTIONAL = 0x0008; - - /** - * Indicates attention seeking audio as, for example, in beeps signalling arrival of a message - * or keyboard clicks. - * @hide - */ - public static final int CONTEXT_TYPE_ATTENTION_SEEKING = 0x0010; - - /** - * Indicates immediate alerts as, for example, in a low battery alarm, timer expiry or alarm - * clock. - * @hide - */ - public static final int CONTEXT_TYPE_IMMEDIATE_ALERT = 0x0020; - - /** - * Indicates man machine communication as, for example, with voice recognition or virtual - * assistant. - * @hide - */ - public static final int CONTEXT_TYPE_MAN_MACHINE = 0x0040; - - /** - * Indicates emergency alerts as, for example, with fire alarms or other urgent alerts. - * @hide - */ - public static final int CONTEXT_TYPE_EMERGENCY_ALERT = 0x0080; - - /** - * Indicates ringtone as in a call alert. - * @hide - */ - public static final int CONTEXT_TYPE_RINGTONE = 0x0100; - - /** - * Indicates audio associated with a television program and/or with metadata conforming to the - * Bluetooth Broadcast TV profile. - * @hide - */ - public static final int CONTEXT_TYPE_TV = 0x0200; - - /** - * Indicates audio associated with a low latency live audio stream. - * - * @hide - */ - public static final int CONTEXT_TYPE_LIVE = 0x0400; - - /** - * Indicates audio associated with a video game stream. - * @hide - */ - public static final int CONTEXT_TYPE_GAME = 0x0800; - - /** - * This represents an invalid group ID. - * - * @hide - */ - public static final int GROUP_ID_INVALID = IBluetoothLeAudio.LE_AUDIO_GROUP_ID_INVALID; - - /** - * Contains group id. - * @hide - */ - public static final String EXTRA_LE_AUDIO_GROUP_ID = - "android.bluetooth.extra.LE_AUDIO_GROUP_ID"; - - /** - * Contains group node status, can be any of - *

    - *

      - *
    • {@link #GROUP_NODE_ADDED}
    • - *
    • {@link #GROUP_NODE_REMOVED}
    • - *
    - *

    - * @hide - */ - public static final String EXTRA_LE_AUDIO_GROUP_NODE_STATUS = - "android.bluetooth.extra.LE_AUDIO_GROUP_NODE_STATUS"; - - /** - * Contains group status, can be any of - * - *

    - *

      - *
    • {@link #GROUP_STATUS_ACTIVE}
    • - *
    • {@link #GROUP_STATUS_INACTIVE}
    • - *
    - *

    - * @hide - */ - public static final String EXTRA_LE_AUDIO_GROUP_STATUS = - "android.bluetooth.extra.LE_AUDIO_GROUP_STATUS"; - - /** - * Contains bit mask for direction, bit 0 set when Sink, bit 1 set when Source. - * @hide - */ - public static final String EXTRA_LE_AUDIO_DIRECTION = - "android.bluetooth.extra.LE_AUDIO_DIRECTION"; - - /** - * Contains source location as per Bluetooth Assigned Numbers - * @hide - */ - public static final String EXTRA_LE_AUDIO_SOURCE_LOCATION = - "android.bluetooth.extra.LE_AUDIO_SOURCE_LOCATION"; - - /** - * Contains sink location as per Bluetooth Assigned Numbers - * @hide - */ - public static final String EXTRA_LE_AUDIO_SINK_LOCATION = - "android.bluetooth.extra.LE_AUDIO_SINK_LOCATION"; - - /** - * Contains available context types for group as per Bluetooth Assigned Numbers - * @hide - */ - public static final String EXTRA_LE_AUDIO_AVAILABLE_CONTEXTS = - "android.bluetooth.extra.LE_AUDIO_AVAILABLE_CONTEXTS"; - - private final BluetoothAdapter mAdapter; - private final AttributionSource mAttributionSource; - /** - * Indicating that group is Active ( Audio device is available ) - * @hide - */ - public static final int GROUP_STATUS_ACTIVE = IBluetoothLeAudio.GROUP_STATUS_ACTIVE; - - /** - * Indicating that group is Inactive ( Audio device is not available ) - * @hide - */ - public static final int GROUP_STATUS_INACTIVE = IBluetoothLeAudio.GROUP_STATUS_INACTIVE; - - /** - * Indicating that node has been added to the group. - * @hide - */ - public static final int GROUP_NODE_ADDED = IBluetoothLeAudio.GROUP_NODE_ADDED; - - /** - * Indicating that node has been removed from the group. - * @hide - */ - public static final int GROUP_NODE_REMOVED = IBluetoothLeAudio.GROUP_NODE_REMOVED; - - private final BluetoothProfileConnector mProfileConnector = - new BluetoothProfileConnector(this, BluetoothProfile.LE_AUDIO, "BluetoothLeAudio", - IBluetoothLeAudio.class.getName()) { - @Override - public IBluetoothLeAudio getServiceInterface(IBinder service) { - return IBluetoothLeAudio.Stub.asInterface(service); - } - }; - - /** - * Create a BluetoothLeAudio proxy object for interacting with the local - * Bluetooth LeAudio service. - */ - /* package */ BluetoothLeAudio(Context context, ServiceListener listener, - BluetoothAdapter adapter) { - mAdapter = adapter; - mAttributionSource = adapter.getAttributionSource(); - mProfileConnector.connect(context, listener); - mCloseGuard = new CloseGuard(); - mCloseGuard.open("close"); - } - - /** - * @hide - */ - public void close() { - mProfileConnector.disconnect(); - } - - private IBluetoothLeAudio getService() { - return mProfileConnector.getService(); - } - - protected void finalize() { - if (mCloseGuard != null) { - mCloseGuard.warnIfOpen(); - } - close(); - } - - /** - * Initiate connection to a profile of the remote bluetooth device. - * - *

    This API returns false in scenarios like the profile on the - * device is already connected or Bluetooth is not turned on. - * When this API returns true, it is guaranteed that - * connection state intent for the profile will be broadcasted with - * the state. Users can get the connection state of the profile - * from this intent. - * - * - * @param device Remote Bluetooth Device - * @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 + ")"); - final IBluetoothLeAudio service = getService(); - final boolean defaultValue = false; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (mAdapter.isEnabled() && isValidDevice(device)) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.connect(device, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Initiate disconnection from a profile - * - *

    This API will return false in scenarios like the profile on the - * Bluetooth device is not in connected state etc. When this API returns, - * true, it is guaranteed that the connection state change - * intent will be broadcasted with the state. Users can get the - * disconnection state of the profile from this intent. - * - *

    If the disconnection is initiated by a remote device, the state - * will transition from {@link #STATE_CONNECTED} to - * {@link #STATE_DISCONNECTED}. If the disconnect is initiated by the - * host (local) device the state will transition from - * {@link #STATE_CONNECTED} to state {@link #STATE_DISCONNECTING} to - * state {@link #STATE_DISCONNECTED}. The transition to - * {@link #STATE_DISCONNECTING} can be used to distinguish between the - * two scenarios. - * - * - * @param device Remote Bluetooth Device - * @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 + ")"); - final IBluetoothLeAudio service = getService(); - final boolean defaultValue = false; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (mAdapter.isEnabled() && isValidDevice(device)) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.disconnect(device, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * {@inheritDoc} - */ - @Override - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public @NonNull List getConnectedDevices() { - if (VDBG) log("getConnectedDevices()"); - final IBluetoothLeAudio service = getService(); - final List defaultValue = new ArrayList(); - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (mAdapter.isEnabled()) { - try { - final SynchronousResultReceiver> recv = - new SynchronousResultReceiver(); - service.getConnectedDevices(mAttributionSource, recv); - return Attributable.setAttributionSource( - recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue), - mAttributionSource); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * {@inheritDoc} - */ - @Override - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public @NonNull List getDevicesMatchingConnectionStates( - @NonNull int[] states) { - if (VDBG) log("getDevicesMatchingStates()"); - final IBluetoothLeAudio service = getService(); - final List defaultValue = new ArrayList(); - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (mAdapter.isEnabled()) { - try { - final SynchronousResultReceiver> recv = - new SynchronousResultReceiver(); - service.getDevicesMatchingConnectionStates(states, mAttributionSource, recv); - return Attributable.setAttributionSource( - recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue), - mAttributionSource); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * {@inheritDoc} - */ - @Override - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public @BtProfileState int getConnectionState(@NonNull BluetoothDevice device) { - if (VDBG) log("getState(" + device + ")"); - final IBluetoothLeAudio service = getService(); - final int defaultValue = BluetoothProfile.STATE_DISCONNECTED; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (mAdapter.isEnabled() && isValidDevice(device)) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.getConnectionState(device, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Select a connected device as active. - * - * The active device selection is per profile. An active device's - * purpose is profile-specific. For example, LeAudio audio - * streaming is to the active LeAudio device. If a remote device - * is not connected, it cannot be selected as active. - * - *

    This API returns false in scenarios like the profile on the - * device is not connected or Bluetooth is not turned on. - * When this API returns true, it is guaranteed that the - * {@link #ACTION_LE_AUDIO_ACTIVE_DEVICE_CHANGED} intent will be broadcasted - * with the active device. - * - * - * @param device the remote Bluetooth device. Could be null to clear - * the active device and stop streaming audio to a Bluetooth device. - * @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 + ")"); - final IBluetoothLeAudio service = getService(); - final boolean defaultValue = false; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (mAdapter.isEnabled() && ((device == null) || isValidDevice(device))) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.setActiveDevice(device, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Get the connected LeAudio devices that are active - * - * @return the list of active devices. Returns empty list on error. - * @hide - */ - @NonNull - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public List getActiveDevices() { - if (VDBG) log("getActiveDevice()"); - final IBluetoothLeAudio service = getService(); - final List defaultValue = new ArrayList(); - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (mAdapter.isEnabled()) { - try { - final SynchronousResultReceiver> recv = - new SynchronousResultReceiver(); - service.getActiveDevices(mAttributionSource, recv); - return Attributable.setAttributionSource( - recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue), - mAttributionSource); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Get device group id. Devices with same group id belong to same group (i.e left and right - * earbud) - * @param device LE Audio capable device - * @return group id that this device currently belongs to - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public int getGroupId(@NonNull BluetoothDevice device) { - if (VDBG) log("getGroupId()"); - final IBluetoothLeAudio service = getService(); - final int defaultValue = GROUP_ID_INVALID; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (mAdapter.isEnabled()) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.getGroupId(device, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Set volume for the streaming devices - * - * @param volume volume to set - * @hide - */ - @RequiresBluetoothConnectPermission - @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) - public void setVolume(int volume) { - if (VDBG) log("setVolume(vol: " + volume + " )"); - final IBluetoothLeAudio service = getService(); - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (mAdapter.isEnabled()) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.setVolume(volume, mAttributionSource, recv); - recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(null); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - } - - /** - * Add device to the given group. - * @param group_id group ID the device is being added to - * @param device the active device - * @return true on success, otherwise false - * @hide - */ - @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED - }) - public boolean groupAddNode(int group_id, @NonNull BluetoothDevice device) { - if (VDBG) log("groupAddNode()"); - final IBluetoothLeAudio service = getService(); - final boolean defaultValue = false; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (mAdapter.isEnabled()) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.groupAddNode(group_id, device, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Remove device from a given group. - * @param group_id group ID the device is being removed from - * @param device the active device - * @return true on success, otherwise false - * - * @hide - */ - @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED - }) - public boolean groupRemoveNode(int group_id, @NonNull BluetoothDevice device) { - if (VDBG) log("groupRemoveNode()"); - final IBluetoothLeAudio service = getService(); - final boolean defaultValue = false; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (mAdapter.isEnabled()) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.groupRemoveNode(group_id, device, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Set connection policy of the profile - * - *

    The device should already be paired. - * Connection policy can be one of {@link #CONNECTION_POLICY_ALLOWED}, - * {@link #CONNECTION_POLICY_FORBIDDEN}, {@link #CONNECTION_POLICY_UNKNOWN} - * - * @param device Paired bluetooth device - * @param connectionPolicy is the connection policy to set to for this profile - * @return true if connectionPolicy is set, false on error - * @hide - */ - @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) - public boolean setConnectionPolicy(@NonNull BluetoothDevice device, - @ConnectionPolicy int connectionPolicy) { - if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")"); - final IBluetoothLeAudio service = getService(); - final boolean defaultValue = false; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (mAdapter.isEnabled() && isValidDevice(device) - && (connectionPolicy == BluetoothProfile.CONNECTION_POLICY_FORBIDDEN - || connectionPolicy == BluetoothProfile.CONNECTION_POLICY_ALLOWED)) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.setConnectionPolicy(device, connectionPolicy, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Get the connection policy of the profile. - * - *

    The connection policy can be any of: - * {@link #CONNECTION_POLICY_ALLOWED}, {@link #CONNECTION_POLICY_FORBIDDEN}, - * {@link #CONNECTION_POLICY_UNKNOWN} - * - * @param device Bluetooth device - * @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 + ")"); - final IBluetoothLeAudio service = getService(); - final int defaultValue = BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (mAdapter.isEnabled() && isValidDevice(device)) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.getConnectionPolicy(device, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - - /** - * Helper for converting a state to a string. - * - * For debug use only - strings are not internationalized. - * - * @hide - */ - public static String stateToString(int state) { - switch (state) { - case STATE_DISCONNECTED: - return "disconnected"; - case STATE_CONNECTING: - return "connecting"; - case STATE_CONNECTED: - return "connected"; - case STATE_DISCONNECTING: - return "disconnecting"; - default: - return ""; - } - } - - private boolean isValidDevice(@Nullable BluetoothDevice device) { - if (device == null) return false; - - if (BluetoothAdapter.checkBluetoothAddress(device.getAddress())) return true; - return false; - } - - private static void log(String msg) { - Log.d(TAG, msg); - } -} diff --git a/core/java/android/bluetooth/BluetoothLeAudioCodecConfig.java b/core/java/android/bluetooth/BluetoothLeAudioCodecConfig.java deleted file mode 100644 index dcaf4b682f4422a7971159718ed736bebedd5c7a..0000000000000000000000000000000000000000 --- a/core/java/android/bluetooth/BluetoothLeAudioCodecConfig.java +++ /dev/null @@ -1,129 +0,0 @@ -/* - * 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.bluetooth; - -import android.annotation.IntDef; -import android.annotation.NonNull; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -/** - * Represents the codec configuration for a Bluetooth LE Audio source device. - *

    Contains the source codec type. - *

    The source codec type values are the same as those supported by the - * device hardware. - * - * {@see BluetoothLeAudioCodecConfig} - */ -public final class BluetoothLeAudioCodecConfig { - // Add an entry for each source codec here. - - /** @hide */ - @IntDef(prefix = "SOURCE_CODEC_TYPE_", value = { - SOURCE_CODEC_TYPE_LC3, - SOURCE_CODEC_TYPE_INVALID - }) - @Retention(RetentionPolicy.SOURCE) - public @interface SourceCodecType {}; - - public static final int SOURCE_CODEC_TYPE_LC3 = 0; - public static final int SOURCE_CODEC_TYPE_INVALID = 1000 * 1000; - - /** - * Represents the count of valid source codec types. Can be accessed via - * {@link #getMaxCodecType}. - */ - private static final int SOURCE_CODEC_TYPE_MAX = 1; - - private final @SourceCodecType int mCodecType; - - /** - * Creates a new BluetoothLeAudioCodecConfig. - * - * @param codecType the source codec type - */ - private BluetoothLeAudioCodecConfig(@SourceCodecType int codecType) { - mCodecType = codecType; - } - - @Override - public String toString() { - return "{codecName:" + getCodecName() + "}"; - } - - /** - * Gets the codec type. - * - * @return the codec type - */ - public @SourceCodecType int getCodecType() { - return mCodecType; - } - - /** - * Returns the valid codec types count. - */ - public static int getMaxCodecType() { - return SOURCE_CODEC_TYPE_MAX; - } - - /** - * Gets the codec name. - * - * @return the codec name - */ - public @NonNull String getCodecName() { - switch (mCodecType) { - case SOURCE_CODEC_TYPE_LC3: - return "LC3"; - case SOURCE_CODEC_TYPE_INVALID: - return "INVALID CODEC"; - default: - break; - } - return "UNKNOWN CODEC(" + mCodecType + ")"; - } - - /** - * Builder for {@link BluetoothLeAudioCodecConfig}. - *

    By default, the codec type will be set to - * {@link BluetoothLeAudioCodecConfig#SOURCE_CODEC_TYPE_INVALID} - */ - public static final class Builder { - private int mCodecType = BluetoothLeAudioCodecConfig.SOURCE_CODEC_TYPE_INVALID; - - /** - * Set codec type for Bluetooth codec config. - * - * @param codecType of this codec - * @return the same Builder instance - */ - public @NonNull Builder setCodecType(@SourceCodecType int codecType) { - mCodecType = codecType; - return this; - } - - /** - * Build {@link BluetoothLeAudioCodecConfig}. - * @return new BluetoothLeAudioCodecConfig built - */ - public @NonNull BluetoothLeAudioCodecConfig build() { - return new BluetoothLeAudioCodecConfig(mCodecType); - } - } -} diff --git a/core/java/android/bluetooth/BluetoothLeBroadcast.java b/core/java/android/bluetooth/BluetoothLeBroadcast.java deleted file mode 100644 index fed9f911d5b37df16c75591fd567348b3a23bc73..0000000000000000000000000000000000000000 --- a/core/java/android/bluetooth/BluetoothLeBroadcast.java +++ /dev/null @@ -1,287 +0,0 @@ -/* - * Copyright 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.bluetooth; - -import android.annotation.IntDef; -import android.content.Context; -import android.util.Log; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.util.List; - -/** - * This class provides the public APIs to control the Bluetooth LE Broadcast Source profile. - * - *

    BluetoothLeBroadcast is a proxy object for controlling the Bluetooth LE Broadcast - * Source Service via IPC. Use {@link BluetoothAdapter#getProfileProxy} - * to get the BluetoothLeBroadcast proxy object. - * - * @hide - */ -public final class BluetoothLeBroadcast implements BluetoothProfile { - private static final String TAG = "BluetoothLeBroadcast"; - private static final boolean DBG = true; - private static final boolean VDBG = false; - - /** - * Constants used by the LE Audio Broadcast profile for the Broadcast state - * - * @hide - */ - @IntDef(prefix = {"LE_AUDIO_BROADCAST_STATE_"}, value = { - LE_AUDIO_BROADCAST_STATE_DISABLED, - LE_AUDIO_BROADCAST_STATE_ENABLING, - LE_AUDIO_BROADCAST_STATE_ENABLED, - LE_AUDIO_BROADCAST_STATE_DISABLING, - LE_AUDIO_BROADCAST_STATE_PLAYING, - LE_AUDIO_BROADCAST_STATE_NOT_PLAYING - }) - @Retention(RetentionPolicy.SOURCE) - public @interface LeAudioBroadcastState {} - - /** - * Indicates that LE Audio Broadcast mode is currently disabled - * - * @hide - */ - public static final int LE_AUDIO_BROADCAST_STATE_DISABLED = 10; - - /** - * Indicates that LE Audio Broadcast mode is being enabled - * - * @hide - */ - public static final int LE_AUDIO_BROADCAST_STATE_ENABLING = 11; - - /** - * Indicates that LE Audio Broadcast mode is currently enabled - * - * @hide - */ - public static final int LE_AUDIO_BROADCAST_STATE_ENABLED = 12; - /** - * Indicates that LE Audio Broadcast mode is being disabled - * - * @hide - */ - public static final int LE_AUDIO_BROADCAST_STATE_DISABLING = 13; - - /** - * Indicates that an LE Audio Broadcast mode is currently playing - * - * @hide - */ - public static final int LE_AUDIO_BROADCAST_STATE_PLAYING = 14; - - /** - * Indicates that LE Audio Broadcast is currently not playing - * - * @hide - */ - public static final int LE_AUDIO_BROADCAST_STATE_NOT_PLAYING = 15; - - /** - * Constants used by the LE Audio Broadcast profile for encryption key length - * - * @hide - */ - @IntDef(prefix = {"LE_AUDIO_BROADCAST_ENCRYPTION_KEY_"}, value = { - LE_AUDIO_BROADCAST_ENCRYPTION_KEY_32BIT, - LE_AUDIO_BROADCAST_ENCRYPTION_KEY_128BIT - }) - @Retention(RetentionPolicy.SOURCE) - public @interface LeAudioEncryptionKeyLength {} - - /** - * Indicates that the LE Audio Broadcast encryption key size is 32 bits. - * - * @hide - */ - public static final int LE_AUDIO_BROADCAST_ENCRYPTION_KEY_32BIT = 16; - - /** - * Indicates that the LE Audio Broadcast encryption key size is 128 bits. - * - * @hide - */ - public static final int LE_AUDIO_BROADCAST_ENCRYPTION_KEY_128BIT = 17; - - /** - * Interface for receiving events related to broadcasts - */ - public interface Callback { - /** - * Called when broadcast state has changed - * - * @param prevState broadcast state before the change - * @param newState broadcast state after the change - */ - @LeAudioBroadcastState - void onBroadcastStateChange(int prevState, int newState); - /** - * Called when encryption key has been updated - * - * @param success true if the key was updated successfully, false otherwise - */ - void onEncryptionKeySet(boolean success); - } - - /** - * Create a BluetoothLeBroadcast proxy object for interacting with the local - * LE Audio Broadcast Source service. - * - * @hide - */ - /*package*/ BluetoothLeBroadcast(Context context, - BluetoothProfile.ServiceListener listener) { - } - - /** - * Not supported since LE Audio Broadcasts do not establish a connection - * - * @throws UnsupportedOperationException - * - * @hide - */ - @Override - public int getConnectionState(BluetoothDevice device) { - throw new UnsupportedOperationException( - "LE Audio Broadcasts are not connection-oriented."); - } - - /** - * Not supported since LE Audio Broadcasts do not establish a connection - * - * @throws UnsupportedOperationException - * - * @hide - */ - @Override - public List getDevicesMatchingConnectionStates(int[] states) { - throw new UnsupportedOperationException( - "LE Audio Broadcasts are not connection-oriented."); - } - - /** - * Not supported since LE Audio Broadcasts do not establish a connection - * - * @throws UnsupportedOperationException - * - * @hide - */ - @Override - public List getConnectedDevices() { - throw new UnsupportedOperationException( - "LE Audio Broadcasts are not connection-oriented."); - } - - /** - * Enable LE Audio Broadcast mode. - * - * Generates a new broadcast ID and enables sending of encrypted or unencrypted - * isochronous PDUs - * - * @hide - */ - public int enableBroadcastMode() { - if (DBG) log("enableBroadcastMode"); - return BluetoothStatusCodes.ERROR_LE_AUDIO_BROADCAST_SOURCE_SET_BROADCAST_MODE_FAILED; - } - - /** - * Disable LE Audio Broadcast mode. - * - * @hide - */ - public int disableBroadcastMode() { - if (DBG) log("disableBroadcastMode"); - return BluetoothStatusCodes.ERROR_LE_AUDIO_BROADCAST_SOURCE_SET_BROADCAST_MODE_FAILED; - } - - /** - * Get the current LE Audio broadcast state - * - * @hide - */ - @LeAudioBroadcastState - public int getBroadcastState() { - if (DBG) log("getBroadcastState"); - return LE_AUDIO_BROADCAST_STATE_DISABLED; - } - - /** - * Enable LE Audio broadcast encryption - * - * @param keyLength if useExisting is true, this specifies the length of the key that should - * be generated - * @param useExisting true, if an existing key should be used - * false, if a new key should be generated - * - * @hide - */ - @LeAudioEncryptionKeyLength - public int enableEncryption(boolean useExisting, int keyLength) { - if (DBG) log("enableEncryption useExisting=" + useExisting + " keyLength=" + keyLength); - return BluetoothStatusCodes.ERROR_LE_AUDIO_BROADCAST_SOURCE_ENABLE_ENCRYPTION_FAILED; - } - - /** - * Disable LE Audio broadcast encryption - * - * @param removeExisting true, if the existing key should be removed - * false, otherwise - * - * @hide - */ - public int disableEncryption(boolean removeExisting) { - if (DBG) log("disableEncryption removeExisting=" + removeExisting); - return BluetoothStatusCodes.ERROR_LE_AUDIO_BROADCAST_SOURCE_DISABLE_ENCRYPTION_FAILED; - } - - /** - * Enable or disable LE Audio broadcast encryption - * - * @param key use the provided key if non-null, generate a new key if null - * @param keyLength 0 if encryption is disabled, 4 bytes (low security), - * 16 bytes (high security) - * - * @hide - */ - @LeAudioEncryptionKeyLength - public int setEncryptionKey(byte[] key, int keyLength) { - if (DBG) log("setEncryptionKey key=" + key + " keyLength=" + keyLength); - return BluetoothStatusCodes.ERROR_LE_AUDIO_BROADCAST_SOURCE_SET_ENCRYPTION_KEY_FAILED; - } - - - /** - * Get the encryption key that was set before - * - * @return encryption key as a byte array or null if no encryption key was set - * - * @hide - */ - public byte[] getEncryptionKey() { - if (DBG) log("getEncryptionKey"); - return null; - } - - private static void log(String msg) { - Log.d(TAG, msg); - } -} diff --git a/core/java/android/bluetooth/BluetoothLeBroadcastAssistantCallback.java b/core/java/android/bluetooth/BluetoothLeBroadcastAssistantCallback.java deleted file mode 100644 index b866cce22470aab0223375312a299777b1e88510..0000000000000000000000000000000000000000 --- a/core/java/android/bluetooth/BluetoothLeBroadcastAssistantCallback.java +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Copyright 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.bluetooth; - -import android.annotation.IntDef; -import android.annotation.NonNull; -import android.bluetooth.le.ScanResult; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -/** - * This class provides a set of callbacks that are invoked when scanning for Broadcast Sources is - * offloaded to a Broadcast Assistant. - * - *

    An LE Audio Broadcast Assistant can help a Broadcast Sink to scan for available Broadcast - * Sources. The Broadcast Sink achieves this by offloading the scan to a Broadcast Assistant. This - * is facilitated by the Broadcast Audio Scan Service (BASS). A BASS server is a GATT server that is - * part of the Scan Delegator on a Broadcast Sink. A BASS client instead runs on the Broadcast - * Assistant. - * - *

    Once a GATT connection is established between the BASS client and the BASS server, the - * Broadcast Sink can offload the scans to the Broadcast Assistant. Upon finding new Broadcast - * Sources, the Broadcast Assistant then notifies the Broadcast Sink about these over the - * established GATT connection. The Scan Delegator on the Broadcast Sink can also notify the - * Assistant about changes such as addition and removal of Broadcast Sources. - * - * @hide - */ -public abstract class BluetoothLeBroadcastAssistantCallback { - - /** - * Broadcast Audio Scan Service (BASS) codes returned by a BASS Server - * - * @hide - */ - @IntDef( - prefix = "BASS_STATUS_", - value = { - BASS_STATUS_SUCCESS, - BASS_STATUS_FAILURE, - BASS_STATUS_INVALID_GATT_HANDLE, - BASS_STATUS_TXN_TIMEOUT, - BASS_STATUS_INVALID_SOURCE_ID, - BASS_STATUS_COLOCATED_SRC_UNAVAILABLE, - BASS_STATUS_INVALID_SOURCE_SELECTED, - BASS_STATUS_SOURCE_UNAVAILABLE, - BASS_STATUS_DUPLICATE_ADDITION, - }) - @Retention(RetentionPolicy.SOURCE) - public @interface BassStatus {} - - public static final int BASS_STATUS_SUCCESS = 0x00; - public static final int BASS_STATUS_FAILURE = 0x01; - public static final int BASS_STATUS_INVALID_GATT_HANDLE = 0x02; - public static final int BASS_STATUS_TXN_TIMEOUT = 0x03; - - public static final int BASS_STATUS_INVALID_SOURCE_ID = 0x04; - public static final int BASS_STATUS_COLOCATED_SRC_UNAVAILABLE = 0x05; - public static final int BASS_STATUS_INVALID_SOURCE_SELECTED = 0x06; - public static final int BASS_STATUS_SOURCE_UNAVAILABLE = 0x07; - public static final int BASS_STATUS_DUPLICATE_ADDITION = 0x08; - public static final int BASS_STATUS_NO_EMPTY_SLOT = 0x09; - public static final int BASS_STATUS_INVALID_GROUP_OP = 0x10; - - /** - * Callback invoked when a new LE Audio Broadcast Source is found. - * - * @param result {@link ScanResult} scan result representing a Broadcast Source - */ - public void onBluetoothLeBroadcastSourceFound(@NonNull ScanResult result) {} - - /** - * Callback invoked when the Broadcast Assistant synchronizes with Periodic Advertisements (PAs) - * of an LE Audio Broadcast Source. - * - * @param source the selected Broadcast Source - */ - public void onBluetoothLeBroadcastSourceSelected( - @NonNull BluetoothLeBroadcastSourceInfo source, @BassStatus int status) {} - - /** - * Callback invoked when the Broadcast Assistant loses synchronization with an LE Audio - * Broadcast Source. - * - * @param source the Broadcast Source with which synchronization was lost - */ - public void onBluetoothLeBroadcastSourceLost( - @NonNull BluetoothLeBroadcastSourceInfo source, @BassStatus int status) {} - - /** - * Callback invoked when a new LE Audio Broadcast Source has been successfully added to the Scan - * Delegator (within a Broadcast Sink, for example). - * - * @param sink Scan Delegator device on which a new Broadcast Source has been added - * @param source the added Broadcast Source - */ - public void onBluetoothLeBroadcastSourceAdded( - @NonNull BluetoothDevice sink, - @NonNull BluetoothLeBroadcastSourceInfo source, - @BassStatus int status) {} - - /** - * Callback invoked when an existing LE Audio Broadcast Source within a remote Scan Delegator - * has been updated. - * - * @param sink Scan Delegator device on which a Broadcast Source has been updated - * @param source the updated Broadcast Source - */ - public void onBluetoothLeBroadcastSourceUpdated( - @NonNull BluetoothDevice sink, - @NonNull BluetoothLeBroadcastSourceInfo source, - @BassStatus int status) {} - - /** - * Callback invoked when an LE Audio Broadcast Source has been successfully removed from the - * Scan Delegator (within a Broadcast Sink, for example). - * - * @param sink Scan Delegator device from which a Broadcast Source has been removed - * @param source the removed Broadcast Source - */ - public void onBluetoothLeBroadcastSourceRemoved( - @NonNull BluetoothDevice sink, - @NonNull BluetoothLeBroadcastSourceInfo source, - @BassStatus int status) {} -} diff --git a/core/java/android/bluetooth/BluetoothLeBroadcastSourceInfo.java b/core/java/android/bluetooth/BluetoothLeBroadcastSourceInfo.java deleted file mode 100644 index cb47280acc7ec78e9b7f20322476e41e9334dd5f..0000000000000000000000000000000000000000 --- a/core/java/android/bluetooth/BluetoothLeBroadcastSourceInfo.java +++ /dev/null @@ -1,788 +0,0 @@ -/* - * Copyright 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.bluetooth; - -import android.annotation.IntDef; -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.os.Parcel; -import android.os.Parcelable; -import android.util.Log; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.util.Arrays; -import java.util.HashMap; -import java.util.Map; -import java.util.Objects; - -/** - * This class represents an LE Audio Broadcast Source and the associated information that is needed - * by Broadcast Audio Scan Service (BASS) residing on a Scan Delegator. - * - *

    For example, the Scan Delegator on an LE Audio Broadcast Sink can use the information - * contained within an instance of this class to synchronize with an LE Audio Broadcast Source in - * order to listen to a Broadcast Audio Stream. - * - *

    BroadcastAssistant has a BASS client which facilitates scanning and discovery of Broadcast - * Sources on behalf of say a Broadcast Sink. Upon successful discovery of one or more Broadcast - * sources, this information needs to be communicated to the BASS Server residing within the Scan - * Delegator on a Broadcast Sink. This is achieved using the Periodic Advertising Synchronization - * Transfer (PAST) procedure. This procedure uses information contained within an instance of this - * class. - * - * @hide - */ -public final class BluetoothLeBroadcastSourceInfo implements Parcelable { - private static final String TAG = "BluetoothLeBroadcastSourceInfo"; - private static final boolean DBG = true; - - /** - * Constants representing Broadcast Source address types - * - * @hide - */ - @IntDef( - prefix = "LE_AUDIO_BROADCAST_SOURCE_ADDRESS_TYPE_", - value = { - LE_AUDIO_BROADCAST_SOURCE_ADDRESS_TYPE_PUBLIC, - LE_AUDIO_BROADCAST_SOURCE_ADDRESS_TYPE_RANDOM, - LE_AUDIO_BROADCAST_SOURCE_ADDRESS_TYPE_INVALID - }) - @Retention(RetentionPolicy.SOURCE) - public @interface LeAudioBroadcastSourceAddressType {} - - /** - * Represents a public address used by an LE Audio Broadcast Source - * - * @hide - */ - public static final int LE_AUDIO_BROADCAST_SOURCE_ADDRESS_TYPE_PUBLIC = 0; - - /** - * Represents a random address used by an LE Audio Broadcast Source - * - * @hide - */ - public static final int LE_AUDIO_BROADCAST_SOURCE_ADDRESS_TYPE_RANDOM = 1; - - /** - * Represents an invalid address used by an LE Audio Broadcast Seurce - * - * @hide - */ - public static final int LE_AUDIO_BROADCAST_SOURCE_ADDRESS_TYPE_INVALID = 0xFFFF; - - /** - * Periodic Advertising Synchronization state - * - *

    Periodic Advertising (PA) enables the LE Audio Broadcast Assistant to discover broadcast - * audio streams as well as the audio stream configuration on behalf of an LE Audio Broadcast - * Sink. This information can then be transferred to the LE Audio Broadcast Sink using the - * Periodic Advertising Synchronizaton Transfer (PAST) procedure. - * - * @hide - */ - @IntDef( - prefix = "LE_AUDIO_BROADCAST_SINK_PA_SYNC_STATE_", - value = { - LE_AUDIO_BROADCAST_SINK_PA_SYNC_STATE_IDLE, - LE_AUDIO_BROADCAST_SINK_PA_SYNC_STATE_SYNCINFO_REQ, - LE_AUDIO_BROADCAST_SINK_PA_SYNC_STATE_IN_SYNC, - LE_AUDIO_BROADCAST_SINK_PA_SYNC_STATE_SYNC_FAIL, - LE_AUDIO_BROADCAST_SINK_PA_SYNC_STATE_NO_PAST - }) - @Retention(RetentionPolicy.SOURCE) - public @interface LeAudioBroadcastSinkPaSyncState {} - - /** - * Indicates that the Broadcast Sink is not synchronized with the Periodic Advertisements (PA) - * - * @hide - */ - public static final int LE_AUDIO_BROADCAST_SINK_PA_SYNC_STATE_IDLE = 0; - - /** - * Indicates that the Broadcast Sink requested the Broadcast Assistant to synchronize with the - * Periodic Advertisements (PA). - * - *

    This is also known as scan delegation or scan offloading. - * - * @hide - */ - public static final int LE_AUDIO_BROADCAST_SINK_PA_SYNC_STATE_SYNCINFO_REQ = 1; - - /** - * Indicates that the Broadcast Sink is synchronized with the Periodic Advertisements (PA). - * - * @hide - */ - public static final int LE_AUDIO_BROADCAST_SINK_PA_SYNC_STATE_IN_SYNC = 2; - - /** - * Indicates that the Broadcast Sink was unable to synchronize with the Periodic Advertisements - * (PA). - * - * @hide - */ - public static final int LE_AUDIO_BROADCAST_SINK_PA_SYNC_STATE_SYNC_FAIL = 3; - - /** - * Indicates that the Broadcast Sink should be synchronized with the Periodic Advertisements - * (PA) using the Periodic Advertisements Synchronization Transfert (PAST) procedure. - * - * @hide - */ - public static final int LE_AUDIO_BROADCAST_SINK_PA_SYNC_STATE_NO_PAST = 4; - - /** - * Indicates that the Broadcast Sink synchornization state is invalid. - * - * @hide - */ - public static final int LE_AUDIO_BROADCAST_SINK_PA_SYNC_STATE_INVALID = 0xFFFF; - - /** @hide */ - @IntDef( - prefix = "LE_AUDIO_BROADCAST_SINK_AUDIO_SYNC_STATE_", - value = { - LE_AUDIO_BROADCAST_SINK_AUDIO_SYNC_STATE_NOT_SYNCHRONIZED, - LE_AUDIO_BROADCAST_SINK_AUDIO_SYNC_STATE_SYNCHRONIZED - }) - @Retention(RetentionPolicy.SOURCE) - public @interface LeAudioBroadcastSinkAudioSyncState {} - - /** - * Indicates that the Broadcast Sink is not synchronized with a Broadcast Audio Stream. - * - * @hide - */ - public static final int LE_AUDIO_BROADCAST_SINK_AUDIO_SYNC_STATE_NOT_SYNCHRONIZED = 0; - - /** - * Indicates that the Broadcast Sink is synchronized with a Broadcast Audio Stream. - * - * @hide - */ - public static final int LE_AUDIO_BROADCAST_SINK_AUDIO_SYNC_STATE_SYNCHRONIZED = 1; - - /** - * Indicates that the Broadcast Sink audio synchronization state is invalid. - * - * @hide - */ - public static final int LE_AUDIO_BROADCAST_SINK_AUDIO_SYNC_STATE_INVALID = 0xFFFF; - - /** @hide */ - @IntDef( - prefix = "LE_AUDIO_BROADCAST_SINK_ENC_STATE_", - value = { - LE_AUDIO_BROADCAST_SINK_ENC_STATE_NOT_ENCRYPTED, - LE_AUDIO_BROADCAST_SINK_ENC_STATE_CODE_REQUIRED, - LE_AUDIO_BROADCAST_SINK_ENC_STATE_DECRYPTING, - LE_AUDIO_BROADCAST_SINK_ENC_STATE_BAD_CODE - }) - @Retention(RetentionPolicy.SOURCE) - public @interface LeAudioBroadcastSinkEncryptionState {} - - /** - * Indicates that the Broadcast Sink is synchronized with an unencrypted audio stream. - * - * @hide - */ - public static final int LE_AUDIO_BROADCAST_SINK_ENC_STATE_NOT_ENCRYPTED = 0; - - /** - * Indicates that the Broadcast Sink needs a Broadcast Code to synchronize with the audio - * stream. - * - * @hide - */ - public static final int LE_AUDIO_BROADCAST_SINK_ENC_STATE_CODE_REQUIRED = 1; - - /** - * Indicates that the Broadcast Sink is synchronized with an encrypted audio stream. - * - * @hide - */ - public static final int LE_AUDIO_BROADCAST_SINK_ENC_STATE_DECRYPTING = 2; - - /** - * Indicates that the Broadcast Sink is unable to decrypt an audio stream due to an incorrect - * Broadcast Code - * - * @hide - */ - public static final int LE_AUDIO_BROADCAST_SINK_ENC_STATE_BAD_CODE = 3; - - /** - * Indicates that the Broadcast Sink encryption state is invalid. - * - * @hide - */ - public static final int LE_AUDIO_BROADCAST_SINK_ENC_STATE_INVALID = 0xFF; - - /** - * Represents an invalid LE Audio Broadcast Source ID - * - * @hide - */ - public static final byte LE_AUDIO_BROADCAST_SINK_INVALID_SOURCE_ID = (byte) 0x00; - - /** - * Represents an invalid Broadcast ID of a Broadcast Source - * - * @hide - */ - public static final int INVALID_BROADCAST_ID = 0xFFFFFF; - - private byte mSourceId; - private @LeAudioBroadcastSourceAddressType int mSourceAddressType; - private BluetoothDevice mSourceDevice; - private byte mSourceAdvSid; - private int mBroadcastId; - private @LeAudioBroadcastSinkPaSyncState int mPaSyncState; - private @LeAudioBroadcastSinkEncryptionState int mEncryptionStatus; - private @LeAudioBroadcastSinkAudioSyncState int mAudioSyncState; - private byte[] mBadBroadcastCode; - private byte mNumSubGroups; - private Map mSubgroupBisSyncState = new HashMap(); - private Map mSubgroupMetadata = new HashMap(); - - private String mBroadcastCode; - private static final int BIS_NO_PREF = 0xFFFFFFFF; - private static final int BROADCAST_CODE_SIZE = 16; - - /** - * Constructor to create an Empty object of {@link BluetoothLeBroadcastSourceInfo } with the - * given Source Id. - * - *

    This is mainly used to represent the Empty Broadcast Source entries - * - * @param sourceId Source Id for this Broadcast Source info object - * @hide - */ - public BluetoothLeBroadcastSourceInfo(byte sourceId) { - mSourceId = sourceId; - mSourceAddressType = LE_AUDIO_BROADCAST_SOURCE_ADDRESS_TYPE_INVALID; - mSourceDevice = null; - mSourceAdvSid = (byte) 0x00; - mBroadcastId = INVALID_BROADCAST_ID; - mPaSyncState = LE_AUDIO_BROADCAST_SINK_PA_SYNC_STATE_INVALID; - mAudioSyncState = LE_AUDIO_BROADCAST_SINK_AUDIO_SYNC_STATE_INVALID; - mEncryptionStatus = LE_AUDIO_BROADCAST_SINK_ENC_STATE_INVALID; - mBadBroadcastCode = null; - mNumSubGroups = 0; - mBroadcastCode = null; - } - - /*package*/ BluetoothLeBroadcastSourceInfo( - byte sourceId, - @LeAudioBroadcastSourceAddressType int addressType, - @NonNull BluetoothDevice device, - byte advSid, - int broadcastId, - @LeAudioBroadcastSinkPaSyncState int paSyncstate, - @LeAudioBroadcastSinkEncryptionState int encryptionStatus, - @LeAudioBroadcastSinkAudioSyncState int audioSyncstate, - @Nullable byte[] badCode, - byte numSubGroups, - @NonNull Map bisSyncState, - @Nullable Map subgroupMetadata, - @NonNull String broadcastCode) { - mSourceId = sourceId; - mSourceAddressType = addressType; - mSourceDevice = device; - mSourceAdvSid = advSid; - mBroadcastId = broadcastId; - mPaSyncState = paSyncstate; - mEncryptionStatus = encryptionStatus; - mAudioSyncState = audioSyncstate; - - if (badCode != null && badCode.length != 0) { - mBadBroadcastCode = new byte[badCode.length]; - System.arraycopy(badCode, 0, mBadBroadcastCode, 0, badCode.length); - } - mNumSubGroups = numSubGroups; - mSubgroupBisSyncState = new HashMap(bisSyncState); - mSubgroupMetadata = new HashMap(subgroupMetadata); - mBroadcastCode = broadcastCode; - } - - @Override - public boolean equals(Object o) { - if (o instanceof BluetoothLeBroadcastSourceInfo) { - BluetoothLeBroadcastSourceInfo other = (BluetoothLeBroadcastSourceInfo) o; - return (other.mSourceId == mSourceId - && other.mSourceAddressType == mSourceAddressType - && other.mSourceDevice == mSourceDevice - && other.mSourceAdvSid == mSourceAdvSid - && other.mBroadcastId == mBroadcastId - && other.mPaSyncState == mPaSyncState - && other.mEncryptionStatus == mEncryptionStatus - && other.mAudioSyncState == mAudioSyncState - && Arrays.equals(other.mBadBroadcastCode, mBadBroadcastCode) - && other.mNumSubGroups == mNumSubGroups - && mSubgroupBisSyncState.equals(other.mSubgroupBisSyncState) - && mSubgroupMetadata.equals(other.mSubgroupMetadata) - && other.mBroadcastCode == mBroadcastCode); - } - return false; - } - - /** - * Checks if an instance of {@link BluetoothLeBroadcastSourceInfo} is empty. - * - * @hide - */ - public boolean isEmpty() { - boolean ret = false; - if (mSourceAddressType == LE_AUDIO_BROADCAST_SOURCE_ADDRESS_TYPE_INVALID - && mSourceDevice == null - && mSourceAdvSid == (byte) 0 - && mPaSyncState == LE_AUDIO_BROADCAST_SINK_PA_SYNC_STATE_INVALID - && mEncryptionStatus == LE_AUDIO_BROADCAST_SINK_ENC_STATE_INVALID - && mAudioSyncState == LE_AUDIO_BROADCAST_SINK_AUDIO_SYNC_STATE_INVALID - && mBadBroadcastCode == null - && mNumSubGroups == 0 - && mSubgroupBisSyncState.size() == 0 - && mSubgroupMetadata.size() == 0 - && mBroadcastCode == null) { - ret = true; - } - return ret; - } - - /** - * Compares an instance of {@link BluetoothLeBroadcastSourceInfo} with the provided instance. - * - * @hide - */ - public boolean matches(BluetoothLeBroadcastSourceInfo srcInfo) { - boolean ret = false; - if (srcInfo == null) { - ret = false; - } else { - if (mSourceDevice == null) { - if (mSourceAdvSid == srcInfo.getAdvertisingSid() - && mSourceAddressType == srcInfo.getAdvAddressType()) { - ret = true; - } - } else { - if (mSourceDevice.equals(srcInfo.getSourceDevice()) - && mSourceAdvSid == srcInfo.getAdvertisingSid() - && mSourceAddressType == srcInfo.getAdvAddressType() - && mBroadcastId == srcInfo.getBroadcastId()) { - ret = true; - } - } - } - return ret; - } - - @Override - public int hashCode() { - return Objects.hash( - mSourceId, - mSourceAddressType, - mSourceDevice, - mSourceAdvSid, - mBroadcastId, - mPaSyncState, - mEncryptionStatus, - mAudioSyncState, - mBadBroadcastCode, - mNumSubGroups, - mSubgroupBisSyncState, - mSubgroupMetadata, - mBroadcastCode); - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public String toString() { - return "{BluetoothLeBroadcastSourceInfo : mSourceId" - + mSourceId - + " addressType: " - + mSourceAddressType - + " sourceDevice: " - + mSourceDevice - + " mSourceAdvSid:" - + mSourceAdvSid - + " mBroadcastId:" - + mBroadcastId - + " mPaSyncState:" - + mPaSyncState - + " mEncryptionStatus:" - + mEncryptionStatus - + " mAudioSyncState:" - + mAudioSyncState - + " mBadBroadcastCode:" - + mBadBroadcastCode - + " mNumSubGroups:" - + mNumSubGroups - + " mSubgroupBisSyncState:" - + mSubgroupBisSyncState - + " mSubgroupMetadata:" - + mSubgroupMetadata - + " mBroadcastCode:" - + mBroadcastCode - + "}"; - } - - /** - * Get the Source Id - * - * @return byte representing the Source Id, {@link - * #LE_AUDIO_BROADCAST_ASSISTANT_INVALID_SOURCE_ID} if invalid - * @hide - */ - public byte getSourceId() { - return mSourceId; - } - - /** - * Set the Source Id - * - * @param sourceId source Id - * @hide - */ - public void setSourceId(byte sourceId) { - mSourceId = sourceId; - } - - /** - * Set the Broadcast Source device - * - * @param sourceDevice the Broadcast Source BluetoothDevice - * @hide - */ - public void setSourceDevice(@NonNull BluetoothDevice sourceDevice) { - mSourceDevice = sourceDevice; - } - - /** - * Get the Broadcast Source BluetoothDevice - * - * @return Broadcast Source BluetoothDevice - * @hide - */ - public @NonNull BluetoothDevice getSourceDevice() { - return mSourceDevice; - } - - /** - * Set the address type of the Broadcast Source advertisements - * - * @hide - */ - public void setAdvAddressType(@LeAudioBroadcastSourceAddressType int addressType) { - mSourceAddressType = addressType; - } - - /** - * Get the address type used by advertisements from the Broadcast Source. - * BluetoothLeBroadcastSourceInfo Object - * - * @hide - */ - @LeAudioBroadcastSourceAddressType - public int getAdvAddressType() { - return mSourceAddressType; - } - - /** - * Set the advertising SID of the Broadcast Source advertisement. - * - * @param advSid advertising SID of the Broadcast Source - * @hide - */ - public void setAdvertisingSid(byte advSid) { - mSourceAdvSid = advSid; - } - - /** - * Get the advertising SID of the Broadcast Source advertisement. - * - * @return advertising SID of the Broadcast Source - * @hide - */ - public byte getAdvertisingSid() { - return mSourceAdvSid; - } - - /** - * Get the Broadcast ID of the Broadcast Source. - * - * @return broadcast ID - * @hide - */ - public int getBroadcastId() { - return mBroadcastId; - } - - /** - * Set the Periodic Advertising (PA) Sync State. - * - * @hide - */ - /*package*/ void setPaSyncState(@LeAudioBroadcastSinkPaSyncState int paSyncState) { - mPaSyncState = paSyncState; - } - - /** - * Get the Periodic Advertising (PA) Sync State - * - * @hide - */ - public @LeAudioBroadcastSinkPaSyncState int getMetadataSyncState() { - return mPaSyncState; - } - - /** - * Set the audio sync state - * - * @hide - */ - /*package*/ void setAudioSyncState(@LeAudioBroadcastSinkAudioSyncState int audioSyncState) { - mAudioSyncState = audioSyncState; - } - - /** - * Get the audio sync state - * - * @hide - */ - public @LeAudioBroadcastSinkAudioSyncState int getAudioSyncState() { - return mAudioSyncState; - } - - /** - * Set the encryption status - * - * @hide - */ - /*package*/ void setEncryptionStatus( - @LeAudioBroadcastSinkEncryptionState int encryptionStatus) { - mEncryptionStatus = encryptionStatus; - } - - /** - * Get the encryption status - * - * @hide - */ - public @LeAudioBroadcastSinkEncryptionState int getEncryptionStatus() { - return mEncryptionStatus; - } - - /** - * Get the incorrect broadcast code that the Scan delegator used to decrypt the Broadcast Audio - * Stream and failed. - * - *

    This code is valid only if {@link #getEncryptionStatus} returns {@link - * #LE_AUDIO_BROADCAST_SINK_ENC_STATE_BAD_CODE} - * - * @return byte array containing bad broadcast value, null if the current encryption status is - * not {@link #LE_AUDIO_BROADCAST_SINK_ENC_STATE_BAD_CODE} - * @hide - */ - public @Nullable byte[] getBadBroadcastCode() { - return mBadBroadcastCode; - } - - /** - * Get the number of subgroups. - * - * @return number of subgroups - * @hide - */ - public byte getNumberOfSubGroups() { - return mNumSubGroups; - } - - public @NonNull Map getSubgroupBisSyncState() { - return mSubgroupBisSyncState; - } - - public void setSubgroupBisSyncState(@NonNull Map bisSyncState) { - mSubgroupBisSyncState = new HashMap(bisSyncState); - } - - /*package*/ void setBroadcastCode(@NonNull String broadcastCode) { - mBroadcastCode = broadcastCode; - } - - /** - * Get the broadcast code - * - * @return - * @hide - */ - public @NonNull String getBroadcastCode() { - return mBroadcastCode; - } - - /** - * Set the broadcast ID - * - * @param broadcastId broadcast ID of the Broadcast Source - * @hide - */ - public void setBroadcastId(int broadcastId) { - mBroadcastId = broadcastId; - } - - private void writeSubgroupBisSyncStateToParcel( - @NonNull Parcel dest, @NonNull Map subgroupBisSyncState) { - dest.writeInt(subgroupBisSyncState.size()); - for (Map.Entry entry : subgroupBisSyncState.entrySet()) { - dest.writeInt(entry.getKey()); - dest.writeInt(entry.getValue()); - } - } - - private static void readSubgroupBisSyncStateFromParcel( - @NonNull Parcel in, @NonNull Map subgroupBisSyncState) { - int size = in.readInt(); - - for (int i = 0; i < size; i++) { - Integer key = in.readInt(); - Integer value = in.readInt(); - subgroupBisSyncState.put(key, value); - } - } - - private void writeSubgroupMetadataToParcel( - @NonNull Parcel dest, @Nullable Map subgroupMetadata) { - if (subgroupMetadata == null) { - dest.writeInt(0); - return; - } - - dest.writeInt(subgroupMetadata.size()); - for (Map.Entry entry : subgroupMetadata.entrySet()) { - dest.writeInt(entry.getKey()); - byte[] metadata = entry.getValue(); - if (metadata != null) { - dest.writeInt(metadata.length); - dest.writeByteArray(metadata); - } - } - } - - private static void readSubgroupMetadataFromParcel( - @NonNull Parcel in, @NonNull Map subgroupMetadata) { - int size = in.readInt(); - - for (int i = 0; i < size; i++) { - Integer key = in.readInt(); - Integer metaDataLen = in.readInt(); - byte[] metadata = null; - if (metaDataLen != 0) { - metadata = new byte[metaDataLen]; - in.readByteArray(metadata); - } - subgroupMetadata.put(key, metadata); - } - } - - public static final @NonNull Parcelable.Creator CREATOR = - new Parcelable.Creator() { - public @NonNull BluetoothLeBroadcastSourceInfo createFromParcel( - @NonNull Parcel in) { - final byte sourceId = in.readByte(); - final int sourceAddressType = in.readInt(); - final BluetoothDevice sourceDevice = - in.readTypedObject(BluetoothDevice.CREATOR); - final byte sourceAdvSid = in.readByte(); - final int broadcastId = in.readInt(); - final int paSyncState = in.readInt(); - final int audioSyncState = in.readInt(); - final int encryptionStatus = in.readInt(); - final int badBroadcastLen = in.readInt(); - byte[] badBroadcastCode = null; - - if (badBroadcastLen > 0) { - badBroadcastCode = new byte[badBroadcastLen]; - in.readByteArray(badBroadcastCode); - } - final byte numSubGroups = in.readByte(); - final String broadcastCode = in.readString(); - Map subgroupBisSyncState = new HashMap(); - readSubgroupBisSyncStateFromParcel(in, subgroupBisSyncState); - Map subgroupMetadata = new HashMap(); - readSubgroupMetadataFromParcel(in, subgroupMetadata); - - BluetoothLeBroadcastSourceInfo srcInfo = - new BluetoothLeBroadcastSourceInfo( - sourceId, - sourceAddressType, - sourceDevice, - sourceAdvSid, - broadcastId, - paSyncState, - encryptionStatus, - audioSyncState, - badBroadcastCode, - numSubGroups, - subgroupBisSyncState, - subgroupMetadata, - broadcastCode); - return srcInfo; - } - - public @NonNull BluetoothLeBroadcastSourceInfo[] newArray(int size) { - return new BluetoothLeBroadcastSourceInfo[size]; - } - }; - - @Override - public void writeToParcel(@NonNull Parcel out, int flags) { - out.writeByte(mSourceId); - out.writeInt(mSourceAddressType); - out.writeTypedObject(mSourceDevice, 0); - out.writeByte(mSourceAdvSid); - out.writeInt(mBroadcastId); - out.writeInt(mPaSyncState); - out.writeInt(mAudioSyncState); - out.writeInt(mEncryptionStatus); - - if (mBadBroadcastCode != null) { - out.writeInt(mBadBroadcastCode.length); - out.writeByteArray(mBadBroadcastCode); - } else { - // zero indicates that there is no "bad broadcast code" - out.writeInt(0); - } - out.writeByte(mNumSubGroups); - out.writeString(mBroadcastCode); - writeSubgroupBisSyncStateToParcel(out, mSubgroupBisSyncState); - writeSubgroupMetadataToParcel(out, mSubgroupMetadata); - } - - private static void log(@NonNull String msg) { - if (DBG) { - Log.d(TAG, msg); - } - } -} -; diff --git a/core/java/android/bluetooth/BluetoothLeCall.java b/core/java/android/bluetooth/BluetoothLeCall.java deleted file mode 100644 index fb7789db25c75992bfa7e47e1e73ca0350ab0b82..0000000000000000000000000000000000000000 --- a/core/java/android/bluetooth/BluetoothLeCall.java +++ /dev/null @@ -1,285 +0,0 @@ -/* - * Copyright 2021 HIMSA II K/S - www.himsa.com. - * Represented by EHIMA - www.ehima.com - * - * 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.bluetooth; - -import android.annotation.IntDef; -import android.annotation.NonNull; -import android.os.Parcel; -import android.os.Parcelable; -import android.os.ParcelUuid; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.util.Objects; -import java.util.UUID; - -/** - * Representation of Call - * - * @hide - */ -public final class BluetoothLeCall implements Parcelable { - - /** @hide */ - @IntDef(prefix = "STATE_", value = { - STATE_INCOMING, - STATE_DIALING, - STATE_ALERTING, - STATE_ACTIVE, - STATE_LOCALLY_HELD, - STATE_REMOTELY_HELD, - STATE_LOCALLY_AND_REMOTELY_HELD - }) - @Retention(RetentionPolicy.SOURCE) - public @interface State { - } - - /** - * A remote party is calling (incoming call). - * - * @hide - */ - public static final int STATE_INCOMING = 0x00; - - /** - * The process to call the remote party has started but the remote party is not - * being alerted (outgoing call). - * - * @hide - */ - public static final int STATE_DIALING = 0x01; - - /** - * A remote party is being alerted (outgoing call). - * - * @hide - */ - public static final int STATE_ALERTING = 0x02; - - /** - * The call is in an active conversation. - * - * @hide - */ - public static final int STATE_ACTIVE = 0x03; - - /** - * The call is connected but held locally. “Locally Held” implies that either - * the server or the client can affect the state. - * - * @hide - */ - public static final int STATE_LOCALLY_HELD = 0x04; - - /** - * The call is connected but held remotely. “Remotely Held” means that the state - * is controlled by the remote party of a call. - * - * @hide - */ - public static final int STATE_REMOTELY_HELD = 0x05; - - /** - * The call is connected but held both locally and remotely. - * - * @hide - */ - public static final int STATE_LOCALLY_AND_REMOTELY_HELD = 0x06; - - /** - * Whether the call direction is outgoing. - * - * @hide - */ - public static final int FLAG_OUTGOING_CALL = 0x00000001; - - /** - * Whether the call URI and Friendly Name are withheld by server. - * - * @hide - */ - public static final int FLAG_WITHHELD_BY_SERVER = 0x00000002; - - /** - * Whether the call URI and Friendly Name are withheld by network. - * - * @hide - */ - public static final int FLAG_WITHHELD_BY_NETWORK = 0x00000004; - - /** Unique UUID that identifies this call */ - private UUID mUuid; - - /** Remote Caller URI */ - private String mUri; - - /** Caller friendly name */ - private String mFriendlyName; - - /** Call state */ - private @State int mState; - - /** Call flags */ - private int mCallFlags; - - /** @hide */ - public BluetoothLeCall(@NonNull BluetoothLeCall that) { - mUuid = new UUID(that.getUuid().getMostSignificantBits(), - that.getUuid().getLeastSignificantBits()); - mUri = that.mUri; - mFriendlyName = that.mFriendlyName; - mState = that.mState; - mCallFlags = that.mCallFlags; - } - - /** @hide */ - public BluetoothLeCall(@NonNull UUID uuid, @NonNull String uri, @NonNull String friendlyName, - @State int state, int callFlags) { - mUuid = uuid; - mUri = uri; - mFriendlyName = friendlyName; - mState = state; - mCallFlags = callFlags; - } - - @Override - public boolean equals(Object o) { - if (this == o) - return true; - if (o == null || getClass() != o.getClass()) - return false; - BluetoothLeCall that = (BluetoothLeCall) o; - return mUuid.equals(that.mUuid) && mUri.equals(that.mUri) - && mFriendlyName.equals(that.mFriendlyName) && mState == that.mState - && mCallFlags == that.mCallFlags; - } - - @Override - public int hashCode() { - return Objects.hash(mUuid, mUri, mFriendlyName, mState, mCallFlags); - } - - /** - * Returns a string representation of this BluetoothLeCall. - * - *

    - * Currently this is the UUID. - * - * @return string representation of this BluetoothLeCall - */ - @Override - public String toString() { - return mUuid.toString(); - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(@NonNull Parcel out, int flags) { - out.writeParcelable(new ParcelUuid(mUuid), 0); - out.writeString(mUri); - out.writeString(mFriendlyName); - out.writeInt(mState); - out.writeInt(mCallFlags); - } - - public static final @android.annotation.NonNull Parcelable.Creator CREATOR = - new Parcelable.Creator() { - public BluetoothLeCall createFromParcel(Parcel in) { - return new BluetoothLeCall(in); - } - - public BluetoothLeCall[] newArray(int size) { - return new BluetoothLeCall[size]; - } - }; - - private BluetoothLeCall(Parcel in) { - mUuid = ((ParcelUuid) in.readParcelable(null)).getUuid(); - mUri = in.readString(); - mFriendlyName = in.readString(); - mState = in.readInt(); - mCallFlags = in.readInt(); - } - - /** - * Returns an UUID of this BluetoothLeCall. - * - *

    - * An UUID is unique identifier of a BluetoothLeCall. - * - * @return UUID of this BluetoothLeCall - * @hide - */ - public @NonNull UUID getUuid() { - return mUuid; - } - - /** - * Returns a URI of the remote party of this BluetoothLeCall. - * - * @return string representation of this BluetoothLeCall - * @hide - */ - public @NonNull String getUri() { - return mUri; - } - - /** - * Returns a friendly name of the call. - * - * @return friendly name representation of this BluetoothLeCall - * @hide - */ - public @NonNull String getFriendlyName() { - return mFriendlyName; - } - - /** - * Returns the call state. - * - * @return the state of this BluetoothLeCall - * @hide - */ - public @State int getState() { - return mState; - } - - /** - * Returns the call flags. - * - * @return call flags - * @hide - */ - public int getCallFlags() { - return mCallFlags; - } - - /** - * Whether the call direction is incoming. - * - * @return true if incoming call, false otherwise - * @hide - */ - public boolean isIncomingCall() { - return (mCallFlags & FLAG_OUTGOING_CALL) == 0; - } -} diff --git a/core/java/android/bluetooth/BluetoothLeCallControl.java b/core/java/android/bluetooth/BluetoothLeCallControl.java deleted file mode 100644 index fb080c9ec3e3711a7b26724ca33f2896163d8bd7..0000000000000000000000000000000000000000 --- a/core/java/android/bluetooth/BluetoothLeCallControl.java +++ /dev/null @@ -1,899 +0,0 @@ -/* - * Copyright 2019 HIMSA II K/S - www.himsa.com. - * Represented by EHIMA - www.ehima.com - * - * 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.bluetooth; - -import android.Manifest; -import android.annotation.IntDef; -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.annotation.RequiresPermission; -import android.bluetooth.annotations.RequiresBluetoothConnectPermission; -import android.content.ComponentName; -import android.content.Context; -import android.os.Binder; -import android.os.Handler; -import android.os.IBinder; -import android.os.Looper; -import android.os.Message; -import android.os.ParcelUuid; -import android.os.RemoteException; -import android.util.Log; -import android.annotation.SuppressLint; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.UUID; -import java.util.concurrent.Executor; - -/** - * This class provides the APIs to control the Call Control profile. - * - *

    - * This class provides Bluetooth Telephone Bearer Service functionality, - * allowing applications to expose a GATT Service based interface to control the - * state of the calls by remote devices such as LE audio devices. - * - *

    - * BluetoothLeCallControl is a proxy object for controlling the Bluetooth Telephone Bearer - * Service via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get the - * BluetoothLeCallControl proxy object. - * - * @hide - */ -public final class BluetoothLeCallControl implements BluetoothProfile { - private static final String TAG = "BluetoothLeCallControl"; - private static final boolean DBG = true; - private static final boolean VDBG = false; - - /** @hide */ - @IntDef(prefix = "RESULT_", value = { - RESULT_SUCCESS, - RESULT_ERROR_UNKNOWN_CALL_ID, - RESULT_ERROR_INVALID_URI, - RESULT_ERROR_APPLICATION - }) - @Retention(RetentionPolicy.SOURCE) - public @interface Result { - } - - /** - * Opcode write was successful. - * - * @hide - */ - public static final int RESULT_SUCCESS = 0; - - /** - * Unknown call Id has been used in the operation. - * - * @hide - */ - public static final int RESULT_ERROR_UNKNOWN_CALL_ID = 1; - - /** - * The URI provided in {@link Callback#onPlaceCallRequest} is invalid. - * - * @hide - */ - public static final int RESULT_ERROR_INVALID_URI = 2; - - /** - * Application internal error. - * - * @hide - */ - public static final int RESULT_ERROR_APPLICATION = 3; - - /** @hide */ - @IntDef(prefix = "TERMINATION_REASON_", value = { - TERMINATION_REASON_INVALID_URI, - TERMINATION_REASON_FAIL, - TERMINATION_REASON_REMOTE_HANGUP, - TERMINATION_REASON_SERVER_HANGUP, - TERMINATION_REASON_LINE_BUSY, - TERMINATION_REASON_NETWORK_CONGESTION, - TERMINATION_REASON_CLIENT_HANGUP, - TERMINATION_REASON_NO_SERVICE, - TERMINATION_REASON_NO_ANSWER - }) - @Retention(RetentionPolicy.SOURCE) - public @interface TerminationReason { - } - - /** - * Remote Caller ID value used to place a call was formed improperly. - * - * @hide - */ - public static final int TERMINATION_REASON_INVALID_URI = 0x00; - - /** - * Call fail. - * - * @hide - */ - public static final int TERMINATION_REASON_FAIL = 0x01; - - /** - * Remote party ended call. - * - * @hide - */ - public static final int TERMINATION_REASON_REMOTE_HANGUP = 0x02; - - /** - * Call ended from the server. - * - * @hide - */ - public static final int TERMINATION_REASON_SERVER_HANGUP = 0x03; - - /** - * Line busy. - * - * @hide - */ - public static final int TERMINATION_REASON_LINE_BUSY = 0x04; - - /** - * Network congestion. - * - * @hide - */ - public static final int TERMINATION_REASON_NETWORK_CONGESTION = 0x05; - - /** - * Client terminated. - * - * @hide - */ - public static final int TERMINATION_REASON_CLIENT_HANGUP = 0x06; - - /** - * No service. - * - * @hide - */ - public static final int TERMINATION_REASON_NO_SERVICE = 0x07; - - /** - * No answer. - * - * @hide - */ - public static final int TERMINATION_REASON_NO_ANSWER = 0x08; - - /* - * Flag indicating support for hold/unhold call feature. - * - * @hide - */ - public static final int CAPABILITY_HOLD_CALL = 0x00000001; - - /** - * Flag indicating support for joining calls feature. - * - * @hide - */ - public static final int CAPABILITY_JOIN_CALLS = 0x00000002; - - private static final int MESSAGE_TBS_SERVICE_CONNECTED = 102; - private static final int MESSAGE_TBS_SERVICE_DISCONNECTED = 103; - - private static final int REG_TIMEOUT = 10000; - - /** - * The template class is used to call callback functions on events from the TBS - * server. Callback functions are wrapped in this class and registered to the - * Android system during app registration. - * - * @hide - */ - public abstract static class Callback { - - private static final String TAG = "BluetoothLeCallControl.Callback"; - - /** - * Called when a remote client requested to accept the call. - * - *

    - * An application must call {@link BluetoothLeCallControl#requestResult} to complete the - * request. - * - * @param requestId The Id of the request - * @param callId The call Id requested to be accepted - * @hide - */ - public abstract void onAcceptCall(int requestId, @NonNull UUID callId); - - /** - * A remote client has requested to terminate the call. - * - *

    - * An application must call {@link BluetoothLeCallControl#requestResult} to complete the - * request. - * - * @param requestId The Id of the request - * @param callId The call Id requested to terminate - * @hide - */ - public abstract void onTerminateCall(int requestId, @NonNull UUID callId); - - /** - * A remote client has requested to hold the call. - * - *

    - * An application must call {@link BluetoothLeCallControl#requestResult} to complete the - * request. - * - * @param requestId The Id of the request - * @param callId The call Id requested to be put on hold - * @hide - */ - public void onHoldCall(int requestId, @NonNull UUID callId) { - Log.e(TAG, "onHoldCall: unimplemented, however CAPABILITY_HOLD_CALL is set!"); - } - - /** - * A remote client has requested to unhold the call. - * - *

    - * An application must call {@link BluetoothLeCallControl#requestResult} to complete the - * request. - * - * @param requestId The Id of the request - * @param callId The call Id requested to unhold - * @hide - */ - public void onUnholdCall(int requestId, @NonNull UUID callId) { - Log.e(TAG, "onUnholdCall: unimplemented, however CAPABILITY_HOLD_CALL is set!"); - } - - /** - * A remote client has requested to place a call. - * - *

    - * An application must call {@link BluetoothLeCallControl#requestResult} to complete the - * request. - * - * @param requestId The Id of the request - * @param callId The Id to be assigned for the new call - * @param uri The caller URI requested - * @hide - */ - public abstract void onPlaceCall(int requestId, @NonNull UUID callId, @NonNull String uri); - - /** - * A remote client has requested to join the calls. - * - *

    - * An application must call {@link BluetoothLeCallControl#requestResult} to complete the - * request. - * - * @param requestId The Id of the request - * @param callIds The call Id list requested to join - * @hide - */ - public void onJoinCalls(int requestId, @NonNull List callIds) { - Log.e(TAG, "onJoinCalls: unimplemented, however CAPABILITY_JOIN_CALLS is set!"); - } - } - - private class CallbackWrapper extends IBluetoothLeCallControlCallback.Stub { - - private final Executor mExecutor; - private final Callback mCallback; - - CallbackWrapper(Executor executor, Callback callback) { - mExecutor = executor; - mCallback = callback; - } - - @Override - public void onBearerRegistered(int ccid) { - if (mCallback != null) { - mCcid = ccid; - } else { - // registration timeout - Log.e(TAG, "onBearerRegistered: mCallback is null"); - } - } - - @Override - public void onAcceptCall(int requestId, ParcelUuid uuid) { - final long identityToken = Binder.clearCallingIdentity(); - try { - mExecutor.execute(() -> mCallback.onAcceptCall(requestId, uuid.getUuid())); - } finally { - Binder.restoreCallingIdentity(identityToken); - } - } - - @Override - public void onTerminateCall(int requestId, ParcelUuid uuid) { - final long identityToken = Binder.clearCallingIdentity(); - try { - mExecutor.execute(() -> mCallback.onTerminateCall(requestId, uuid.getUuid())); - } finally { - Binder.restoreCallingIdentity(identityToken); - } - } - - @Override - public void onHoldCall(int requestId, ParcelUuid uuid) { - final long identityToken = Binder.clearCallingIdentity(); - try { - mExecutor.execute(() -> mCallback.onHoldCall(requestId, uuid.getUuid())); - } finally { - Binder.restoreCallingIdentity(identityToken); - } - } - - @Override - public void onUnholdCall(int requestId, ParcelUuid uuid) { - final long identityToken = Binder.clearCallingIdentity(); - try { - mExecutor.execute(() -> mCallback.onUnholdCall(requestId, uuid.getUuid())); - } finally { - Binder.restoreCallingIdentity(identityToken); - } - } - - @Override - public void onPlaceCall(int requestId, ParcelUuid uuid, String uri) { - final long identityToken = Binder.clearCallingIdentity(); - try { - mExecutor.execute(() -> mCallback.onPlaceCall(requestId, uuid.getUuid(), uri)); - } finally { - Binder.restoreCallingIdentity(identityToken); - } - } - - @Override - public void onJoinCalls(int requestId, List parcelUuids) { - List uuids = new ArrayList<>(); - for (ParcelUuid parcelUuid : parcelUuids) { - uuids.add(parcelUuid.getUuid()); - } - - final long identityToken = Binder.clearCallingIdentity(); - try { - mExecutor.execute(() -> mCallback.onJoinCalls(requestId, uuids)); - } finally { - Binder.restoreCallingIdentity(identityToken); - } - } - }; - - private Context mContext; - private ServiceListener mServiceListener; - private volatile IBluetoothLeCallControl mService; - private BluetoothAdapter mAdapter; - private int mCcid = 0; - private String mToken; - private Callback mCallback = null; - - private final IBluetoothStateChangeCallback mBluetoothStateChangeCallback = - new IBluetoothStateChangeCallback.Stub() { - public void onBluetoothStateChange(boolean up) { - if (DBG) - Log.d(TAG, "onBluetoothStateChange: up=" + up); - if (!up) { - doUnbind(); - } else { - doBind(); - } - } - }; - - /** - * Create a BluetoothLeCallControl proxy object for interacting with the local Bluetooth - * telephone bearer service. - */ - /* package */ BluetoothLeCallControl(Context context, ServiceListener listener) { - mContext = context; - mAdapter = BluetoothAdapter.getDefaultAdapter(); - mServiceListener = listener; - - IBluetoothManager mgr = mAdapter.getBluetoothManager(); - if (mgr != null) { - try { - mgr.registerStateChangeCallback(mBluetoothStateChangeCallback); - } catch (RemoteException e) { - Log.e(TAG, "", e); - } - } - - doBind(); - } - - private boolean doBind() { - synchronized (mConnection) { - if (mService == null) { - if (VDBG) - Log.d(TAG, "Binding service..."); - try { - return mAdapter.getBluetoothManager(). - bindBluetoothProfileService(BluetoothProfile.LE_CALL_CONTROL, - mConnection); - } catch (RemoteException e) { - Log.e(TAG, "Unable to bind TelephoneBearerService", e); - } - } - } - return false; - } - - private void doUnbind() { - synchronized (mConnection) { - if (mService != null) { - if (VDBG) - Log.d(TAG, "Unbinding service..."); - try { - mAdapter.getBluetoothManager(). - unbindBluetoothProfileService(BluetoothProfile.LE_CALL_CONTROL, - mConnection); - } catch (RemoteException e) { - Log.e(TAG, "Unable to unbind TelephoneBearerService", e); - } finally { - mService = null; - } - } - } - } - - /* package */ void close() { - if (VDBG) - log("close()"); - unregisterBearer(); - - IBluetoothManager mgr = mAdapter.getBluetoothManager(); - if (mgr != null) { - try { - mgr.unregisterStateChangeCallback(mBluetoothStateChangeCallback); - } catch (RemoteException re) { - Log.e(TAG, "", re); - } - } - mServiceListener = null; - doUnbind(); - } - - private IBluetoothLeCallControl getService() { - return mService; - } - - /** - * Not supported - * - * @throws UnsupportedOperationException - */ - @Override - public int getConnectionState(@Nullable BluetoothDevice device) { - throw new UnsupportedOperationException("not supported"); - } - - /** - * Not supported - * - * @throws UnsupportedOperationException - */ - @Override - public @NonNull List getConnectedDevices() { - throw new UnsupportedOperationException("not supported"); - } - - /** - * Not supported - * - * @throws UnsupportedOperationException - */ - @Override - public @NonNull List getDevicesMatchingConnectionStates( - @NonNull int[] states) { - throw new UnsupportedOperationException("not supported"); - } - - /** - * Register Telephone Bearer exposing the interface that allows remote devices - * to track and control the call states. - * - *

    - * This is an asynchronous call. The callback is used to notify success or - * failure if the function returns true. - * - *

    - * Requires {@link android.Manifest.permission#BLUETOOTH} permission. - * - * - * - * - * - * - * - * @param uci Bearer Unique Client Identifier - * @param uriSchemes URI Schemes supported list - * @param capabilities bearer capabilities - * @param provider Network provider name - * @param technology Network technology - * @param executor {@link Executor} object on which callback will be - * executed. The Executor object is required. - * @param callback {@link Callback} object to which callback messages will - * be sent. The Callback object is required. - * @return true on success, false otherwise - * @hide - */ - @SuppressLint("ExecutorRegistration") - @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) - public boolean registerBearer(@Nullable String uci, - @NonNull List uriSchemes, int capabilities, - @NonNull String provider, int technology, - @NonNull Executor executor, @NonNull Callback callback) { - if (DBG) { - Log.d(TAG, "registerBearer"); - } - if (callback == null) { - throw new IllegalArgumentException("null parameter: " + callback); - } - if (mCcid != 0) { - return false; - } - - mToken = uci; - - final IBluetoothLeCallControl service = getService(); - if (service != null) { - if (mCallback != null) { - Log.e(TAG, "Bearer can be opened only once"); - return false; - } - - mCallback = callback; - try { - CallbackWrapper callbackWrapper = new CallbackWrapper(executor, callback); - service.registerBearer(mToken, callbackWrapper, uci, uriSchemes, capabilities, - provider, technology); - } catch (RemoteException e) { - Log.e(TAG, "", e); - mCallback = null; - return false; - } - - if (mCcid == 0) { - mCallback = null; - return false; - } - - return true; - } - - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - } - - return false; - } - - /** - * Unregister Telephone Bearer Service and destroy all the associated data. - * - * @hide - */ - @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) - public void unregisterBearer() { - if (DBG) { - Log.d(TAG, "unregisterBearer"); - } - if (mCcid == 0) { - return; - } - - int ccid = mCcid; - mCcid = 0; - mCallback = null; - - final IBluetoothLeCallControl service = getService(); - if (service != null) { - try { - service.unregisterBearer(mToken); - } catch (RemoteException e) { - Log.e(TAG, "", e); - } - } - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - } - } - - /** - * Get the Content Control ID (CCID) value. - * - * @return ccid Content Control ID value - * @hide - */ - @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) - public int getContentControlId() { - return mCcid; - } - - /** - * Notify about the newly added call. - * - *

    - * This shall be called as early as possible after the call has been added. - * - *

    - * Requires {@link android.Manifest.permission#BLUETOOTH} permission. - * - * @param call Newly added call - * @hide - */ - @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) - public void onCallAdded(@NonNull BluetoothLeCall call) { - if (DBG) { - Log.d(TAG, "onCallAdded: call=" + call); - } - if (mCcid == 0) { - return; - } - - final IBluetoothLeCallControl service = getService(); - if (service != null) { - try { - service.callAdded(mCcid, call); - } catch (RemoteException e) { - Log.e(TAG, "", e); - } - } - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - } - } - - /** - * Notify about the removed call. - * - *

    - * This shall be called as early as possible after the call has been removed. - * - *

    - * Requires {@link android.Manifest.permission#BLUETOOTH} permission. - * - * @param callId The Id of a call that has been removed - * @param reason Call termination reason - * @hide - */ - @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) - public void onCallRemoved(@NonNull UUID callId, @TerminationReason int reason) { - if (DBG) { - Log.d(TAG, "callRemoved: callId=" + callId); - } - if (mCcid == 0) { - return; - } - - final IBluetoothLeCallControl service = getService(); - if (service != null) { - try { - service.callRemoved(mCcid, new ParcelUuid(callId), reason); - } catch (RemoteException e) { - Log.e(TAG, "", e); - } - } - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - } - } - - /** - * Notify the call state change - * - *

    - * This shall be called as early as possible after the state of the call has - * changed. - * - *

    - * Requires {@link android.Manifest.permission#BLUETOOTH} permission. - * - * @param callId The call Id that state has been changed - * @param state Call state - * @hide - */ - @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) - public void onCallStateChanged(@NonNull UUID callId, @BluetoothLeCall.State int state) { - if (DBG) { - Log.d(TAG, "callStateChanged: callId=" + callId + " state=" + state); - } - if (mCcid == 0) { - return; - } - - final IBluetoothLeCallControl service = getService(); - if (service != null) { - try { - service.callStateChanged(mCcid, new ParcelUuid(callId), state); - } catch (RemoteException e) { - Log.e(TAG, "", e); - } - } - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - } - } - - /** - * Provide the current calls list - * - *

    - * This function must be invoked after registration if application has any - * calls. - * - * @param calls current calls list - * @hide - */ - @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) - public void currentCallsList(@NonNull List calls) { - final IBluetoothLeCallControl service = getService(); - if (service != null) { - try { - service.currentCallsList(mCcid, calls); - } catch (RemoteException e) { - Log.e(TAG, "", e); - } - } - } - - /** - * Provide the network current status - * - *

    - * This function must be invoked on change of network state. - * - *

    - * Requires {@link android.Manifest.permission#BLUETOOTH} permission. - * - * - * - * @param provider Network provider name - * @param technology Network technology - * @hide - */ - @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) - public void networkStateChanged(@NonNull String provider, int technology) { - if (DBG) { - Log.d(TAG, "networkStateChanged: provider=" + provider + ", technology=" + technology); - } - if (mCcid == 0) { - return; - } - - final IBluetoothLeCallControl service = getService(); - if (service != null) { - try { - service.networkStateChanged(mCcid, provider, technology); - } catch (RemoteException e) { - Log.e(TAG, "", e); - } - } - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - } - } - - /** - * Send a response to a call control request to a remote device. - * - *

    - * This function must be invoked in when a request is received by one of these - * callback methods: - * - *

      - *
    • {@link Callback#onAcceptCall} - *
    • {@link Callback#onTerminateCall} - *
    • {@link Callback#onHoldCall} - *
    • {@link Callback#onUnholdCall} - *
    • {@link Callback#onPlaceCall} - *
    • {@link Callback#onJoinCalls} - *
    - * - * @param requestId The ID of the request that was received with the callback - * @param result The result of the request to be sent to the remote devices - */ - @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) - public void requestResult(int requestId, @Result int result) { - if (DBG) { - Log.d(TAG, "requestResult: requestId=" + requestId + " result=" + result); - } - if (mCcid == 0) { - return; - } - - final IBluetoothLeCallControl service = getService(); - if (service != null) { - try { - service.requestResult(mCcid, requestId, result); - } catch (RemoteException e) { - Log.e(TAG, "", e); - } - } - } - - @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) - private static boolean isValidDevice(@Nullable BluetoothDevice device) { - return device != null && BluetoothAdapter.checkBluetoothAddress(device.getAddress()); - } - - private static void log(String msg) { - Log.d(TAG, msg); - } - - private final IBluetoothProfileServiceConnection mConnection = - new IBluetoothProfileServiceConnection.Stub() { - @Override - public void onServiceConnected(ComponentName className, IBinder service) { - if (DBG) { - Log.d(TAG, "Proxy object connected"); - } - mService = IBluetoothLeCallControl.Stub.asInterface(Binder.allowBlocking(service)); - mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_TBS_SERVICE_CONNECTED)); - } - - @Override - public void onServiceDisconnected(ComponentName className) { - if (DBG) { - Log.d(TAG, "Proxy object disconnected"); - } - doUnbind(); - mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_TBS_SERVICE_DISCONNECTED)); - } - }; - - private final Handler mHandler = new Handler(Looper.getMainLooper()) { - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case MESSAGE_TBS_SERVICE_CONNECTED: { - if (mServiceListener != null) { - mServiceListener.onServiceConnected(BluetoothProfile.LE_CALL_CONTROL, - BluetoothLeCallControl.this); - } - break; - } - case MESSAGE_TBS_SERVICE_DISCONNECTED: { - if (mServiceListener != null) { - mServiceListener.onServiceDisconnected(BluetoothProfile.LE_CALL_CONTROL); - } - break; - } - } - } - }; -} diff --git a/core/java/android/bluetooth/BluetoothManager.java b/core/java/android/bluetooth/BluetoothManager.java deleted file mode 100644 index fef6f225dd3bcf420633372e6a4e18603e7811e0..0000000000000000000000000000000000000000 --- a/core/java/android/bluetooth/BluetoothManager.java +++ /dev/null @@ -1,283 +0,0 @@ -/* - * Copyright (C) 2013 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.bluetooth; - -import android.annotation.RequiresFeature; -import android.annotation.RequiresNoPermission; -import android.annotation.RequiresPermission; -import android.annotation.SystemService; -import android.bluetooth.annotations.RequiresBluetoothConnectPermission; -import android.bluetooth.annotations.RequiresLegacyBluetoothPermission; -import android.content.AttributionSource; -import android.content.Context; -import android.content.pm.PackageManager; -import android.os.RemoteException; -import android.util.Log; - -import java.util.ArrayList; -import java.util.List; - -/** - * High level manager used to obtain an instance of an {@link BluetoothAdapter} - * and to conduct overall Bluetooth Management. - *

    - * Use {@link android.content.Context#getSystemService(java.lang.String)} - * with {@link Context#BLUETOOTH_SERVICE} to create an {@link BluetoothManager}, - * then call {@link #getAdapter} to obtain the {@link BluetoothAdapter}. - *

    - *
    - *

    Developer Guides

    - *

    - * For more information about using BLUETOOTH, read the Bluetooth developer - * guide. - *

    - *
    - * - * @see Context#getSystemService - * @see BluetoothAdapter#getDefaultAdapter() - */ -@SystemService(Context.BLUETOOTH_SERVICE) -@RequiresFeature(PackageManager.FEATURE_BLUETOOTH) -public final class BluetoothManager { - private static final String TAG = "BluetoothManager"; - private static final boolean DBG = false; - - private final AttributionSource mAttributionSource; - private final BluetoothAdapter mAdapter; - - /** - * @hide - */ - public BluetoothManager(Context context) { - mAttributionSource = (context != null) ? context.getAttributionSource() : - AttributionSource.myAttributionSource(); - mAdapter = BluetoothAdapter.createAdapter(mAttributionSource); - } - - /** - * Get the BLUETOOTH Adapter for this device. - * - * @return the BLUETOOTH Adapter - */ - @RequiresNoPermission - public BluetoothAdapter getAdapter() { - return mAdapter; - } - - /** - * Get the current connection state of the profile to the remote device. - * - *

    This is not specific to any application configuration but represents - * the connection state of the local Bluetooth adapter for certain profile. - * This can be used by applications like status bar which would just like - * to know the state of Bluetooth. - * - * @param device Remote bluetooth device. - * @param profile GATT or GATT_SERVER - * @return State of the profile connection. One of {@link BluetoothProfile#STATE_CONNECTED}, - * {@link BluetoothProfile#STATE_CONNECTING}, {@link BluetoothProfile#STATE_DISCONNECTED}, - * {@link BluetoothProfile#STATE_DISCONNECTING} - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public int getConnectionState(BluetoothDevice device, int profile) { - if (DBG) Log.d(TAG, "getConnectionState()"); - - List connectedDevices = getConnectedDevices(profile); - for (BluetoothDevice connectedDevice : connectedDevices) { - if (device.equals(connectedDevice)) { - return BluetoothProfile.STATE_CONNECTED; - } - } - - return BluetoothProfile.STATE_DISCONNECTED; - } - - /** - * Get connected devices for the specified profile. - * - *

    Return the set of devices which are in state {@link BluetoothProfile#STATE_CONNECTED} - * - *

    This is not specific to any application configuration but represents - * the connection state of Bluetooth for this profile. - * This can be used by applications like status bar which would just like - * to know the state of Bluetooth. - * - * @param profile GATT or GATT_SERVER - * @return List of devices. The list will be empty on error. - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public List getConnectedDevices(int profile) { - if (DBG) Log.d(TAG, "getConnectedDevices"); - return getDevicesMatchingConnectionStates(profile, new int[] { - BluetoothProfile.STATE_CONNECTED - }); - } - - /** - * Get a list of devices that match any of the given connection - * states. - * - *

    If none of the devices match any of the given states, - * an empty list will be returned. - * - *

    This is not specific to any application configuration but represents - * the connection state of the local Bluetooth adapter for this profile. - * This can be used by applications like status bar which would just like - * to know the state of the local adapter. - * - * @param profile GATT or GATT_SERVER - * @param states Array of states. States can be one of {@link BluetoothProfile#STATE_CONNECTED}, - * {@link BluetoothProfile#STATE_CONNECTING}, {@link BluetoothProfile#STATE_DISCONNECTED}, - * {@link BluetoothProfile#STATE_DISCONNECTING}, - * @return List of devices. The list will be empty on error. - */ - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public List getDevicesMatchingConnectionStates(int profile, int[] states) { - if (DBG) Log.d(TAG, "getDevicesMatchingConnectionStates"); - - if (profile != BluetoothProfile.GATT && profile != BluetoothProfile.GATT_SERVER) { - throw new IllegalArgumentException("Profile not supported: " + profile); - } - - List devices = new ArrayList(); - - try { - IBluetoothManager managerService = mAdapter.getBluetoothManager(); - IBluetoothGatt iGatt = managerService.getBluetoothGatt(); - if (iGatt == null) return devices; - devices = Attributable.setAttributionSource( - iGatt.getDevicesMatchingConnectionStates(states, mAttributionSource), - mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "", e); - } - - return devices; - } - - /** - * Open a GATT Server - * The callback is used to deliver results to Caller, such as connection status as well - * as the results of any other GATT server operations. - * The method returns a BluetoothGattServer instance. You can use BluetoothGattServer - * to conduct GATT server operations. - * - * @param context App context - * @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) { - - return (openGattServer(context, callback, BluetoothDevice.TRANSPORT_AUTO)); - } - - /** - * Open a GATT Server - * The callback is used to deliver results to Caller, such as connection status as well - * as the results of any other GATT server operations. - * The method returns a BluetoothGattServer instance. You can use BluetoothGattServer - * to conduct GATT server operations. - * - * @param context App context - * @param callback GATT server callback handler that will receive asynchronous callbacks. - * @param eatt_support idicates if server should use eatt channel for notifications. - * @return BluetoothGattServer instance - * @hide - */ - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public BluetoothGattServer openGattServer(Context context, - BluetoothGattServerCallback callback, boolean eatt_support) { - return (openGattServer(context, callback, BluetoothDevice.TRANSPORT_AUTO, eatt_support)); - } - - /** - * Open a GATT Server - * The callback is used to deliver results to Caller, such as connection status as well - * as the results of any other GATT server operations. - * The method returns a BluetoothGattServer instance. You can use BluetoothGattServer - * to conduct GATT server operations. - * - * @param context App context - * @param callback GATT server callback handler that will receive asynchronous callbacks. - * @param transport preferred transport for GATT connections to remote dual-mode devices {@link - * BluetoothDevice#TRANSPORT_AUTO} or {@link BluetoothDevice#TRANSPORT_BREDR} or {@link - * BluetoothDevice#TRANSPORT_LE} - * @return BluetoothGattServer instance - * @hide - */ - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public BluetoothGattServer openGattServer(Context context, - BluetoothGattServerCallback callback, int transport) { - return (openGattServer(context, callback, transport, false)); - } - - /** - * Open a GATT Server - * The callback is used to deliver results to Caller, such as connection status as well - * as the results of any other GATT server operations. - * The method returns a BluetoothGattServer instance. You can use BluetoothGattServer - * to conduct GATT server operations. - * - * @param context App context - * @param callback GATT server callback handler that will receive asynchronous callbacks. - * @param transport preferred transport for GATT connections to remote dual-mode devices {@link - * BluetoothDevice#TRANSPORT_AUTO} or {@link BluetoothDevice#TRANSPORT_BREDR} or {@link - * BluetoothDevice#TRANSPORT_LE} - * @param eatt_support idicates if server should use eatt channel for notifications. - * @return BluetoothGattServer instance - * @hide - */ - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public BluetoothGattServer openGattServer(Context context, - BluetoothGattServerCallback callback, int transport, boolean eatt_support) { - if (context == null || callback == null) { - throw new IllegalArgumentException("null parameter: " + context + " " + callback); - } - - // TODO(Bluetooth) check whether platform support BLE - // Do the check here or in GattServer? - - try { - IBluetoothManager managerService = mAdapter.getBluetoothManager(); - IBluetoothGatt iGatt = managerService.getBluetoothGatt(); - if (iGatt == null) { - Log.e(TAG, "Fail to get GATT Server connection"); - return null; - } - BluetoothGattServer mGattServer = - new BluetoothGattServer(iGatt, transport, mAdapter); - Boolean regStatus = mGattServer.registerCallback(callback, eatt_support); - return regStatus ? mGattServer : null; - } catch (RemoteException e) { - Log.e(TAG, "", e); - return null; - } - } -} diff --git a/core/java/android/bluetooth/BluetoothMap.java b/core/java/android/bluetooth/BluetoothMap.java deleted file mode 100644 index 56e4972624210383660b647fef1f79385a1af648..0000000000000000000000000000000000000000 --- a/core/java/android/bluetooth/BluetoothMap.java +++ /dev/null @@ -1,513 +0,0 @@ -/* - * 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.bluetooth; - -import static android.bluetooth.BluetoothUtils.getSyncTimeout; - -import android.Manifest; -import android.annotation.NonNull; -import android.annotation.RequiresNoPermission; -import android.annotation.RequiresPermission; -import android.annotation.SdkConstant; -import android.annotation.SdkConstant.SdkConstantType; -import android.annotation.SuppressLint; -import android.annotation.SystemApi; -import android.bluetooth.annotations.RequiresBluetoothConnectPermission; -import android.compat.annotation.UnsupportedAppUsage; -import android.content.AttributionSource; -import android.content.Context; -import android.os.Build; -import android.os.IBinder; -import android.os.RemoteException; -import android.util.CloseGuard; -import android.util.Log; - -import com.android.modules.utils.SynchronousResultReceiver; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.TimeoutException; - -/** - * This class provides the APIs to control the Bluetooth MAP - * Profile. - * - * @hide - */ -@SystemApi -public final class BluetoothMap implements BluetoothProfile, AutoCloseable { - - private static final String TAG = "BluetoothMap"; - private static final boolean DBG = true; - private static final boolean VDBG = false; - - private CloseGuard mCloseGuard; - - /** @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"; - - /** - * There was an error trying to obtain the state - * - * @hide - */ - public static final int STATE_ERROR = -1; - - /** @hide */ - public static final int RESULT_FAILURE = 0; - /** @hide */ - public static final int RESULT_SUCCESS = 1; - /** - * Connection canceled before completion. - * - * @hide - */ - public static final int RESULT_CANCELED = 2; - - private final BluetoothAdapter mAdapter; - private final AttributionSource mAttributionSource; - private final BluetoothProfileConnector mProfileConnector = - new BluetoothProfileConnector(this, BluetoothProfile.MAP, - "BluetoothMap", IBluetoothMap.class.getName()) { - @Override - public IBluetoothMap getServiceInterface(IBinder service) { - return IBluetoothMap.Stub.asInterface(service); - } - }; - - /** - * Create a BluetoothMap proxy object. - */ - /* package */ BluetoothMap(Context context, ServiceListener listener, - BluetoothAdapter adapter) { - if (DBG) Log.d(TAG, "Create BluetoothMap proxy object"); - mAdapter = adapter; - mAttributionSource = adapter.getAttributionSource(); - mProfileConnector.connect(context, listener); - mCloseGuard = new CloseGuard(); - mCloseGuard.open("close"); - } - - protected void finalize() { - if (mCloseGuard != null) { - mCloseGuard.warnIfOpen(); - } - close(); - } - - /** - * Close the connection to the backing service. - * Other public functions of BluetoothMap will return default error - * results once close() has been called. Multiple invocations of close() - * are ok. - * - * @hide - */ - @SystemApi - public void close() { - if (VDBG) log("close()"); - mProfileConnector.disconnect(); - } - - private IBluetoothMap getService() { - return mProfileConnector.getService(); - } - - /** - * Get the current state of the BluetoothMap service. - * - * @return One of the STATE_ return codes, or STATE_ERROR if this proxy object is currently not - * connected to the Map service. - * - * @hide - */ - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public int getState() { - if (VDBG) log("getState()"); - final IBluetoothMap service = getService(); - final int defaultValue = BluetoothMap.STATE_ERROR; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled()) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.getState(mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Get the currently connected remote Bluetooth device (PCE). - * - * @return The remote Bluetooth device, or null if not in connected or connecting state, or if - * this proxy object is not connected to the Map service. - * - * @hide - */ - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public BluetoothDevice getClient() { - if (VDBG) log("getClient()"); - final IBluetoothMap service = getService(); - final BluetoothDevice defaultValue = null; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled()) { - try { - final SynchronousResultReceiver recv = - new SynchronousResultReceiver(); - service.getClient(mAttributionSource, recv); - return Attributable.setAttributionSource( - recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue), - mAttributionSource); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Returns true if the specified Bluetooth device is connected. - * Returns false if not connected, or if this proxy object is not - * currently connected to the Map service. - * - * @hide - */ - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public boolean isConnected(BluetoothDevice device) { - if (VDBG) log("isConnected(" + device + ")"); - final IBluetoothMap service = getService(); - final boolean defaultValue = false; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device)) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.isConnected(device, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Initiate connection. Initiation of outgoing connections is not - * supported for MAP server. - * - * @hide - */ - @RequiresNoPermission - public boolean connect(BluetoothDevice device) { - if (DBG) log("connect(" + device + ")" + "not supported for MAPS"); - return false; - } - - /** - * Initiate disconnect. - * - * @param device Remote Bluetooth Device - * @return false on error, true otherwise - * - * @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 + ")"); - final IBluetoothMap service = getService(); - final boolean defaultValue = false; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device)) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.disconnect(device, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Check class bits for possible Map support. - * This is a simple heuristic that tries to guess if a device with the - * given class bits might support Map. It is not accurate for all - * devices. It tries to err on the side of false positives. - * - * @return True if this device might support Map. - * - * @hide - */ - public static boolean doesClassMatchSink(BluetoothClass btClass) { - // TODO optimize the rule - switch (btClass.getDeviceClass()) { - case BluetoothClass.Device.COMPUTER_DESKTOP: - case BluetoothClass.Device.COMPUTER_LAPTOP: - case BluetoothClass.Device.COMPUTER_SERVER: - case BluetoothClass.Device.COMPUTER_UNCATEGORIZED: - return true; - default: - return false; - } - } - - /** - * Get the list of connected devices. Currently at most one. - * - * @return list of connected devices - * - * @hide - */ - @SystemApi - @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) - public @NonNull List getConnectedDevices() { - if (DBG) log("getConnectedDevices()"); - final IBluetoothMap service = getService(); - final List defaultValue = new ArrayList(); - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled()) { - try { - final SynchronousResultReceiver> recv = - new SynchronousResultReceiver(); - service.getConnectedDevices(mAttributionSource, recv); - return Attributable.setAttributionSource( - recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue), - mAttributionSource); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Get the list of devices matching specified states. Currently at most one. - * - * @return list of matching devices - * - * @hide - */ - @RequiresBluetoothConnectPermission - @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT) - public List getDevicesMatchingConnectionStates(int[] states) { - if (DBG) log("getDevicesMatchingStates()"); - final IBluetoothMap service = getService(); - final List defaultValue = new ArrayList(); - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled()) { - try { - final SynchronousResultReceiver> recv = - new SynchronousResultReceiver(); - service.getDevicesMatchingConnectionStates(states, mAttributionSource, recv); - return Attributable.setAttributionSource( - recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue), - mAttributionSource); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Get connection state of device - * - * @return device connection state - * - * @hide - */ - @RequiresBluetoothConnectPermission - @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT) - public int getConnectionState(BluetoothDevice device) { - if (DBG) log("getConnectionState(" + device + ")"); - final IBluetoothMap service = getService(); - final int defaultValue = BluetoothProfile.STATE_DISCONNECTED; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device)) { - try { - final SynchronousResultReceiver recv = - new SynchronousResultReceiver(); - service.getConnectionState(device, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Set priority of the profile - * - *

    The device should already be paired. - * Priority can be one of {@link #PRIORITY_ON} or {@link #PRIORITY_OFF}, - * - * @param device Paired bluetooth device - * @param priority - * @return true if priority is set, false on error - * @hide - */ - @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) - public boolean setPriority(BluetoothDevice device, int priority) { - if (DBG) log("setPriority(" + device + ", " + priority + ")"); - return setConnectionPolicy(device, BluetoothAdapter.priorityToConnectionPolicy(priority)); - } - - /** - * Set connection policy of the profile - * - *

    The device should already be paired. - * Connection policy can be one of {@link #CONNECTION_POLICY_ALLOWED}, - * {@link #CONNECTION_POLICY_FORBIDDEN}, {@link #CONNECTION_POLICY_UNKNOWN} - * - * @param device Paired bluetooth device - * @param connectionPolicy is the connection policy to set to for this profile - * @return true if connectionPolicy is set, false on error - * @hide - */ - @SystemApi - @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) - public boolean setConnectionPolicy(@NonNull BluetoothDevice device, - @ConnectionPolicy int connectionPolicy) { - if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")"); - final IBluetoothMap service = getService(); - final boolean defaultValue = false; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device) - && (connectionPolicy == BluetoothProfile.CONNECTION_POLICY_FORBIDDEN - || connectionPolicy == BluetoothProfile.CONNECTION_POLICY_ALLOWED)) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.setConnectionPolicy(device, connectionPolicy, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Get the priority of the profile. - * - *

    The priority can be any of: - * {@link #PRIORITY_OFF}, {@link #PRIORITY_ON}, {@link #PRIORITY_UNDEFINED} - * - * @param device Bluetooth device - * @return priority of the device - * @hide - */ - @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) - public int getPriority(BluetoothDevice device) { - if (VDBG) log("getPriority(" + device + ")"); - return BluetoothAdapter.connectionPolicyToPriority(getConnectionPolicy(device)); - } - - /** - * Get the connection policy of the profile. - * - *

    The connection policy can be any of: - * {@link #CONNECTION_POLICY_ALLOWED}, {@link #CONNECTION_POLICY_FORBIDDEN}, - * {@link #CONNECTION_POLICY_UNKNOWN} - * - * @param device Bluetooth device - * @return connection policy of the device - * @hide - */ - @SystemApi - @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) - public @ConnectionPolicy int getConnectionPolicy(@NonNull BluetoothDevice device) { - if (VDBG) log("getConnectionPolicy(" + device + ")"); - final IBluetoothMap service = getService(); - final int defaultValue = BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device)) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.getConnectionPolicy(device, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - private static void log(String msg) { - Log.d(TAG, msg); - } - - private boolean isEnabled() { - return mAdapter.isEnabled(); - } - - private static boolean isValidDevice(BluetoothDevice device) { - return device != null && BluetoothAdapter.checkBluetoothAddress(device.getAddress()); - } -} diff --git a/core/java/android/bluetooth/BluetoothMapClient.java b/core/java/android/bluetooth/BluetoothMapClient.java deleted file mode 100644 index 03536f9aad39d5bbb1b8758031968f5b0bf10554..0000000000000000000000000000000000000000 --- a/core/java/android/bluetooth/BluetoothMapClient.java +++ /dev/null @@ -1,686 +0,0 @@ -/* - * Copyright (C) 2016 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.bluetooth; - -import static android.bluetooth.BluetoothUtils.getSyncTimeout; - -import android.Manifest; -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.annotation.RequiresPermission; -import android.annotation.SdkConstant; -import android.annotation.SdkConstant.SdkConstantType; -import android.annotation.SystemApi; -import android.app.PendingIntent; -import android.bluetooth.annotations.RequiresBluetoothConnectPermission; -import android.compat.annotation.UnsupportedAppUsage; -import android.content.AttributionSource; -import android.content.Context; -import android.net.Uri; -import android.os.Build; -import android.os.IBinder; -import android.os.RemoteException; -import android.util.Log; - -import com.android.modules.utils.SynchronousResultReceiver; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.concurrent.TimeoutException; - -/** - * This class provides the APIs to control the Bluetooth MAP MCE Profile. - * - * @hide - */ -@SystemApi -public final class BluetoothMapClient implements BluetoothProfile { - - private static final String TAG = "BluetoothMapClient"; - private static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG); - 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"; - - /** - * Action to notify read status changed - * - * @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"; - - /** - * Action to notify deleted status changed - * - * @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"; - - /** - * Extras used in ACTION_MESSAGE_RECEIVED intent. - * NOTE: HANDLE is only valid for a single session with the device. - */ - /** @hide */ - public static final String EXTRA_MESSAGE_HANDLE = - "android.bluetooth.mapmce.profile.extra.MESSAGE_HANDLE"; - /** @hide */ - public static final String EXTRA_MESSAGE_TIMESTAMP = - "android.bluetooth.mapmce.profile.extra.MESSAGE_TIMESTAMP"; - /** @hide */ - public static final String EXTRA_MESSAGE_READ_STATUS = - "android.bluetooth.mapmce.profile.extra.MESSAGE_READ_STATUS"; - /** @hide */ - public static final String EXTRA_SENDER_CONTACT_URI = - "android.bluetooth.mapmce.profile.extra.SENDER_CONTACT_URI"; - /** @hide */ - public static final String EXTRA_SENDER_CONTACT_NAME = - "android.bluetooth.mapmce.profile.extra.SENDER_CONTACT_NAME"; - - /** - * Used as a boolean extra in ACTION_MESSAGE_DELETED_STATUS_CHANGED - * Contains the MAP message deleted status - * Possible values are: - * true: deleted - * false: undeleted - * - * @hide - */ - public static final String EXTRA_MESSAGE_DELETED_STATUS = - "android.bluetooth.mapmce.profile.extra.MESSAGE_DELETED_STATUS"; - - /** - * Extra used in ACTION_MESSAGE_READ_STATUS_CHANGED or ACTION_MESSAGE_DELETED_STATUS_CHANGED - * Possible values are: - * 0: failure - * 1: success - * - * @hide - */ - public static final String EXTRA_RESULT_CODE = - "android.bluetooth.device.extra.RESULT_CODE"; - - /** - * There was an error trying to obtain the state - * @hide - */ - public static final int STATE_ERROR = -1; - - /** @hide */ - public static final int RESULT_FAILURE = 0; - /** @hide */ - public static final int RESULT_SUCCESS = 1; - /** - * Connection canceled before completion. - * @hide - */ - public static final int RESULT_CANCELED = 2; - /** @hide */ - private static final int UPLOADING_FEATURE_BITMASK = 0x08; - - /* - * UNREAD, READ, UNDELETED, DELETED are passed as parameters - * to setMessageStatus to indicate the messages new state. - */ - - /** @hide */ - public static final int UNREAD = 0; - /** @hide */ - public static final int READ = 1; - /** @hide */ - public static final int UNDELETED = 2; - /** @hide */ - public static final int DELETED = 3; - - private final BluetoothAdapter mAdapter; - private final AttributionSource mAttributionSource; - private final BluetoothProfileConnector mProfileConnector = - new BluetoothProfileConnector(this, BluetoothProfile.MAP_CLIENT, - "BluetoothMapClient", IBluetoothMapClient.class.getName()) { - @Override - public IBluetoothMapClient getServiceInterface(IBinder service) { - return IBluetoothMapClient.Stub.asInterface(service); - } - }; - - /** - * Create a BluetoothMapClient proxy object. - */ - /* package */ BluetoothMapClient(Context context, ServiceListener listener, - BluetoothAdapter adapter) { - if (DBG) Log.d(TAG, "Create BluetoothMapClient proxy object"); - mAdapter = adapter; - mAttributionSource = adapter.getAttributionSource(); - mProfileConnector.connect(context, listener); - } - - /** - * Close the connection to the backing service. - * Other public functions of BluetoothMap will return default error - * results once close() has been called. Multiple invocations of close() - * are ok. - * @hide - */ - public void close() { - mProfileConnector.disconnect(); - } - - private IBluetoothMapClient getService() { - return mProfileConnector.getService(); - } - - /** - * Returns true if the specified Bluetooth device is connected. - * Returns false if not connected, or if this proxy object is not - * 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 + ")"); - final IBluetoothMapClient service = getService(); - final boolean defaultValue = false; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable())); - } else if (isEnabled()) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.isConnected(device, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Initiate connection. Initiation of outgoing connections is not - * supported for MAP server. - * - * @hide - */ - @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) - public boolean connect(BluetoothDevice device) { - if (DBG) Log.d(TAG, "connect(" + device + ")" + "for MAPS MCE"); - final IBluetoothMapClient service = getService(); - final boolean defaultValue = false; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device)) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.connect(device, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Initiate disconnect. - * - * @param device Remote Bluetooth Device - * @return false on error, true otherwise - * - * @hide - */ - @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) - public boolean disconnect(BluetoothDevice device) { - if (DBG) Log.d(TAG, "disconnect(" + device + ")"); - final IBluetoothMapClient service = getService(); - final boolean defaultValue = false; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device)) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.disconnect(device, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Get the list of connected devices. Currently at most one. - * - * @return list of connected devices - * @hide - */ - @Override - @RequiresBluetoothConnectPermission - @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT) - public List getConnectedDevices() { - if (DBG) Log.d(TAG, "getConnectedDevices()"); - final IBluetoothMapClient service = getService(); - final List defaultValue = new ArrayList<>(); - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable())); - } else if (isEnabled()) { - try { - final SynchronousResultReceiver> recv = - new SynchronousResultReceiver(); - service.getConnectedDevices(mAttributionSource, recv); - return Attributable.setAttributionSource( - recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue), - mAttributionSource); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Get the list of devices matching specified states. Currently at most one. - * - * @return list of matching devices - * @hide - */ - @Override - @RequiresBluetoothConnectPermission - @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT) - public List getDevicesMatchingConnectionStates(int[] states) { - if (DBG) Log.d(TAG, "getDevicesMatchingStates()"); - final IBluetoothMapClient service = getService(); - final List defaultValue = new ArrayList<>(); - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable())); - } else if (isEnabled()) { - try { - final SynchronousResultReceiver> recv = - new SynchronousResultReceiver(); - service.getDevicesMatchingConnectionStates(states, mAttributionSource, recv); - return Attributable.setAttributionSource( - recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue), - mAttributionSource); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Get connection state of device - * - * @return device connection state - * @hide - */ - @Override - @RequiresBluetoothConnectPermission - @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT) - public int getConnectionState(BluetoothDevice device) { - if (DBG) Log.d(TAG, "getConnectionState(" + device + ")"); - final IBluetoothMapClient service = getService(); - final int defaultValue = BluetoothProfile.STATE_DISCONNECTED; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device)) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver<>(); - service.getConnectionState(device, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Set priority of the profile - * - *

    The device should already be paired. - * Priority can be one of {@link #PRIORITY_ON} or {@link #PRIORITY_OFF}, - * - * @param device Paired bluetooth device - * @param priority - * @return true if priority is set, false on error - * @hide - */ - @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) - public boolean setPriority(BluetoothDevice device, int priority) { - if (DBG) Log.d(TAG, "setPriority(" + device + ", " + priority + ")"); - return setConnectionPolicy(device, BluetoothAdapter.priorityToConnectionPolicy(priority)); - } - - /** - * Set connection policy of the profile - * - *

    The device should already be paired. - * Connection policy can be one of {@link #CONNECTION_POLICY_ALLOWED}, - * {@link #CONNECTION_POLICY_FORBIDDEN}, {@link #CONNECTION_POLICY_UNKNOWN} - * - * @param device Paired bluetooth device - * @param connectionPolicy is the connection policy to set to for this profile - * @return true if connectionPolicy is set, false on error - * @hide - */ - @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) - public boolean setConnectionPolicy(@NonNull BluetoothDevice device, - @ConnectionPolicy int connectionPolicy) { - if (DBG) Log.d(TAG, "setConnectionPolicy(" + device + ", " + connectionPolicy + ")"); - final IBluetoothMapClient service = getService(); - final boolean defaultValue = false; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device) - && (connectionPolicy == BluetoothProfile.CONNECTION_POLICY_FORBIDDEN - || connectionPolicy == BluetoothProfile.CONNECTION_POLICY_ALLOWED)) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.setConnectionPolicy(device, connectionPolicy, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Get the priority of the profile. - * - *

    The priority can be any of: - * {@link #PRIORITY_OFF}, {@link #PRIORITY_ON}, {@link #PRIORITY_UNDEFINED} - * - * @param device Bluetooth device - * @return priority of the device - * @hide - */ - @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) - public int getPriority(BluetoothDevice device) { - if (VDBG) Log.d(TAG, "getPriority(" + device + ")"); - return BluetoothAdapter.connectionPolicyToPriority(getConnectionPolicy(device)); - } - - /** - * Get the connection policy of the profile. - * - *

    The connection policy can be any of: - * {@link #CONNECTION_POLICY_ALLOWED}, {@link #CONNECTION_POLICY_FORBIDDEN}, - * {@link #CONNECTION_POLICY_UNKNOWN} - * - * @param device Bluetooth device - * @return connection policy of the device - * @hide - */ - @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) - public @ConnectionPolicy int getConnectionPolicy(@NonNull BluetoothDevice device) { - if (VDBG) Log.d(TAG, "getConnectionPolicy(" + device + ")"); - final IBluetoothMapClient service = getService(); - final int defaultValue = BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device)) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.getConnectionPolicy(device, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Send a message. - * - * Send an SMS message to either the contacts primary number or the telephone number specified. - * - * @param device Bluetooth device - * @param contacts Uri Collection of the contacts - * @param message Message to be sent - * @param sentIntent intent issued when message is sent - * @param deliveredIntent intent issued when message is delivered - * @return true if the message is enqueued, false on error - * @hide - */ - @SystemApi - @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.SEND_SMS, - }) - public boolean sendMessage(@NonNull BluetoothDevice device, @NonNull Collection contacts, - @NonNull String message, @Nullable PendingIntent sentIntent, - @Nullable PendingIntent deliveredIntent) { - return sendMessage(device, contacts.toArray(new Uri[contacts.size()]), message, sentIntent, - deliveredIntent); - } - - /** - * Send a message. - * - * Send an SMS message to either the contacts primary number or the telephone number specified. - * - * @param device Bluetooth device - * @param contacts Uri[] of the contacts - * @param message Message to be sent - * @param sentIntent intent issued when message is sent - * @param deliveredIntent intent issued when message is delivered - * @return true if the message is enqueued, false on error - * @hide - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.SEND_SMS, - }) - public boolean sendMessage(BluetoothDevice device, Uri[] contacts, String message, - PendingIntent sentIntent, PendingIntent deliveredIntent) { - if (DBG) Log.d(TAG, "sendMessage(" + device + ", " + contacts + ", " + message); - final IBluetoothMapClient service = getService(); - final boolean defaultValue = false; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device)) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.sendMessage(device, contacts, message, sentIntent, deliveredIntent, - mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Get unread messages. Unread messages will be published via {@link #ACTION_MESSAGE_RECEIVED}. - * - * @param device Bluetooth device - * @return true if the message is enqueued, false on error - * @hide - */ - @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.READ_SMS, - }) - public boolean getUnreadMessages(BluetoothDevice device) { - if (DBG) Log.d(TAG, "getUnreadMessages(" + device + ")"); - final IBluetoothMapClient service = getService(); - final boolean defaultValue = false; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device)) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.getUnreadMessages(device, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Returns the "Uploading" feature bit value from the SDP record's - * MapSupportedFeatures field (see Bluetooth MAP 1.4 spec, page 114). - * @param device The Bluetooth device to get this value for. - * @return Returns true if the Uploading bit value in SDP record's - * MapSupportedFeatures field is set. False is returned otherwise. - * @hide - */ - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public boolean isUploadingSupported(BluetoothDevice device) { - if (DBG) Log.d(TAG, "isUploadingSupported(" + device + ")"); - final IBluetoothMapClient service = getService(); - final int defaultValue = 0; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device)) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.getSupportedFeatures(device, mAttributionSource, recv); - return (recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue) - & UPLOADING_FEATURE_BITMASK) > 0; - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return false; - } - - /** - * Set message status of message on MSE - *

    - * When read status changed, the result will be published via - * {@link #ACTION_MESSAGE_READ_STATUS_CHANGED} - * When deleted status changed, the result will be published via - * {@link #ACTION_MESSAGE_DELETED_STATUS_CHANGED} - * - * @param device Bluetooth device - * @param handle message handle - * @param status UNREAD for "unread", READ for - * "read", UNDELETED for "undeleted", DELETED for - * "deleted", otherwise return error - * @return true if request has been sent, false on error - * @hide - */ - @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.READ_SMS, - }) - public boolean setMessageStatus(BluetoothDevice device, String handle, int status) { - if (DBG) Log.d(TAG, "setMessageStatus(" + device + ", " + handle + ", " + status + ")"); - final IBluetoothMapClient service = getService(); - final boolean defaultValue = false; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device) && handle != null && (status == READ - || status == UNREAD || status == UNDELETED || status == DELETED)) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.setMessageStatus(device, handle, status, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - private boolean isEnabled() { - return mAdapter.isEnabled(); - } - - private static boolean isValidDevice(BluetoothDevice device) { - return device != null && BluetoothAdapter.checkBluetoothAddress(device.getAddress()); - } -} diff --git a/core/java/android/bluetooth/BluetoothMasInstance.java b/core/java/android/bluetooth/BluetoothMasInstance.java deleted file mode 100644 index eeaf0854514659e0d22a8ffeb392207e7e9d7ce7..0000000000000000000000000000000000000000 --- a/core/java/android/bluetooth/BluetoothMasInstance.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright (C) 2014 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.bluetooth; - -import android.annotation.Nullable; -import android.os.Parcel; -import android.os.Parcelable; - -/** @hide */ -public final class BluetoothMasInstance implements Parcelable { - private final int mId; - private final String mName; - private final int mChannel; - private final int mMsgTypes; - - public BluetoothMasInstance(int id, String name, int channel, int msgTypes) { - mId = id; - mName = name; - mChannel = channel; - mMsgTypes = msgTypes; - } - - @Override - public boolean equals(@Nullable Object o) { - if (o instanceof BluetoothMasInstance) { - return mId == ((BluetoothMasInstance) o).mId; - } - return false; - } - - @Override - public int hashCode() { - return mId + (mChannel << 8) + (mMsgTypes << 16); - } - - @Override - public String toString() { - return Integer.toString(mId) + ":" + mName + ":" + mChannel + ":" - + Integer.toHexString(mMsgTypes); - } - - @Override - public int describeContents() { - return 0; - } - - public static final @android.annotation.NonNull Parcelable.Creator CREATOR = - new Parcelable.Creator() { - public BluetoothMasInstance createFromParcel(Parcel in) { - return new BluetoothMasInstance(in.readInt(), in.readString(), - in.readInt(), in.readInt()); - } - - public BluetoothMasInstance[] newArray(int size) { - return new BluetoothMasInstance[size]; - } - }; - - @Override - public void writeToParcel(Parcel out, int flags) { - out.writeInt(mId); - out.writeString(mName); - out.writeInt(mChannel); - out.writeInt(mMsgTypes); - } - - public static final class MessageType { - public static final int EMAIL = 0x01; - public static final int SMS_GSM = 0x02; - public static final int SMS_CDMA = 0x04; - public static final int MMS = 0x08; - } - - public int getId() { - return mId; - } - - public String getName() { - return mName; - } - - public int getChannel() { - return mChannel; - } - - public int getMsgTypes() { - return mMsgTypes; - } - - public boolean msgSupported(int msg) { - return (mMsgTypes & msg) != 0; - } -} diff --git a/core/java/android/bluetooth/BluetoothOutputStream.java b/core/java/android/bluetooth/BluetoothOutputStream.java deleted file mode 100644 index ac2b3edb0eb85df2c05b7c9f1db24b56d5d4868f..0000000000000000000000000000000000000000 --- a/core/java/android/bluetooth/BluetoothOutputStream.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (C) 2009 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.bluetooth; - -import android.annotation.SuppressLint; - -import java.io.IOException; -import java.io.OutputStream; - -/** - * BluetoothOutputStream. - * - * Used to read from a Bluetooth socket. - * - * @hide - */ -@SuppressLint("AndroidFrameworkBluetoothPermission") -/*package*/ final class BluetoothOutputStream extends OutputStream { - private BluetoothSocket mSocket; - - /*package*/ BluetoothOutputStream(BluetoothSocket s) { - mSocket = s; - } - - /** - * Close this output stream and the socket associated with it. - */ - public void close() throws IOException { - mSocket.close(); - } - - /** - * Writes a single byte to this stream. Only the least significant byte of - * the integer {@code oneByte} is written to the stream. - * - * @param oneByte the byte to be written. - * @throws IOException if an error occurs while writing to this stream. - * @since Android 1.0 - */ - public void write(int oneByte) throws IOException { - byte[] b = new byte[1]; - b[0] = (byte) oneByte; - mSocket.write(b, 0, 1); - } - - /** - * Writes {@code count} bytes from the byte array {@code buffer} starting - * at position {@code offset} to this stream. - * - * @param b the buffer to be written. - * @param offset the start position in {@code buffer} from where to get bytes. - * @param count the number of bytes from {@code buffer} to write to this stream. - * @throws IOException if an error occurs while writing to this stream. - * @throws IndexOutOfBoundsException if {@code offset < 0} or {@code count < 0}, or if {@code - * offset + count} is bigger than the length of {@code buffer}. - * @since Android 1.0 - */ - public void write(byte[] b, int offset, int count) throws IOException { - if (b == null) { - throw new NullPointerException("buffer is null"); - } - if ((offset | count) < 0 || count > b.length - offset) { - throw new IndexOutOfBoundsException("invalid offset or length"); - } - mSocket.write(b, offset, count); - } -} diff --git a/core/java/android/bluetooth/BluetoothPan.java b/core/java/android/bluetooth/BluetoothPan.java deleted file mode 100644 index d4ad4ef47acd7626d1ac24c38df7d4f614d71a18..0000000000000000000000000000000000000000 --- a/core/java/android/bluetooth/BluetoothPan.java +++ /dev/null @@ -1,525 +0,0 @@ -/* - * 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.bluetooth; - -import static android.bluetooth.BluetoothUtils.getSyncTimeout; - -import android.annotation.IntDef; -import android.annotation.NonNull; -import android.annotation.RequiresPermission; -import android.annotation.SdkConstant; -import android.annotation.SdkConstant.SdkConstantType; -import android.annotation.SuppressLint; -import android.annotation.SystemApi; -import android.bluetooth.annotations.RequiresBluetoothConnectPermission; -import android.bluetooth.annotations.RequiresLegacyBluetoothPermission; -import android.compat.annotation.UnsupportedAppUsage; -import android.content.AttributionSource; -import android.content.Context; -import android.os.Build; -import android.os.IBinder; -import android.os.RemoteException; -import android.util.Log; - -import com.android.modules.utils.SynchronousResultReceiver; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.TimeoutException; - -/** - * This class provides the APIs to control the Bluetooth Pan - * Profile. - * - *

    BluetoothPan is a proxy object for controlling the Bluetooth - * Service via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get - * the BluetoothPan proxy object. - * - *

    Each method is protected with its appropriate permission. - * - * @hide - */ -@SystemApi -public final class BluetoothPan implements BluetoothProfile { - private static final String TAG = "BluetoothPan"; - private static final boolean DBG = true; - private static final boolean VDBG = false; - - /** - * Intent used to broadcast the change in connection state of the Pan - * profile. - * - *

    This intent will have 4 extras: - *

      - *
    • {@link #EXTRA_STATE} - The current state of the profile.
    • - *
    • {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile.
    • - *
    • {@link BluetoothDevice#EXTRA_DEVICE} - The remote device.
    • - *
    • {@link #EXTRA_LOCAL_ROLE} - Which local role the remote device is - * bound to.
    • - *
    - * - *

    {@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of - * {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING}, - * {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}. - * - *

    {@link #EXTRA_LOCAL_ROLE} can be one of {@link #LOCAL_NAP_ROLE} or - * {@link #LOCAL_PANU_ROLE} - */ - @SuppressLint("ActionValue") - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - public static final String ACTION_CONNECTION_STATE_CHANGED = - "android.bluetooth.pan.profile.action.CONNECTION_STATE_CHANGED"; - - /** - * Extra for {@link #ACTION_CONNECTION_STATE_CHANGED} intent - * The local role of the PAN profile that the remote device is bound to. - * It can be one of {@link #LOCAL_NAP_ROLE} or {@link #LOCAL_PANU_ROLE}. - */ - @SuppressLint("ActionValue") - public static final String EXTRA_LOCAL_ROLE = "android.bluetooth.pan.extra.LOCAL_ROLE"; - - /** - * Intent used to broadcast the change in tethering state of the Pan - * Profile - * - *

    This intent will have 1 extra: - *

      - *
    • {@link #EXTRA_TETHERING_STATE} - The current state of Bluetooth - * tethering.
    • - *
    - * - *

    {@link #EXTRA_TETHERING_STATE} can be any of {@link #TETHERING_STATE_OFF} or - * {@link #TETHERING_STATE_ON} - */ - @RequiresLegacyBluetoothPermission - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - public static final String ACTION_TETHERING_STATE_CHANGED = - "android.bluetooth.action.TETHERING_STATE_CHANGED"; - - /** - * Extra for {@link #ACTION_TETHERING_STATE_CHANGED} intent - * The tethering state of the PAN profile. - * It can be one of {@link #TETHERING_STATE_OFF} or {@link #TETHERING_STATE_ON}. - */ - public static final String EXTRA_TETHERING_STATE = - "android.bluetooth.extra.TETHERING_STATE"; - - /** @hide */ - @IntDef({PAN_ROLE_NONE, LOCAL_NAP_ROLE, LOCAL_PANU_ROLE}) - @Retention(RetentionPolicy.SOURCE) - public @interface LocalPanRole {} - - public static final int PAN_ROLE_NONE = 0; - /** - * The local device is acting as a Network Access Point. - */ - public static final int LOCAL_NAP_ROLE = 1; - - /** - * The local device is acting as a PAN User. - */ - public static final int LOCAL_PANU_ROLE = 2; - - /** @hide */ - @IntDef({PAN_ROLE_NONE, REMOTE_NAP_ROLE, REMOTE_PANU_ROLE}) - @Retention(RetentionPolicy.SOURCE) - public @interface RemotePanRole {} - - public static final int REMOTE_NAP_ROLE = 1; - - public static final int REMOTE_PANU_ROLE = 2; - - /** @hide **/ - @IntDef({TETHERING_STATE_OFF, TETHERING_STATE_ON}) - @Retention(RetentionPolicy.SOURCE) - public @interface TetheringState{} - - public static final int TETHERING_STATE_OFF = 1; - - public static final int TETHERING_STATE_ON = 2; - /** - * Return codes for the connect and disconnect Bluez / Dbus calls. - * - * @hide - */ - public static final int PAN_DISCONNECT_FAILED_NOT_CONNECTED = 1000; - - /** - * @hide - */ - public static final int PAN_CONNECT_FAILED_ALREADY_CONNECTED = 1001; - - /** - * @hide - */ - public static final int PAN_CONNECT_FAILED_ATTEMPT_FAILED = 1002; - - /** - * @hide - */ - public static final int PAN_OPERATION_GENERIC_FAILURE = 1003; - - /** - * @hide - */ - public static final int PAN_OPERATION_SUCCESS = 1004; - - private final Context mContext; - - private final BluetoothAdapter mAdapter; - private final AttributionSource mAttributionSource; - private final BluetoothProfileConnector mProfileConnector = - new BluetoothProfileConnector(this, BluetoothProfile.PAN, - "BluetoothPan", IBluetoothPan.class.getName()) { - @Override - public IBluetoothPan getServiceInterface(IBinder service) { - return IBluetoothPan.Stub.asInterface(service); - } - }; - - - /** - * Create a BluetoothPan proxy object for interacting with the local - * Bluetooth Service which handles the Pan profile - * - * @hide - */ - @UnsupportedAppUsage - /* package */ BluetoothPan(Context context, ServiceListener listener, - BluetoothAdapter adapter) { - mAdapter = adapter; - mAttributionSource = adapter.getAttributionSource(); - mContext = context; - mProfileConnector.connect(context, listener); - } - - /** - * Closes the connection to the service and unregisters callbacks - */ - @UnsupportedAppUsage - void close() { - if (VDBG) log("close()"); - mProfileConnector.disconnect(); - } - - private IBluetoothPan getService() { - return mProfileConnector.getService(); - } - - /** @hide */ - protected void finalize() { - close(); - } - - /** - * Initiate connection to a profile of the remote bluetooth device. - * - *

    This API returns false in scenarios like the profile on the - * device is already connected or Bluetooth is not turned on. - * When this API returns true, it is guaranteed that - * connection state intent for the profile will be broadcasted with - * the state. Users can get the connection state of the profile - * from this intent. - * - * @param device Remote Bluetooth Device - * @return false on immediate error, true otherwise - * @hide - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) - public boolean connect(BluetoothDevice device) { - if (DBG) log("connect(" + device + ")"); - final IBluetoothPan service = getService(); - final boolean defaultValue = false; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device)) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.connect(device, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Initiate disconnection from a profile - * - *

    This API will return false in scenarios like the profile on the - * Bluetooth device is not in connected state etc. When this API returns, - * true, it is guaranteed that the connection state change - * intent will be broadcasted with the state. Users can get the - * disconnection state of the profile from this intent. - * - *

    If the disconnection is initiated by a remote device, the state - * will transition from {@link #STATE_CONNECTED} to - * {@link #STATE_DISCONNECTED}. If the disconnect is initiated by the - * host (local) device the state will transition from - * {@link #STATE_CONNECTED} to state {@link #STATE_DISCONNECTING} to - * state {@link #STATE_DISCONNECTED}. The transition to - * {@link #STATE_DISCONNECTING} can be used to distinguish between the - * two scenarios. - * - * @param device Remote Bluetooth Device - * @return false on immediate error, true otherwise - * @hide - */ - @UnsupportedAppUsage - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public boolean disconnect(BluetoothDevice device) { - if (DBG) log("disconnect(" + device + ")"); - final IBluetoothPan service = getService(); - final boolean defaultValue = false; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device)) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.disconnect(device, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Set connection policy of the profile - * - *

    The device should already be paired. - * Connection policy can be one of {@link #CONNECTION_POLICY_ALLOWED}, - * {@link #CONNECTION_POLICY_FORBIDDEN}, {@link #CONNECTION_POLICY_UNKNOWN} - * - * @param device Paired bluetooth device - * @param connectionPolicy is the connection policy to set to for this profile - * @return true if connectionPolicy is set, false on error - * @hide - */ - @SystemApi - @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) - public boolean setConnectionPolicy(@NonNull BluetoothDevice device, - @ConnectionPolicy int connectionPolicy) { - if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")"); - final IBluetoothPan service = getService(); - final boolean defaultValue = false; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device) - && (connectionPolicy == BluetoothProfile.CONNECTION_POLICY_FORBIDDEN - || connectionPolicy == BluetoothProfile.CONNECTION_POLICY_ALLOWED)) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.setConnectionPolicy(device, connectionPolicy, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * {@inheritDoc} - * @hide - */ - @SystemApi - @Override - @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) - public @NonNull List getConnectedDevices() { - if (VDBG) log("getConnectedDevices()"); - final IBluetoothPan service = getService(); - final List defaultValue = new ArrayList(); - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled()) { - try { - final SynchronousResultReceiver> recv = - new SynchronousResultReceiver(); - service.getConnectedDevices(mAttributionSource, recv); - return Attributable.setAttributionSource( - recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue), - mAttributionSource); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * {@inheritDoc} - * @hide - */ - @Override - @RequiresLegacyBluetoothPermission - @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) - public List getDevicesMatchingConnectionStates(int[] states) { - if (VDBG) log("getDevicesMatchingStates()"); - final IBluetoothPan service = getService(); - final List defaultValue = new ArrayList(); - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled()) { - try { - final SynchronousResultReceiver> recv = - new SynchronousResultReceiver(); - service.getDevicesMatchingConnectionStates(states, mAttributionSource, recv); - return Attributable.setAttributionSource( - recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue), - mAttributionSource); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * {@inheritDoc} - * @hide - */ - @SystemApi - @Override - @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) - public int getConnectionState(@NonNull BluetoothDevice device) { - if (VDBG) log("getState(" + device + ")"); - final IBluetoothPan service = getService(); - final int defaultValue = BluetoothProfile.STATE_DISCONNECTED; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device)) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.getConnectionState(device, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Turns on/off bluetooth tethering - * - * @param value is whether to enable or disable bluetooth tethering - * @hide - */ - @SystemApi - @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - android.Manifest.permission.TETHER_PRIVILEGED, - }) - public void setBluetoothTethering(boolean value) { - String pkgName = mContext.getOpPackageName(); - if (DBG) log("setBluetoothTethering(" + value + "), calling package:" + pkgName); - final IBluetoothPan service = getService(); - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled()) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.setBluetoothTethering(value, mAttributionSource, recv); - recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(null); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - } - - /** - * Determines whether tethering is enabled - * - * @return true if tethering is on, false if not or some error occurred - * @hide - */ - @SystemApi - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public boolean isTetheringOn() { - if (VDBG) log("isTetheringOn()"); - final IBluetoothPan service = getService(); - final boolean defaultValue = false; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled()) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.isTetheringOn(mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - @UnsupportedAppUsage - private boolean isEnabled() { - return mAdapter.getState() == BluetoothAdapter.STATE_ON; - } - - @UnsupportedAppUsage - private static boolean isValidDevice(BluetoothDevice device) { - return device != null && BluetoothAdapter.checkBluetoothAddress(device.getAddress()); - } - - @UnsupportedAppUsage - private static void log(String msg) { - Log.d(TAG, msg); - } -} diff --git a/core/java/android/bluetooth/BluetoothPbap.java b/core/java/android/bluetooth/BluetoothPbap.java deleted file mode 100644 index de2db9c2ca86272ffb54c54258e5d3deaf736f53..0000000000000000000000000000000000000000 --- a/core/java/android/bluetooth/BluetoothPbap.java +++ /dev/null @@ -1,317 +0,0 @@ -/* - * 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.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.bluetooth.annotations.RequiresBluetoothConnectPermission; -import android.compat.annotation.UnsupportedAppUsage; -import android.content.AttributionSource; -import android.content.Context; -import android.os.Build; -import android.os.IBinder; -import android.os.RemoteException; -import android.util.Log; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -/** - * Public API for controlling the Bluetooth Pbap Service. This includes - * Bluetooth Phone book Access profile. - * BluetoothPbap is a proxy object for controlling the Bluetooth Pbap - * Service via IPC. - * - * Creating a BluetoothPbap object will create a binding with the - * BluetoothPbap service. Users of this object should call close() when they - * are finished with the BluetoothPbap, so that this proxy object can unbind - * from the service. - * - * This BluetoothPbap object is not immediately bound to the - * BluetoothPbap service. Use the ServiceListener interface to obtain a - * notification when it is bound, this is especially important if you wish to - * immediately call methods on BluetoothPbap after construction. - * - * To get an instance of the BluetoothPbap class, you can call - * {@link BluetoothAdapter#getProfileProxy(Context, ServiceListener, int)} with the final param - * being {@link BluetoothProfile#PBAP}. The ServiceListener should be able to get the instance of - * BluetoothPbap in {@link android.bluetooth.BluetoothProfile.ServiceListener#onServiceConnected}. - * - * Android only supports one connected Bluetooth Pce at a time. - * - * @hide - */ -@SystemApi -public class BluetoothPbap implements BluetoothProfile { - - private static final String TAG = "BluetoothPbap"; - private static final boolean DBG = false; - - /** - * Intent used to broadcast the change in connection state of the PBAP - * profile. - * - *

    This intent will have 3 extras: - *

      - *
    • {@link BluetoothProfile#EXTRA_STATE} - The current state of the profile.
    • - *
    • {@link BluetoothProfile#EXTRA_PREVIOUS_STATE}- The previous state of the profile.
    • - *
    • {@link BluetoothDevice#EXTRA_DEVICE} - The remote device.
    • - *
    - *

    {@link BluetoothProfile#EXTRA_STATE} or {@link BluetoothProfile#EXTRA_PREVIOUS_STATE} - * can be any of {@link BluetoothProfile#STATE_DISCONNECTED}, - * {@link BluetoothProfile#STATE_CONNECTING}, {@link BluetoothProfile#STATE_CONNECTED}, - * {@link BluetoothProfile#STATE_DISCONNECTING}. - * - * @hide - */ - @SuppressLint("ActionValue") - @SystemApi - @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"; - - private final AttributionSource mAttributionSource; - - /** @hide */ - public static final int RESULT_FAILURE = 0; - /** @hide */ - public static final int RESULT_SUCCESS = 1; - /** - * Connection canceled before completion. - * - * @hide - */ - public static final int RESULT_CANCELED = 2; - - private BluetoothAdapter mAdapter; - private final BluetoothProfileConnector mProfileConnector = - new BluetoothProfileConnector(this, BluetoothProfile.PBAP, "BluetoothPbap", - IBluetoothPbap.class.getName()) { - @Override - public IBluetoothPbap getServiceInterface(IBinder service) { - return IBluetoothPbap.Stub.asInterface(service); - } - }; - - /** - * Create a BluetoothPbap proxy object. - * - * @hide - */ - public BluetoothPbap(Context context, ServiceListener listener, BluetoothAdapter adapter) { - mAdapter = adapter; - mAttributionSource = adapter.getAttributionSource(); - mProfileConnector.connect(context, listener); - } - - /** @hide */ - protected void finalize() throws Throwable { - try { - close(); - } finally { - super.finalize(); - } - } - - /** - * Close the connection to the backing service. - * Other public functions of BluetoothPbap will return default error - * results once close() has been called. Multiple invocations of close() - * are ok. - * - * @hide - */ - public synchronized void close() { - mProfileConnector.disconnect(); - } - - private IBluetoothPbap getService() { - return (IBluetoothPbap) mProfileConnector.getService(); - } - - /** - * {@inheritDoc} - * - * @hide - */ - @Override - @RequiresBluetoothConnectPermission - @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT) - public List getConnectedDevices() { - log("getConnectedDevices()"); - final IBluetoothPbap service = getService(); - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - return new ArrayList(); - } - try { - return Attributable.setAttributionSource( - service.getConnectedDevices(mAttributionSource), mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, e.toString()); - } - return new ArrayList(); - } - - /** - * {@inheritDoc} - * - * @hide - */ - @SystemApi - @Override - @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) - public @BtProfileState int getConnectionState(@NonNull BluetoothDevice device) { - log("getConnectionState: device=" + device); - try { - final IBluetoothPbap service = getService(); - if (service != null && isEnabled() && isValidDevice(device)) { - return service.getConnectionState(device, mAttributionSource); - } - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - } - return BluetoothProfile.STATE_DISCONNECTED; - } catch (RemoteException e) { - Log.e(TAG, e.toString()); - } - return BluetoothProfile.STATE_DISCONNECTED; - } - - /** - * {@inheritDoc} - * - * @hide - */ - @Override - @RequiresBluetoothConnectPermission - @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT) - public List getDevicesMatchingConnectionStates(int[] states) { - log("getDevicesMatchingConnectionStates: states=" + Arrays.toString(states)); - final IBluetoothPbap service = getService(); - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - return new ArrayList(); - } - try { - return Attributable.setAttributionSource( - service.getDevicesMatchingConnectionStates(states, mAttributionSource), - mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, e.toString()); - } - return new ArrayList(); - } - - /** - * Set connection policy of the profile and tries to disconnect it if connectionPolicy is - * {@link BluetoothProfile#CONNECTION_POLICY_FORBIDDEN} - * - *

    The device should already be paired. - * Connection policy can be one of: - * {@link BluetoothProfile#CONNECTION_POLICY_ALLOWED}, - * {@link BluetoothProfile#CONNECTION_POLICY_FORBIDDEN}, - * {@link BluetoothProfile#CONNECTION_POLICY_UNKNOWN} - * - * @param device Paired bluetooth device - * @param connectionPolicy is the connection policy to set to for this profile - * @return true if connectionPolicy is set, false on error - * - * @hide - */ - @SystemApi - @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) - public boolean setConnectionPolicy(@NonNull BluetoothDevice device, - @ConnectionPolicy int connectionPolicy) { - if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")"); - try { - final IBluetoothPbap service = getService(); - if (service != null && isEnabled() - && isValidDevice(device)) { - if (connectionPolicy != BluetoothProfile.CONNECTION_POLICY_FORBIDDEN - && connectionPolicy != BluetoothProfile.CONNECTION_POLICY_ALLOWED) { - return false; - } - return service.setConnectionPolicy(device, connectionPolicy, mAttributionSource); - } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return false; - } catch (RemoteException e) { - Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); - return false; - } - } - - /** - * Disconnects the current Pbap client (PCE). Currently this call blocks, - * it may soon be made asynchronous. Returns false if this proxy object is - * not currently connected to the Pbap service. - * - * @hide - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public boolean disconnect(BluetoothDevice device) { - log("disconnect()"); - final IBluetoothPbap service = getService(); - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - return false; - } - try { - service.disconnect(device, mAttributionSource); - return true; - } catch (RemoteException e) { - Log.e(TAG, e.toString()); - } - return false; - } - - private boolean isEnabled() { - if (mAdapter.getState() == BluetoothAdapter.STATE_ON) return true; - return false; - } - - private boolean isValidDevice(BluetoothDevice device) { - if (device == null) return false; - - if (BluetoothAdapter.checkBluetoothAddress(device.getAddress())) return true; - return false; - } - - private static void log(String msg) { - if (DBG) { - Log.d(TAG, msg); - } - } -} diff --git a/core/java/android/bluetooth/BluetoothPbapClient.java b/core/java/android/bluetooth/BluetoothPbapClient.java deleted file mode 100644 index e096de8cb829bf149809917ad84ba3320282a9e9..0000000000000000000000000000000000000000 --- a/core/java/android/bluetooth/BluetoothPbapClient.java +++ /dev/null @@ -1,405 +0,0 @@ -/* - * Copyright (C) 2016 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.bluetooth; - -import static android.bluetooth.BluetoothUtils.getSyncTimeout; - -import android.Manifest; -import android.annotation.NonNull; -import android.annotation.RequiresPermission; -import android.annotation.SdkConstant; -import android.annotation.SdkConstant.SdkConstantType; -import android.bluetooth.annotations.RequiresBluetoothConnectPermission; -import android.content.AttributionSource; -import android.content.Context; -import android.os.IBinder; -import android.os.RemoteException; -import android.util.Log; - -import com.android.modules.utils.SynchronousResultReceiver; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.TimeoutException; - -/** - * This class provides the APIs to control the Bluetooth PBAP Client Profile. - * - * @hide - */ -public final class BluetoothPbapClient implements BluetoothProfile { - - private static final String TAG = "BluetoothPbapClient"; - 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"; - - /** There was an error trying to obtain the state */ - public static final int STATE_ERROR = -1; - - public static final int RESULT_FAILURE = 0; - public static final int RESULT_SUCCESS = 1; - /** Connection canceled before completion. */ - public static final int RESULT_CANCELED = 2; - - private final BluetoothAdapter mAdapter; - private final AttributionSource mAttributionSource; - private final BluetoothProfileConnector mProfileConnector = - new BluetoothProfileConnector(this, BluetoothProfile.PBAP_CLIENT, - "BluetoothPbapClient", IBluetoothPbapClient.class.getName()) { - @Override - public IBluetoothPbapClient getServiceInterface(IBinder service) { - return IBluetoothPbapClient.Stub.asInterface(service); - } - }; - - /** - * Create a BluetoothPbapClient proxy object. - */ - BluetoothPbapClient(Context context, ServiceListener listener, BluetoothAdapter adapter) { - if (DBG) { - Log.d(TAG, "Create BluetoothPbapClient proxy object"); - } - mAdapter = adapter; - mAttributionSource = adapter.getAttributionSource(); - mProfileConnector.connect(context, listener); - } - - protected void finalize() throws Throwable { - try { - close(); - } finally { - super.finalize(); - } - } - - /** - * Close the connection to the backing service. - * Other public functions of BluetoothPbapClient will return default error - * results once close() has been called. Multiple invocations of close() - * are ok. - */ - public synchronized void close() { - mProfileConnector.disconnect(); - } - - private IBluetoothPbapClient getService() { - return mProfileConnector.getService(); - } - - /** - * Initiate connection. - * Upon successful connection to remote PBAP server the Client will - * attempt to automatically download the users phonebook and call log. - * - * @param device a remote device we want connect to - * @return true if command has been issued successfully; false - * otherwise; - * - * @hide - */ - @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) - public boolean connect(BluetoothDevice device) { - if (DBG) { - log("connect(" + device + ") for PBAP Client."); - } - final IBluetoothPbapClient service = getService(); - final boolean defaultValue = false; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device)) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.connect(device, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Initiate disconnect. - * - * @param device Remote Bluetooth Device - * @return false on error, true otherwise - * - * @hide - */ - @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) - public boolean disconnect(BluetoothDevice device) { - if (DBG) { - log("disconnect(" + device + ")" + new Exception()); - } - final IBluetoothPbapClient service = getService(); - final boolean defaultValue = true; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device)) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.disconnect(device, mAttributionSource, recv); - recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - return true; - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Get the list of connected devices. - * Currently at most one. - * - * @return list of connected devices - */ - @Override - @RequiresBluetoothConnectPermission - @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT) - public List getConnectedDevices() { - if (DBG) { - log("getConnectedDevices()"); - } - final IBluetoothPbapClient service = getService(); - final List defaultValue = new ArrayList(); - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled()) { - try { - final SynchronousResultReceiver> recv = - new SynchronousResultReceiver(); - service.getConnectedDevices(mAttributionSource, recv); - return Attributable.setAttributionSource( - recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue), - mAttributionSource); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Get the list of devices matching specified states. Currently at most one. - * - * @return list of matching devices - */ - @Override - @RequiresBluetoothConnectPermission - @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT) - public List getDevicesMatchingConnectionStates(int[] states) { - if (DBG) { - log("getDevicesMatchingStates()"); - } - final IBluetoothPbapClient service = getService(); - final List defaultValue = new ArrayList(); - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled()) { - try { - final SynchronousResultReceiver> recv = - new SynchronousResultReceiver(); - service.getDevicesMatchingConnectionStates(states, mAttributionSource, recv); - return Attributable.setAttributionSource( - recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue), - mAttributionSource); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Get connection state of device - * - * @return device connection state - */ - @Override - @RequiresBluetoothConnectPermission - @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT) - public int getConnectionState(BluetoothDevice device) { - if (DBG) { - log("getConnectionState(" + device + ")"); - } - final IBluetoothPbapClient service = getService(); - final int defaultValue = BluetoothProfile.STATE_DISCONNECTED; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device)) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.getConnectionState(device, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - private static void log(String msg) { - Log.d(TAG, msg); - } - - private boolean isEnabled() { - return mAdapter.isEnabled(); - } - - private static boolean isValidDevice(BluetoothDevice device) { - return device != null && BluetoothAdapter.checkBluetoothAddress(device.getAddress()); - } - - /** - * Set priority of the profile - * - *

    The device should already be paired. - * Priority can be one of {@link #PRIORITY_ON} or {@link #PRIORITY_OFF}, - * - * @param device Paired bluetooth device - * @param priority - * @return true if priority is set, false on error - * @hide - */ - @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) - public boolean setPriority(BluetoothDevice device, int priority) { - if (DBG) log("setPriority(" + device + ", " + priority + ")"); - return setConnectionPolicy(device, BluetoothAdapter.priorityToConnectionPolicy(priority)); - } - - /** - * Set connection policy of the profile - * - *

    The device should already be paired. - * Connection policy can be one of {@link #CONNECTION_POLICY_ALLOWED}, - * {@link #CONNECTION_POLICY_FORBIDDEN}, {@link #CONNECTION_POLICY_UNKNOWN} - * - * @param device Paired bluetooth device - * @param connectionPolicy is the connection policy to set to for this profile - * @return true if connectionPolicy is set, false on error - * @hide - */ - @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) - public boolean setConnectionPolicy(@NonNull BluetoothDevice device, - @ConnectionPolicy int connectionPolicy) { - if (DBG) { - log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")"); - } - final IBluetoothPbapClient service = getService(); - final boolean defaultValue = false; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device) - && (connectionPolicy == BluetoothProfile.CONNECTION_POLICY_FORBIDDEN - || connectionPolicy == BluetoothProfile.CONNECTION_POLICY_ALLOWED)) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.setConnectionPolicy(device, connectionPolicy, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Get the priority of the profile. - * - *

    The priority can be any of: - * {@link #PRIORITY_OFF}, {@link #PRIORITY_ON}, {@link #PRIORITY_UNDEFINED} - * - * @param device Bluetooth device - * @return priority of the device - * @hide - */ - @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) - public int getPriority(BluetoothDevice device) { - if (VDBG) log("getPriority(" + device + ")"); - return BluetoothAdapter.connectionPolicyToPriority(getConnectionPolicy(device)); - } - - /** - * Get the connection policy of the profile. - * - *

    The connection policy can be any of: - * {@link #CONNECTION_POLICY_ALLOWED}, {@link #CONNECTION_POLICY_FORBIDDEN}, - * {@link #CONNECTION_POLICY_UNKNOWN} - * - * @param device Bluetooth device - * @return connection policy of the device - * @hide - */ - @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) - public @ConnectionPolicy int getConnectionPolicy(@NonNull BluetoothDevice device) { - if (VDBG) { - log("getConnectionPolicy(" + device + ")"); - } - final IBluetoothPbapClient service = getService(); - final int defaultValue = BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device)) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.getConnectionPolicy(device, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } -} diff --git a/core/java/android/bluetooth/BluetoothProfile.java b/core/java/android/bluetooth/BluetoothProfile.java deleted file mode 100644 index d0f74e985729094f2c5017b5092b62234a2fc36d..0000000000000000000000000000000000000000 --- a/core/java/android/bluetooth/BluetoothProfile.java +++ /dev/null @@ -1,459 +0,0 @@ -/* - * Copyright (C) 2010-2016 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.bluetooth; - -import android.annotation.IntDef; -import android.annotation.RequiresNoPermission; -import android.annotation.SuppressLint; -import android.annotation.SystemApi; -import android.compat.annotation.UnsupportedAppUsage; -import android.os.Build; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.util.List; - -/** - * Public APIs for the Bluetooth Profiles. - * - *

    Clients should call {@link BluetoothAdapter#getProfileProxy}, - * to get the Profile Proxy. Each public profile implements this - * interface. - */ -public interface BluetoothProfile { - - /** - * Extra for the connection state intents of the individual profiles. - * - * This extra represents the current connection state of the profile of the - * Bluetooth device. - */ - @SuppressLint("ActionValue") - String EXTRA_STATE = "android.bluetooth.profile.extra.STATE"; - - /** - * Extra for the connection state intents of the individual profiles. - * - * This extra represents the previous connection state of the profile of the - * Bluetooth device. - */ - @SuppressLint("ActionValue") - String EXTRA_PREVIOUS_STATE = - "android.bluetooth.profile.extra.PREVIOUS_STATE"; - - /** The profile is in disconnected state */ - int STATE_DISCONNECTED = 0; - /** The profile is in connecting state */ - int STATE_CONNECTING = 1; - /** The profile is in connected state */ - int STATE_CONNECTED = 2; - /** The profile is in disconnecting state */ - int STATE_DISCONNECTING = 3; - - /** @hide */ - @IntDef({ - STATE_DISCONNECTED, - STATE_CONNECTING, - STATE_CONNECTED, - STATE_DISCONNECTING, - }) - @Retention(RetentionPolicy.SOURCE) - public @interface BtProfileState {} - - /** - * Headset and Handsfree profile - */ - int HEADSET = 1; - - /** - * A2DP profile. - */ - int A2DP = 2; - - /** - * Health Profile - * - * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New - * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt}, - * {@link BluetoothAdapter#listenUsingL2capChannel()}, or - * {@link BluetoothDevice#createL2capChannel(int)} - */ - @Deprecated - int HEALTH = 3; - - /** - * HID Host - * - * @hide - */ - int HID_HOST = 4; - - /** - * PAN Profile - * - * @hide - */ - @SystemApi - int PAN = 5; - - /** - * PBAP - * - * @hide - */ - int PBAP = 6; - - /** - * GATT - */ - int GATT = 7; - - /** - * GATT_SERVER - */ - int GATT_SERVER = 8; - - /** - * MAP Profile - * - * @hide - */ - int MAP = 9; - - /* - * SAP Profile - * @hide - */ - int SAP = 10; - - /** - * A2DP Sink Profile - * - * @hide - */ - @SystemApi - int A2DP_SINK = 11; - - /** - * AVRCP Controller Profile - * - * @hide - */ - @SystemApi - int AVRCP_CONTROLLER = 12; - - /** - * AVRCP Target Profile - * - * @hide - */ - int AVRCP = 13; - - /** - * Headset Client - HFP HF Role - * - * @hide - */ - @SystemApi - int HEADSET_CLIENT = 16; - - /** - * PBAP Client - * - * @hide - */ - @SystemApi - int PBAP_CLIENT = 17; - - /** - * MAP Messaging Client Equipment (MCE) - * - * @hide - */ - @SystemApi - int MAP_CLIENT = 18; - - /** - * HID Device - */ - int HID_DEVICE = 19; - - /** - * Object Push Profile (OPP) - * - * @hide - */ - int OPP = 20; - - /** - * Hearing Aid Device - * - */ - int HEARING_AID = 21; - - /** - * LE Audio Device - * - */ - int LE_AUDIO = 22; - - /** - * Volume Control profile - * - * @hide - */ - @SystemApi - int VOLUME_CONTROL = 23; - - /** - * @hide - * Media Control Profile server - * - */ - int MCP_SERVER = 24; - - /** - * Coordinated Set Identification Profile set coordinator - * - */ - int CSIP_SET_COORDINATOR = 25; - - /** - * LE Audio Broadcast Source - * - * @hide - */ - int LE_AUDIO_BROADCAST = 26; - - /** - * @hide - * Telephone Bearer Service from Call Control Profile - * - */ - int LE_CALL_CONTROL = 27; - - /** - * Max profile ID. This value should be updated whenever a new profile is added to match - * the largest value assigned to a profile. - * - * @hide - */ - int MAX_PROFILE_ID = 27; - - /** - * Default priority for devices that we try to auto-connect to and - * and allow incoming connections for the profile - * - * @hide - **/ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - int PRIORITY_AUTO_CONNECT = 1000; - - /** - * Default priority for devices that allow incoming - * and outgoing connections for the profile - * - * @hide - * @deprecated Replaced with {@link #CONNECTION_POLICY_ALLOWED} - **/ - @Deprecated - @SystemApi - int PRIORITY_ON = 100; - - /** - * Default priority for devices that does not allow incoming - * connections and outgoing connections for the profile. - * - * @hide - * @deprecated Replaced with {@link #CONNECTION_POLICY_FORBIDDEN} - **/ - @Deprecated - @SystemApi - int PRIORITY_OFF = 0; - - /** - * Default priority when not set or when the device is unpaired - * - * @hide - */ - @UnsupportedAppUsage - int PRIORITY_UNDEFINED = -1; - - /** @hide */ - @IntDef(prefix = "CONNECTION_POLICY_", value = {CONNECTION_POLICY_ALLOWED, - CONNECTION_POLICY_FORBIDDEN, CONNECTION_POLICY_UNKNOWN}) - @Retention(RetentionPolicy.SOURCE) - public @interface ConnectionPolicy{} - - /** - * Default connection policy for devices that allow incoming and outgoing connections - * for the profile - * - * @hide - **/ - @SystemApi - int CONNECTION_POLICY_ALLOWED = 100; - - /** - * Default connection policy for devices that do not allow incoming or outgoing connections - * for the profile. - * - * @hide - **/ - @SystemApi - int CONNECTION_POLICY_FORBIDDEN = 0; - - /** - * Default connection policy when not set or when the device is unpaired - * - * @hide - */ - @SystemApi - int CONNECTION_POLICY_UNKNOWN = -1; - - /** - * Get connected devices for this specific profile. - * - *

    Return the set of devices which are in state {@link #STATE_CONNECTED} - * - * @return List of devices. The list will be empty on error. - */ - public List getConnectedDevices(); - - /** - * Get a list of devices that match any of the given connection - * states. - * - *

    If none of the devices match any of the given states, - * an empty list will be returned. - * - * @param states Array of states. States can be one of {@link #STATE_CONNECTED}, {@link - * #STATE_CONNECTING}, {@link #STATE_DISCONNECTED}, {@link #STATE_DISCONNECTING}, - * @return List of devices. The list will be empty on error. - */ - public List getDevicesMatchingConnectionStates(int[] states); - - /** - * Get the current connection state of the profile - * - * @param device Remote bluetooth device. - * @return State of the profile connection. One of {@link #STATE_CONNECTED}, {@link - * #STATE_CONNECTING}, {@link #STATE_DISCONNECTED}, {@link #STATE_DISCONNECTING} - */ - @BtProfileState int getConnectionState(BluetoothDevice device); - - /** - * An interface for notifying BluetoothProfile IPC clients when they have - * been connected or disconnected to the service. - */ - public interface ServiceListener { - /** - * Called to notify the client when the proxy object has been - * connected to the service. - * - * @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); - - /** - * Called to notify the client that this proxy object has been - * disconnected from the service. - * - * @param profile - One of {@link #HEADSET} or {@link #A2DP} - */ - @RequiresNoPermission - public void onServiceDisconnected(int profile); - } - - /** - * Convert an integer value of connection state into human readable string - * - * @param connectionState - One of {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING}, - * {@link #STATE_CONNECTED}, or {@link #STATE_DISCONNECTED} - * @return a string representation of the connection state, STATE_UNKNOWN if the state - * is not defined - * @hide - */ - static String getConnectionStateName(int connectionState) { - switch (connectionState) { - case STATE_DISCONNECTED: - return "STATE_DISCONNECTED"; - case STATE_CONNECTING: - return "STATE_CONNECTING"; - case STATE_CONNECTED: - return "STATE_CONNECTED"; - case STATE_DISCONNECTING: - return "STATE_DISCONNECTING"; - default: - return "STATE_UNKNOWN"; - } - } - - /** - * Convert an integer value of profile ID into human readable string - * - * @param profile profile ID - * @return profile name as String, UNKOWN_PROFILE if the profile ID is not defined. - * @hide - */ - static String getProfileName(int profile) { - switch(profile) { - case HEADSET: - return "HEADSET"; - case A2DP: - return "A2DP"; - case HID_HOST: - return "HID_HOST"; - case PAN: - return "PAN"; - case PBAP: - return "PBAP"; - case GATT: - return "GATT"; - case GATT_SERVER: - return "GATT_SERVER"; - case MAP: - return "MAP"; - case SAP: - return "SAP"; - case A2DP_SINK: - return "A2DP_SINK"; - case AVRCP_CONTROLLER: - return "AVRCP_CONTROLLER"; - case AVRCP: - return "AVRCP"; - case HEADSET_CLIENT: - return "HEADSET_CLIENT"; - case PBAP_CLIENT: - return "PBAP_CLIENT"; - case MAP_CLIENT: - return "MAP_CLIENT"; - case HID_DEVICE: - return "HID_DEVICE"; - case OPP: - return "OPP"; - case HEARING_AID: - return "HEARING_AID"; - case LE_AUDIO: - return "LE_AUDIO"; - default: - return "UNKNOWN_PROFILE"; - } - } -} diff --git a/core/java/android/bluetooth/BluetoothProfileConnector.java b/core/java/android/bluetooth/BluetoothProfileConnector.java deleted file mode 100644 index 79373f1a32ecb7cc992c5e27258ee1a910dfe37c..0000000000000000000000000000000000000000 --- a/core/java/android/bluetooth/BluetoothProfileConnector.java +++ /dev/null @@ -1,220 +0,0 @@ -/* - * Copyright 2019 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.bluetooth; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.annotation.SuppressLint; -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.content.ServiceConnection; -import android.content.pm.ApplicationInfo; -import android.content.pm.PackageManager; -import android.content.pm.ResolveInfo; -import android.os.Build; -import android.os.IBinder; -import android.os.RemoteException; -import android.os.UserHandle; -import android.util.CloseGuard; -import android.util.Log; - -import java.util.List; -/** - * Connector for Bluetooth profile proxies to bind manager service and - * profile services - * @param The Bluetooth profile interface for this connection. - * @hide - */ -@SuppressLint("AndroidFrameworkBluetoothPermission") -public abstract class BluetoothProfileConnector { - private final CloseGuard mCloseGuard = new CloseGuard(); - private final int mProfileId; - private BluetoothProfile.ServiceListener mServiceListener; - private final BluetoothProfile mProfileProxy; - private Context mContext; - private final String mProfileName; - private final String mServiceName; - private volatile T mService; - - private final IBluetoothStateChangeCallback mBluetoothStateChangeCallback = - new IBluetoothStateChangeCallback.Stub() { - public void onBluetoothStateChange(boolean up) { - if (up) { - doBind(); - } else { - doUnbind(); - } - } - }; - - private @Nullable ComponentName resolveSystemService(@NonNull Intent intent, - @NonNull PackageManager pm, @PackageManager.ComponentInfoFlags int flags) { - List results = pm.queryIntentServices(intent, flags); - if (results == null) { - return null; - } - ComponentName comp = null; - for (int i = 0; i < results.size(); i++) { - ResolveInfo ri = results.get(i); - if ((ri.serviceInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) { - continue; - } - ComponentName foundComp = new ComponentName(ri.serviceInfo.applicationInfo.packageName, - ri.serviceInfo.name); - if (comp != null) { - throw new IllegalStateException("Multiple system services handle " + intent - + ": " + comp + ", " + foundComp); - } - comp = foundComp; - } - return comp; - } - - private final ServiceConnection mConnection = new ServiceConnection() { - public void onServiceConnected(ComponentName className, IBinder service) { - logDebug("Proxy object connected"); - mService = getServiceInterface(service); - - if (mServiceListener != null) { - mServiceListener.onServiceConnected(mProfileId, mProfileProxy); - } - } - - public void onServiceDisconnected(ComponentName className) { - logDebug("Proxy object disconnected"); - doUnbind(); - if (mServiceListener != null) { - mServiceListener.onServiceDisconnected(mProfileId); - } - } - }; - - BluetoothProfileConnector(BluetoothProfile profile, int profileId, String profileName, - String serviceName) { - mProfileId = profileId; - mProfileProxy = profile; - mProfileName = profileName; - mServiceName = serviceName; - } - - /** {@hide} */ - @Override - public void finalize() { - mCloseGuard.warnIfOpen(); - doUnbind(); - } - - @SuppressLint("AndroidFrameworkRequiresPermission") - private boolean doBind() { - synchronized (mConnection) { - if (mService == null) { - logDebug("Binding service..."); - mCloseGuard.open("doUnbind"); - try { - Intent intent = new Intent(mServiceName); - ComponentName comp = resolveSystemService(intent, mContext.getPackageManager(), - 0); - intent.setComponent(comp); - if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0, - UserHandle.CURRENT)) { - logError("Could not bind to Bluetooth Service with " + intent); - return false; - } - } catch (SecurityException se) { - logError("Failed to bind service. " + se); - return false; - } - } - } - return true; - } - - private void doUnbind() { - synchronized (mConnection) { - if (mService != null) { - logDebug("Unbinding service..."); - mCloseGuard.close(); - try { - mContext.unbindService(mConnection); - } catch (IllegalArgumentException ie) { - logError("Unable to unbind service: " + ie); - } finally { - mService = null; - } - } - } - } - - void connect(Context context, BluetoothProfile.ServiceListener listener) { - mContext = context; - mServiceListener = listener; - IBluetoothManager mgr = BluetoothAdapter.getDefaultAdapter().getBluetoothManager(); - - // Preserve legacy compatibility where apps were depending on - // registerStateChangeCallback() performing a permissions check which - // has been relaxed in modern platform versions - if (context.getApplicationInfo().targetSdkVersion <= Build.VERSION_CODES.R - && context.checkSelfPermission(android.Manifest.permission.BLUETOOTH) - != PackageManager.PERMISSION_GRANTED) { - throw new SecurityException("Need BLUETOOTH permission"); - } - - if (mgr != null) { - try { - mgr.registerStateChangeCallback(mBluetoothStateChangeCallback); - } catch (RemoteException re) { - logError("Failed to register state change callback. " + re); - } - } - doBind(); - } - - void disconnect() { - mServiceListener = null; - IBluetoothManager mgr = BluetoothAdapter.getDefaultAdapter().getBluetoothManager(); - if (mgr != null) { - try { - mgr.unregisterStateChangeCallback(mBluetoothStateChangeCallback); - } catch (RemoteException re) { - logError("Failed to unregister state change callback" + re); - } - } - doUnbind(); - } - - T getService() { - return mService; - } - - /** - * This abstract function is used to implement method to get the - * connected Bluetooth service interface. - * @param service the connected binder service. - * @return T the binder interface of {@code service}. - * @hide - */ - public abstract T getServiceInterface(IBinder service); - - private void logDebug(String log) { - Log.d(mProfileName, log); - } - - private void logError(String log) { - Log.e(mProfileName, log); - } -} diff --git a/core/java/android/bluetooth/BluetoothSap.java b/core/java/android/bluetooth/BluetoothSap.java deleted file mode 100644 index 808fa3913316527efa62c076c442b930ff971cb3..0000000000000000000000000000000000000000 --- a/core/java/android/bluetooth/BluetoothSap.java +++ /dev/null @@ -1,491 +0,0 @@ -/* - * 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.bluetooth; - -import static android.bluetooth.BluetoothUtils.getSyncTimeout; - -import android.Manifest; -import android.annotation.RequiresNoPermission; -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; -import android.content.AttributionSource; -import android.content.Context; -import android.os.Build; -import android.os.IBinder; -import android.os.RemoteException; -import android.util.Log; - -import com.android.modules.utils.SynchronousResultReceiver; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.TimeoutException; - -/** - * This class provides the APIs to control the Bluetooth SIM - * Access Profile (SAP). - * - *

    BluetoothSap is a proxy object for controlling the Bluetooth - * Service via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get - * the BluetoothSap proxy object. - * - *

    Each method is protected with its appropriate permission. - * - * @hide - */ -public final class BluetoothSap implements BluetoothProfile { - - private static final String TAG = "BluetoothSap"; - private static final boolean DBG = true; - private static final boolean VDBG = false; - - /** - * Intent used to broadcast the change in connection state of the profile. - * - *

    This intent will have 4 extras: - *

      - *
    • {@link #EXTRA_STATE} - The current state of the profile.
    • - *
    • {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile.
    • - *
    • {@link BluetoothDevice#EXTRA_DEVICE} - The remote device.
    • - *
    - * - *

    {@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of - * {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING}, - * {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}. - * - * @hide - */ - @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"; - - /** - * There was an error trying to obtain the state. - * - * @hide - */ - public static final int STATE_ERROR = -1; - - /** - * Connection state change succceeded. - * - * @hide - */ - public static final int RESULT_SUCCESS = 1; - - /** - * Connection canceled before completion. - * - * @hide - */ - public static final int RESULT_CANCELED = 2; - - private final BluetoothAdapter mAdapter; - private final AttributionSource mAttributionSource; - private final BluetoothProfileConnector mProfileConnector = - new BluetoothProfileConnector(this, BluetoothProfile.SAP, - "BluetoothSap", IBluetoothSap.class.getName()) { - @Override - public IBluetoothSap getServiceInterface(IBinder service) { - return IBluetoothSap.Stub.asInterface(service); - } - }; - - /** - * Create a BluetoothSap proxy object. - */ - /* package */ BluetoothSap(Context context, ServiceListener listener, - BluetoothAdapter adapter) { - if (DBG) Log.d(TAG, "Create BluetoothSap proxy object"); - mAdapter = adapter; - mAttributionSource = adapter.getAttributionSource(); - mProfileConnector.connect(context, listener); - } - - protected void finalize() throws Throwable { - try { - close(); - } finally { - super.finalize(); - } - } - - /** - * Close the connection to the backing service. - * Other public functions of BluetoothSap will return default error - * results once close() has been called. Multiple invocations of close() - * are ok. - * - * @hide - */ - public synchronized void close() { - mProfileConnector.disconnect(); - } - - private IBluetoothSap getService() { - return mProfileConnector.getService(); - } - - /** - * Get the current state of the BluetoothSap service. - * - * @return One of the STATE_ return codes, or STATE_ERROR if this proxy object is currently not - * connected to the Sap service. - * @hide - */ - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public int getState() { - if (VDBG) log("getState()"); - final IBluetoothSap service = getService(); - final int defaultValue = BluetoothSap.STATE_ERROR; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled()) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.getState(mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Get the currently connected remote Bluetooth device (PCE). - * - * @return The remote Bluetooth device, or null if not in connected or connecting state, or if - * 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()"); - final IBluetoothSap service = getService(); - final BluetoothDevice defaultValue = null; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled()) { - try { - final SynchronousResultReceiver recv = - new SynchronousResultReceiver(); - service.getClient(mAttributionSource, recv); - return Attributable.setAttributionSource( - recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue), - mAttributionSource); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Returns true if the specified Bluetooth device is connected. - * Returns false if not connected, or if this proxy object is not - * currently connected to the Sap service. - * - * @hide - */ - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public boolean isConnected(BluetoothDevice device) { - if (VDBG) log("isConnected(" + device + ")"); - final IBluetoothSap service = getService(); - final boolean defaultValue = false; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled()) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.isConnected(device, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Initiate connection. Initiation of outgoing connections is not - * supported for SAP server. - * - * @hide - */ - @RequiresNoPermission - public boolean connect(BluetoothDevice device) { - if (DBG) log("connect(" + device + ")" + "not supported for SAPS"); - return false; - } - - /** - * Initiate disconnect. - * - * @param device Remote Bluetooth Device - * @return false on error, true otherwise - * @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 + ")"); - final IBluetoothSap service = getService(); - final boolean defaultValue = false; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device)) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.disconnect(device, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Get the list of connected devices. Currently at most one. - * - * @return list of connected devices - * @hide - */ - @RequiresBluetoothConnectPermission - @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT) - public List getConnectedDevices() { - if (DBG) log("getConnectedDevices()"); - final IBluetoothSap service = getService(); - final List defaultValue = new ArrayList(); - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled()) { - try { - final SynchronousResultReceiver> recv = - new SynchronousResultReceiver(); - service.getConnectedDevices(mAttributionSource, recv); - return Attributable.setAttributionSource( - recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue), - mAttributionSource); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Get the list of devices matching specified states. Currently at most one. - * - * @return list of matching devices - * @hide - */ - @RequiresBluetoothConnectPermission - @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT) - public List getDevicesMatchingConnectionStates(int[] states) { - if (DBG) log("getDevicesMatchingStates()"); - final IBluetoothSap service = getService(); - final List defaultValue = new ArrayList(); - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled()) { - try { - final SynchronousResultReceiver> recv = - new SynchronousResultReceiver(); - service.getDevicesMatchingConnectionStates(states, mAttributionSource, recv); - return Attributable.setAttributionSource( - recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue), - mAttributionSource); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Get connection state of device - * - * @return device connection state - * @hide - */ - @RequiresBluetoothConnectPermission - @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT) - public int getConnectionState(BluetoothDevice device) { - if (DBG) log("getConnectionState(" + device + ")"); - final IBluetoothSap service = getService(); - final int defaultValue = BluetoothProfile.STATE_DISCONNECTED; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device)) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.getConnectionState(device, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Set priority of the profile - * - *

    The device should already be paired. - * Priority can be one of {@link #PRIORITY_ON} or {@link #PRIORITY_OFF}, - * - * @param device Paired bluetooth device - * @param priority - * @return true if priority is set, false on error - * @hide - */ - @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) - public boolean setPriority(BluetoothDevice device, int priority) { - if (DBG) log("setPriority(" + device + ", " + priority + ")"); - return setConnectionPolicy(device, BluetoothAdapter.priorityToConnectionPolicy(priority)); - } - - /** - * Set connection policy of the profile - * - *

    The device should already be paired. - * Connection policy can be one of {@link #CONNECTION_POLICY_ALLOWED}, - * {@link #CONNECTION_POLICY_FORBIDDEN}, {@link #CONNECTION_POLICY_UNKNOWN} - * - * @param device Paired bluetooth device - * @param connectionPolicy is the connection policy to set to for this profile - * @return true if connectionPolicy is set, false on error - * @hide - */ - @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) - public boolean setConnectionPolicy(BluetoothDevice device, - @ConnectionPolicy int connectionPolicy) { - if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")"); - final IBluetoothSap service = getService(); - final boolean defaultValue = false; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device) - && (connectionPolicy == BluetoothProfile.CONNECTION_POLICY_FORBIDDEN - || connectionPolicy == BluetoothProfile.CONNECTION_POLICY_ALLOWED)) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.setConnectionPolicy(device, connectionPolicy, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Get the priority of the profile. - * - *

    The priority can be any of: - * {@link #PRIORITY_OFF}, {@link #PRIORITY_ON}, {@link #PRIORITY_UNDEFINED} - * - * @param device Bluetooth device - * @return priority of the device - * @hide - */ - @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) - public int getPriority(BluetoothDevice device) { - if (VDBG) log("getPriority(" + device + ")"); - return BluetoothAdapter.connectionPolicyToPriority(getConnectionPolicy(device)); - } - - /** - * Get the connection policy of the profile. - * - *

    The connection policy can be any of: - * {@link #CONNECTION_POLICY_ALLOWED}, {@link #CONNECTION_POLICY_FORBIDDEN}, - * {@link #CONNECTION_POLICY_UNKNOWN} - * - * @param device Bluetooth device - * @return connection policy of the device - * @hide - */ - @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) - public @ConnectionPolicy int getConnectionPolicy(BluetoothDevice device) { - if (VDBG) log("getConnectionPolicy(" + device + ")"); - final IBluetoothSap service = getService(); - final int defaultValue = BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device)) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.getConnectionPolicy(device, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - private static void log(String msg) { - Log.d(TAG, msg); - } - - private boolean isEnabled() { - return mAdapter.isEnabled(); - } - - private static boolean isValidDevice(BluetoothDevice device) { - return device != null && BluetoothAdapter.checkBluetoothAddress(device.getAddress()); - } -} diff --git a/core/java/android/bluetooth/BluetoothServerSocket.java b/core/java/android/bluetooth/BluetoothServerSocket.java deleted file mode 100644 index bb4e35483fea8069c3a052c3e8687c6adbf3482a..0000000000000000000000000000000000000000 --- a/core/java/android/bluetooth/BluetoothServerSocket.java +++ /dev/null @@ -1,266 +0,0 @@ -/* - * Copyright (C) 2009 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.bluetooth; - -import android.annotation.SuppressLint; -import android.compat.annotation.UnsupportedAppUsage; -import android.os.Handler; -import android.os.ParcelUuid; -import android.util.Log; - -import java.io.Closeable; -import java.io.IOException; - -/** - * A listening Bluetooth socket. - * - *

    The interface for Bluetooth Sockets is similar to that of TCP sockets: - * {@link java.net.Socket} and {@link java.net.ServerSocket}. On the server - * side, use a {@link BluetoothServerSocket} to create a listening server - * socket. When a connection is accepted by the {@link BluetoothServerSocket}, - * it will return a new {@link BluetoothSocket} to manage the connection. - * On the client side, use a single {@link BluetoothSocket} to both initiate - * an outgoing connection and to manage the connection. - * - *

    For Bluetooth BR/EDR, the most common type of socket is RFCOMM, which is the type supported by - * the Android APIs. RFCOMM is a connection-oriented, streaming transport over Bluetooth BR/EDR. It - * is also known as the Serial Port Profile (SPP). To create a listening - * {@link BluetoothServerSocket} that's ready for incoming Bluetooth BR/EDR connections, use {@link - * BluetoothAdapter#listenUsingRfcommWithServiceRecord - * BluetoothAdapter.listenUsingRfcommWithServiceRecord()}. - * - *

    For Bluetooth LE, the socket uses LE Connection-oriented Channel (CoC). LE CoC is a - * connection-oriented, streaming transport over Bluetooth LE and has a credit-based flow control. - * Correspondingly, use {@link BluetoothAdapter#listenUsingL2capChannel - * BluetoothAdapter.listenUsingL2capChannel()} to create a listening {@link BluetoothServerSocket} - * that's ready for incoming Bluetooth LE CoC connections. For LE CoC, you can use {@link #getPsm()} - * to get the protocol/service multiplexer (PSM) value that the peer needs to use to connect to your - * socket. - * - *

    After the listening {@link BluetoothServerSocket} is created, call {@link #accept()} to - * listen for incoming connection requests. This call will block until a connection is established, - * at which point, it will return a {@link BluetoothSocket} to manage the connection. Once the - * {@link BluetoothSocket} is acquired, it's a good idea to call {@link #close()} on the {@link - * BluetoothServerSocket} when it's no longer needed for accepting - * connections. Closing the {@link BluetoothServerSocket} will not close the returned - * {@link BluetoothSocket}. - * - *

    {@link BluetoothServerSocket} is thread - * safe. In particular, {@link #close} will always immediately abort ongoing - * operations and close the server socket. - * - *

    - *

    Developer Guides

    - *

    For more information about using Bluetooth, read the - * Bluetooth developer guide.

    - *
    - * - * {@see BluetoothSocket} - */ -@SuppressLint("AndroidFrameworkBluetoothPermission") -public final class BluetoothServerSocket implements Closeable { - - private static final String TAG = "BluetoothServerSocket"; - private static final boolean DBG = false; - @UnsupportedAppUsage(publicAlternatives = "Use public {@link BluetoothServerSocket} API " - + "instead.") - /*package*/ final BluetoothSocket mSocket; - private Handler mHandler; - private int mMessage; - private int mChannel; - - /** - * Construct a socket for incoming connections. - * - * @param type type of socket - * @param auth require the remote device to be authenticated - * @param encrypt require the connection to be encrypted - * @param port remote port - * @throws IOException On error, for example Bluetooth not available, or insufficient - * privileges - */ - /*package*/ BluetoothServerSocket(int type, boolean auth, boolean encrypt, int port) - throws IOException { - mChannel = port; - mSocket = new BluetoothSocket(type, -1, auth, encrypt, null, port, null); - if (port == BluetoothAdapter.SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) { - mSocket.setExcludeSdp(true); - } - } - - /** - * Construct a socket for incoming connections. - * - * @param type type of socket - * @param auth require the remote device to be authenticated - * @param encrypt require the connection to be encrypted - * @param port remote port - * @param mitm enforce person-in-the-middle protection for authentication. - * @param min16DigitPin enforce a minimum length of 16 digits for a sec mode 2 connection - * @throws IOException On error, for example Bluetooth not available, or insufficient - * privileges - */ - /*package*/ BluetoothServerSocket(int type, boolean auth, boolean encrypt, int port, - boolean mitm, boolean min16DigitPin) - throws IOException { - mChannel = port; - mSocket = new BluetoothSocket(type, -1, auth, encrypt, null, port, null, mitm, - min16DigitPin); - if (port == BluetoothAdapter.SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) { - mSocket.setExcludeSdp(true); - } - } - - /** - * Construct a socket for incoming connections. - * - * @param type type of socket - * @param auth require the remote device to be authenticated - * @param encrypt require the connection to be encrypted - * @param uuid uuid - * @throws IOException On error, for example Bluetooth not available, or insufficient - * privileges - */ - /*package*/ BluetoothServerSocket(int type, boolean auth, boolean encrypt, ParcelUuid uuid) - throws IOException { - mSocket = new BluetoothSocket(type, -1, auth, encrypt, null, -1, uuid); - // TODO: This is the same as mChannel = -1 - is this intentional? - mChannel = mSocket.getPort(); - } - - - /** - * Block until a connection is established. - *

    Returns a connected {@link BluetoothSocket} on successful connection. - *

    Once this call returns, it can be called again to accept subsequent - * incoming connections. - *

    {@link #close} can be used to abort this call from another thread. - * - * @return a connected {@link BluetoothSocket} - * @throws IOException on error, for example this call was aborted, or timeout - */ - public BluetoothSocket accept() throws IOException { - return accept(-1); - } - - /** - * Block until a connection is established, with timeout. - *

    Returns a connected {@link BluetoothSocket} on successful connection. - *

    Once this call returns, it can be called again to accept subsequent - * incoming connections. - *

    {@link #close} can be used to abort this call from another thread. - * - * @return a connected {@link BluetoothSocket} - * @throws IOException on error, for example this call was aborted, or timeout - */ - public BluetoothSocket accept(int timeout) throws IOException { - return mSocket.accept(timeout); - } - - /** - * Immediately close this socket, and release all associated resources. - *

    Causes blocked calls on this socket in other threads to immediately - * throw an IOException. - *

    Closing the {@link BluetoothServerSocket} will not - * close any {@link BluetoothSocket} received from {@link #accept()}. - */ - public void close() throws IOException { - if (DBG) Log.d(TAG, "BluetoothServerSocket:close() called. mChannel=" + mChannel); - synchronized (this) { - if (mHandler != null) { - mHandler.obtainMessage(mMessage).sendToTarget(); - } - } - mSocket.close(); - } - - /*package*/ - synchronized void setCloseHandler(Handler handler, int message) { - mHandler = handler; - mMessage = message; - } - - /*package*/ void setServiceName(String serviceName) { - mSocket.setServiceName(serviceName); - } - - /** - * Returns the channel on which this socket is bound. - * - * @hide - */ - public int getChannel() { - return mChannel; - } - - /** - * Returns the assigned dynamic protocol/service multiplexer (PSM) value for the listening L2CAP - * Connection-oriented Channel (CoC) server socket. This server socket must be returned by the - * {@link BluetoothAdapter#listenUsingL2capChannel()} or {@link - * BluetoothAdapter#listenUsingInsecureL2capChannel()}. The returned value is undefined if this - * method is called on non-L2CAP server sockets. - * - * @return the assigned PSM or LE_PSM value depending on transport - */ - public int getPsm() { - return mChannel; - } - - /** - * Sets the channel on which future sockets are bound. - * Currently used only when a channel is auto generated. - */ - /*package*/ void setChannel(int newChannel) { - /* TODO: From a design/architecture perspective this is wrong. - * The bind operation should be conducted through this class - * and the resulting port should be kept in mChannel, and - * not set from BluetoothAdapter. */ - if (mSocket != null) { - if (mSocket.getPort() != newChannel) { - Log.w(TAG, "The port set is different that the underlying port. mSocket.getPort(): " - + mSocket.getPort() + " requested newChannel: " + newChannel); - } - } - mChannel = newChannel; - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("ServerSocket: Type: "); - switch (mSocket.getConnectionType()) { - case BluetoothSocket.TYPE_RFCOMM: { - sb.append("TYPE_RFCOMM"); - break; - } - case BluetoothSocket.TYPE_L2CAP: { - sb.append("TYPE_L2CAP"); - break; - } - case BluetoothSocket.TYPE_L2CAP_LE: { - sb.append("TYPE_L2CAP_LE"); - break; - } - case BluetoothSocket.TYPE_SCO: { - sb.append("TYPE_SCO"); - break; - } - } - sb.append(" Channel: ").append(mChannel); - return sb.toString(); - } -} diff --git a/core/java/android/bluetooth/BluetoothSocket.java b/core/java/android/bluetooth/BluetoothSocket.java deleted file mode 100644 index db5b75148e88c383aab870abe1d395c91deed7c5..0000000000000000000000000000000000000000 --- a/core/java/android/bluetooth/BluetoothSocket.java +++ /dev/null @@ -1,809 +0,0 @@ -/* - * Copyright (C) 2012 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.bluetooth; - -import android.annotation.RequiresNoPermission; -import android.annotation.RequiresPermission; -import android.bluetooth.annotations.RequiresBluetoothConnectPermission; -import android.compat.annotation.UnsupportedAppUsage; -import android.net.LocalSocket; -import android.os.Build; -import android.os.ParcelFileDescriptor; -import android.os.ParcelUuid; -import android.os.RemoteException; -import android.util.Log; - -import java.io.Closeable; -import java.io.FileDescriptor; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.util.Arrays; -import java.util.Locale; -import java.util.UUID; - -/** - * A connected or connecting Bluetooth socket. - * - *

    The interface for Bluetooth Sockets is similar to that of TCP sockets: - * {@link java.net.Socket} and {@link java.net.ServerSocket}. On the server - * side, use a {@link BluetoothServerSocket} to create a listening server - * socket. When a connection is accepted by the {@link BluetoothServerSocket}, - * it will return a new {@link BluetoothSocket} to manage the connection. - * On the client side, use a single {@link BluetoothSocket} to both initiate - * an outgoing connection and to manage the connection. - * - *

    The most common type of Bluetooth socket is RFCOMM, which is the type - * supported by the Android APIs. RFCOMM is a connection-oriented, streaming - * transport over Bluetooth. It is also known as the Serial Port Profile (SPP). - * - *

    To create a {@link BluetoothSocket} for connecting to a known device, use - * {@link BluetoothDevice#createRfcommSocketToServiceRecord - * BluetoothDevice.createRfcommSocketToServiceRecord()}. - * Then call {@link #connect()} to attempt a connection to the remote device. - * This call will block until a connection is established or the connection - * fails. - * - *

    To create a {@link BluetoothSocket} as a server (or "host"), see the - * {@link BluetoothServerSocket} documentation. - * - *

    Once the socket is connected, whether initiated as a client or accepted - * as a server, open the IO streams by calling {@link #getInputStream} and - * {@link #getOutputStream} in order to retrieve {@link java.io.InputStream} - * and {@link java.io.OutputStream} objects, respectively, which are - * automatically connected to the socket. - * - *

    {@link BluetoothSocket} is thread - * safe. In particular, {@link #close} will always immediately abort ongoing - * operations and close the socket. - * - *

    - *

    Developer Guides

    - *

    For more information about using Bluetooth, read the - * Bluetooth developer guide.

    - *
    - * - * {@see BluetoothServerSocket} - * {@see java.io.InputStream} - * {@see java.io.OutputStream} - */ -public final class BluetoothSocket implements Closeable { - private static final String TAG = "BluetoothSocket"; - private static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG); - private static final boolean VDBG = Log.isLoggable(TAG, Log.VERBOSE); - - /** @hide */ - public static final int MAX_RFCOMM_CHANNEL = 30; - /*package*/ static final int MAX_L2CAP_PACKAGE_SIZE = 0xFFFF; - - /** RFCOMM socket */ - public static final int TYPE_RFCOMM = 1; - - /** SCO socket */ - public static final int TYPE_SCO = 2; - - /** L2CAP socket */ - public static final int TYPE_L2CAP = 3; - - /** L2CAP socket on BR/EDR transport - * @hide - */ - public static final int TYPE_L2CAP_BREDR = TYPE_L2CAP; - - /** L2CAP socket on LE transport - * @hide - */ - public static final int TYPE_L2CAP_LE = 4; - - /*package*/ static final int EBADFD = 77; - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - /*package*/ static final int EADDRINUSE = 98; - - /*package*/ static final int SEC_FLAG_ENCRYPT = 1; - /*package*/ static final int SEC_FLAG_AUTH = 1 << 1; - /*package*/ static final int BTSOCK_FLAG_NO_SDP = 1 << 2; - /*package*/ static final int SEC_FLAG_AUTH_MITM = 1 << 3; - /*package*/ static final int SEC_FLAG_AUTH_16_DIGIT = 1 << 4; - - private final int mType; /* one of TYPE_RFCOMM etc */ - private BluetoothDevice mDevice; /* remote device */ - private String mAddress; /* remote address */ - private final boolean mAuth; - private final boolean mEncrypt; - private final BluetoothInputStream mInputStream; - private final BluetoothOutputStream mOutputStream; - private final ParcelUuid mUuid; - /** when true no SPP SDP record will be created */ - private boolean mExcludeSdp = false; - /** when true Person-in-the-middle protection will be enabled */ - private boolean mAuthMitm = false; - /** Minimum 16 digit pin for sec mode 2 connections */ - private boolean mMin16DigitPin = false; - @UnsupportedAppUsage(publicAlternatives = "Use {@link BluetoothSocket} public API instead.") - private ParcelFileDescriptor mPfd; - @UnsupportedAppUsage - private LocalSocket mSocket; - private InputStream mSocketIS; - private OutputStream mSocketOS; - @UnsupportedAppUsage - private int mPort; /* RFCOMM channel or L2CAP psm */ - private int mFd; - private String mServiceName; - private static final int PROXY_CONNECTION_TIMEOUT = 5000; - - private static final int SOCK_SIGNAL_SIZE = 20; - - private ByteBuffer mL2capBuffer = null; - private int mMaxTxPacketSize = 0; // The l2cap maximum packet size supported by the peer. - private int mMaxRxPacketSize = 0; // The l2cap maximum packet size that can be received. - - private enum SocketState { - INIT, - CONNECTED, - LISTENING, - CLOSED, - } - - /** prevents all native calls after destroyNative() */ - private volatile SocketState mSocketState; - - /** protects mSocketState */ - //private final ReentrantReadWriteLock mLock; - - /** - * Construct a BluetoothSocket. - * - * @param type type of socket - * @param fd fd to use for connected socket, or -1 for a new socket - * @param auth require the remote device to be authenticated - * @param encrypt require the connection to be encrypted - * @param device remote device that this socket can connect to - * @param port remote port - * @param uuid SDP uuid - * @throws IOException On error, for example Bluetooth not available, or insufficient - * privileges - */ - /*package*/ BluetoothSocket(int type, int fd, boolean auth, boolean encrypt, - BluetoothDevice device, int port, ParcelUuid uuid) throws IOException { - this(type, fd, auth, encrypt, device, port, uuid, false, false); - } - - /** - * Construct a BluetoothSocket. - * - * @param type type of socket - * @param fd fd to use for connected socket, or -1 for a new socket - * @param auth require the remote device to be authenticated - * @param encrypt require the connection to be encrypted - * @param device remote device that this socket can connect to - * @param port remote port - * @param uuid SDP uuid - * @param mitm enforce person-in-the-middle protection. - * @param min16DigitPin enforce a minimum length of 16 digits for a sec mode 2 connection - * @throws IOException On error, for example Bluetooth not available, or insufficient - * privileges - */ - /*package*/ BluetoothSocket(int type, int fd, boolean auth, boolean encrypt, - BluetoothDevice device, int port, ParcelUuid uuid, boolean mitm, boolean min16DigitPin) - throws IOException { - if (VDBG) Log.d(TAG, "Creating new BluetoothSocket of type: " + type); - if (type == BluetoothSocket.TYPE_RFCOMM && uuid == null && fd == -1 - && port != BluetoothAdapter.SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) { - if (port < 1 || port > MAX_RFCOMM_CHANNEL) { - throw new IOException("Invalid RFCOMM channel: " + port); - } - } - if (uuid != null) { - mUuid = uuid; - } else { - mUuid = new ParcelUuid(new UUID(0, 0)); - } - mType = type; - mAuth = auth; - mAuthMitm = mitm; - mMin16DigitPin = min16DigitPin; - mEncrypt = encrypt; - mDevice = device; - mPort = port; - mFd = fd; - - mSocketState = SocketState.INIT; - - if (device == null) { - // Server socket - mAddress = BluetoothAdapter.getDefaultAdapter().getAddress(); - } else { - // Remote socket - mAddress = device.getAddress(); - } - mInputStream = new BluetoothInputStream(this); - mOutputStream = new BluetoothOutputStream(this); - } - - private BluetoothSocket(BluetoothSocket s) { - if (VDBG) Log.d(TAG, "Creating new Private BluetoothSocket of type: " + s.mType); - mUuid = s.mUuid; - mType = s.mType; - mAuth = s.mAuth; - mEncrypt = s.mEncrypt; - mPort = s.mPort; - mInputStream = new BluetoothInputStream(this); - mOutputStream = new BluetoothOutputStream(this); - mMaxRxPacketSize = s.mMaxRxPacketSize; - mMaxTxPacketSize = s.mMaxTxPacketSize; - - mServiceName = s.mServiceName; - mExcludeSdp = s.mExcludeSdp; - mAuthMitm = s.mAuthMitm; - mMin16DigitPin = s.mMin16DigitPin; - } - - private BluetoothSocket acceptSocket(String remoteAddr) throws IOException { - BluetoothSocket as = new BluetoothSocket(this); - as.mSocketState = SocketState.CONNECTED; - FileDescriptor[] fds = mSocket.getAncillaryFileDescriptors(); - if (DBG) Log.d(TAG, "socket fd passed by stack fds: " + Arrays.toString(fds)); - if (fds == null || fds.length != 1) { - Log.e(TAG, "socket fd passed from stack failed, fds: " + Arrays.toString(fds)); - as.close(); - throw new IOException("bt socket acept failed"); - } - - as.mPfd = ParcelFileDescriptor.dup(fds[0]); - as.mSocket = LocalSocket.createConnectedLocalSocket(fds[0]); - as.mSocketIS = as.mSocket.getInputStream(); - as.mSocketOS = as.mSocket.getOutputStream(); - as.mAddress = remoteAddr; - as.mDevice = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(remoteAddr); - return as; - } - - /** - * Construct a BluetoothSocket from address. Used by native code. - * - * @param type type of socket - * @param fd fd to use for connected socket, or -1 for a new socket - * @param auth require the remote device to be authenticated - * @param encrypt require the connection to be encrypted - * @param address remote device that this socket can connect to - * @param port remote port - * @throws IOException On error, for example Bluetooth not available, or insufficient - * privileges - */ - private BluetoothSocket(int type, int fd, boolean auth, boolean encrypt, String address, - int port) throws IOException { - this(type, fd, auth, encrypt, new BluetoothDevice(address), port, null, false, false); - } - - /** @hide */ - @Override - protected void finalize() throws Throwable { - try { - close(); - } finally { - super.finalize(); - } - } - - private int getSecurityFlags() { - int flags = 0; - if (mAuth) { - flags |= SEC_FLAG_AUTH; - } - if (mEncrypt) { - flags |= SEC_FLAG_ENCRYPT; - } - if (mExcludeSdp) { - flags |= BTSOCK_FLAG_NO_SDP; - } - if (mAuthMitm) { - flags |= SEC_FLAG_AUTH_MITM; - } - if (mMin16DigitPin) { - flags |= SEC_FLAG_AUTH_16_DIGIT; - } - return flags; - } - - /** - * Get the remote device this socket is connecting, or connected, to. - * - * @return remote device - */ - @RequiresNoPermission - public BluetoothDevice getRemoteDevice() { - return mDevice; - } - - /** - * Get the input stream associated with this socket. - *

    The input stream will be returned even if the socket is not yet - * connected, but operations on that stream will throw IOException until - * the associated socket is connected. - * - * @return InputStream - */ - @RequiresNoPermission - public InputStream getInputStream() throws IOException { - return mInputStream; - } - - /** - * Get the output stream associated with this socket. - *

    The output stream will be returned even if the socket is not yet - * connected, but operations on that stream will throw IOException until - * the associated socket is connected. - * - * @return OutputStream - */ - @RequiresNoPermission - public OutputStream getOutputStream() throws IOException { - return mOutputStream; - } - - /** - * Get the connection status of this socket, ie, whether there is an active connection with - * remote device. - * - * @return true if connected false if not connected - */ - @RequiresNoPermission - public boolean isConnected() { - return mSocketState == SocketState.CONNECTED; - } - - /*package*/ void setServiceName(String name) { - mServiceName = name; - } - - /** - * Attempt to connect to a remote device. - *

    This method will block until a connection is made or the connection - * fails. If this method returns without an exception then this socket - * is now connected. - *

    Creating new connections to - * remote Bluetooth devices should not be attempted while device discovery - * is in progress. Device discovery is a heavyweight procedure on the - * Bluetooth adapter and will significantly slow a device connection. - * Use {@link BluetoothAdapter#cancelDiscovery()} to cancel an ongoing - * discovery. Discovery is not managed by the Activity, - * but is run as a system service, so an application should always call - * {@link BluetoothAdapter#cancelDiscovery()} even if it - * did not directly request a discovery, just to be sure. - *

    {@link #close} can be used to abort this call from another thread. - * - * @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"); - - try { - if (mSocketState == SocketState.CLOSED) throw new IOException("socket closed"); - IBluetooth bluetoothProxy = - BluetoothAdapter.getDefaultAdapter().getBluetoothService(); - if (bluetoothProxy == null) throw new IOException("Bluetooth is off"); - mPfd = bluetoothProxy.getSocketManager().connectSocket(mDevice, mType, - mUuid, mPort, getSecurityFlags()); - synchronized (this) { - if (DBG) Log.d(TAG, "connect(), SocketState: " + mSocketState + ", mPfd: " + mPfd); - if (mSocketState == SocketState.CLOSED) throw new IOException("socket closed"); - if (mPfd == null) throw new IOException("bt socket connect failed"); - FileDescriptor fd = mPfd.getFileDescriptor(); - mSocket = LocalSocket.createConnectedLocalSocket(fd); - mSocketIS = mSocket.getInputStream(); - mSocketOS = mSocket.getOutputStream(); - } - int channel = readInt(mSocketIS); - if (channel <= 0) { - throw new IOException("bt socket connect failed"); - } - mPort = channel; - waitSocketSignal(mSocketIS); - synchronized (this) { - if (mSocketState == SocketState.CLOSED) { - throw new IOException("bt socket closed"); - } - mSocketState = SocketState.CONNECTED; - } - } catch (RemoteException e) { - Log.e(TAG, Log.getStackTraceString(new Throwable())); - throw new IOException("unable to send RPC: " + e.getMessage()); - } - } - - /** - * Currently returns unix errno instead of throwing IOException, - * so that BluetoothAdapter can check the error code for EADDRINUSE - */ - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - /*package*/ int bindListen() { - int ret; - if (mSocketState == SocketState.CLOSED) return EBADFD; - IBluetooth bluetoothProxy = BluetoothAdapter.getDefaultAdapter().getBluetoothService(); - if (bluetoothProxy == null) { - Log.e(TAG, "bindListen fail, reason: bluetooth is off"); - return -1; - } - try { - if (DBG) Log.d(TAG, "bindListen(): mPort=" + mPort + ", mType=" + mType); - mPfd = bluetoothProxy.getSocketManager().createSocketChannel(mType, mServiceName, - mUuid, mPort, getSecurityFlags()); - } catch (RemoteException e) { - Log.e(TAG, Log.getStackTraceString(new Throwable())); - return -1; - } - - // read out port number - try { - synchronized (this) { - if (DBG) { - Log.d(TAG, "bindListen(), SocketState: " + mSocketState + ", mPfd: " + mPfd); - } - if (mSocketState != SocketState.INIT) return EBADFD; - if (mPfd == null) return -1; - FileDescriptor fd = mPfd.getFileDescriptor(); - if (fd == null) { - Log.e(TAG, "bindListen(), null file descriptor"); - return -1; - } - - if (DBG) Log.d(TAG, "bindListen(), Create LocalSocket"); - mSocket = LocalSocket.createConnectedLocalSocket(fd); - if (DBG) Log.d(TAG, "bindListen(), new LocalSocket.getInputStream()"); - mSocketIS = mSocket.getInputStream(); - mSocketOS = mSocket.getOutputStream(); - } - if (DBG) Log.d(TAG, "bindListen(), readInt mSocketIS: " + mSocketIS); - int channel = readInt(mSocketIS); - synchronized (this) { - if (mSocketState == SocketState.INIT) { - mSocketState = SocketState.LISTENING; - } - } - if (DBG) Log.d(TAG, "bindListen(): channel=" + channel + ", mPort=" + mPort); - if (mPort <= -1) { - mPort = channel; - } // else ASSERT(mPort == channel) - ret = 0; - } catch (IOException e) { - if (mPfd != null) { - try { - mPfd.close(); - } catch (IOException e1) { - Log.e(TAG, "bindListen, close mPfd: " + e1); - } - mPfd = null; - } - Log.e(TAG, "bindListen, fail to get port number, exception: " + e); - return -1; - } - return ret; - } - - /*package*/ BluetoothSocket accept(int timeout) throws IOException { - BluetoothSocket acceptedSocket; - if (mSocketState != SocketState.LISTENING) { - throw new IOException("bt socket is not in listen state"); - } - if (timeout > 0) { - Log.d(TAG, "accept() set timeout (ms):" + timeout); - mSocket.setSoTimeout(timeout); - } - String RemoteAddr = waitSocketSignal(mSocketIS); - if (timeout > 0) { - mSocket.setSoTimeout(0); - } - synchronized (this) { - if (mSocketState != SocketState.LISTENING) { - throw new IOException("bt socket is not in listen state"); - } - acceptedSocket = acceptSocket(RemoteAddr); - //quick drop the reference of the file handle - } - return acceptedSocket; - } - - /*package*/ int available() throws IOException { - if (VDBG) Log.d(TAG, "available: " + mSocketIS); - return mSocketIS.available(); - } - - /*package*/ int read(byte[] b, int offset, int length) throws IOException { - int ret = 0; - if (VDBG) Log.d(TAG, "read in: " + mSocketIS + " len: " + length); - if ((mType == TYPE_L2CAP) || (mType == TYPE_L2CAP_LE)) { - int bytesToRead = length; - if (VDBG) { - Log.v(TAG, "l2cap: read(): offset: " + offset + " length:" + length - + "mL2capBuffer= " + mL2capBuffer); - } - if (mL2capBuffer == null) { - createL2capRxBuffer(); - } - if (mL2capBuffer.remaining() == 0) { - if (VDBG) Log.v(TAG, "l2cap buffer empty, refilling..."); - if (fillL2capRxBuffer() == -1) { - return -1; - } - } - if (bytesToRead > mL2capBuffer.remaining()) { - bytesToRead = mL2capBuffer.remaining(); - } - if (VDBG) { - Log.v(TAG, "get(): offset: " + offset - + " bytesToRead: " + bytesToRead); - } - mL2capBuffer.get(b, offset, bytesToRead); - ret = bytesToRead; - } else { - if (VDBG) Log.v(TAG, "default: read(): offset: " + offset + " length:" + length); - ret = mSocketIS.read(b, offset, length); - } - if (ret < 0) { - throw new IOException("bt socket closed, read return: " + ret); - } - if (VDBG) Log.d(TAG, "read out: " + mSocketIS + " ret: " + ret); - return ret; - } - - /*package*/ int write(byte[] b, int offset, int length) throws IOException { - - //TODO: Since bindings can exist between the SDU size and the - // protocol, we might need to throw an exception instead of just - // splitting the write into multiple smaller writes. - // Rfcomm uses dynamic allocation, and should not have any bindings - // to the actual message length. - if (VDBG) Log.d(TAG, "write: " + mSocketOS + " length: " + length); - if ((mType == TYPE_L2CAP) || (mType == TYPE_L2CAP_LE)) { - if (length <= mMaxTxPacketSize) { - mSocketOS.write(b, offset, length); - } else { - if (DBG) { - Log.w(TAG, "WARNING: Write buffer larger than L2CAP packet size!\n" - + "Packet will be divided into SDU packets of size " - + mMaxTxPacketSize); - } - int tmpOffset = offset; - int bytesToWrite = length; - while (bytesToWrite > 0) { - int tmpLength = (bytesToWrite > mMaxTxPacketSize) - ? mMaxTxPacketSize - : bytesToWrite; - mSocketOS.write(b, tmpOffset, tmpLength); - tmpOffset += tmpLength; - bytesToWrite -= tmpLength; - } - } - } else { - mSocketOS.write(b, offset, length); - } - // There is no good way to confirm since the entire process is asynchronous anyway - if (VDBG) Log.d(TAG, "write out: " + mSocketOS + " length: " + length); - return length; - } - - @Override - public void close() throws IOException { - Log.d(TAG, "close() this: " + this + ", channel: " + mPort + ", mSocketIS: " + mSocketIS - + ", mSocketOS: " + mSocketOS + "mSocket: " + mSocket + ", mSocketState: " - + mSocketState); - if (mSocketState == SocketState.CLOSED) { - return; - } else { - synchronized (this) { - if (mSocketState == SocketState.CLOSED) { - return; - } - mSocketState = SocketState.CLOSED; - if (mSocket != null) { - if (DBG) Log.d(TAG, "Closing mSocket: " + mSocket); - mSocket.shutdownInput(); - mSocket.shutdownOutput(); - mSocket.close(); - mSocket = null; - } - if (mPfd != null) { - mPfd.close(); - mPfd = null; - } - } - } - } - - /*package */ void removeChannel() { - } - - /*package */ int getPort() { - return mPort; - } - - /** - * Get the maximum supported Transmit packet size for the underlying transport. - * Use this to optimize the writes done to the output socket, to avoid sending - * half full packets. - * - * @return the maximum supported Transmit packet size for the underlying transport. - */ - @RequiresNoPermission - public int getMaxTransmitPacketSize() { - return mMaxTxPacketSize; - } - - /** - * Get the maximum supported Receive packet size for the underlying transport. - * Use this to optimize the reads done on the input stream, as any call to read - * will return a maximum of this amount of bytes - or for some transports a - * multiple of this value. - * - * @return the maximum supported Receive packet size for the underlying transport. - */ - @RequiresNoPermission - public int getMaxReceivePacketSize() { - return mMaxRxPacketSize; - } - - /** - * Get the type of the underlying connection. - * - * @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. - return TYPE_L2CAP; - } - return mType; - } - - /** - * Change if a SDP entry should be automatically created. - * Must be called before calling .bind, for the call to have any effect. - * - * @param excludeSdp

  • TRUE - do not auto generate SDP record.
  • FALSE - default - auto - * generate SPP SDP record. - * @hide - */ - @RequiresNoPermission - public void setExcludeSdp(boolean excludeSdp) { - mExcludeSdp = excludeSdp; - } - - /** - * Set the LE Transmit Data Length to be the maximum that the BT Controller is capable of. This - * parameter is used by the BT Controller to set the maximum transmission packet size on this - * 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) { - throw new IOException("requestMaximumTxDataLength is called on null device"); - } - - try { - if (mSocketState == SocketState.CLOSED) { - throw new IOException("socket closed"); - } - IBluetooth bluetoothProxy = - BluetoothAdapter.getDefaultAdapter().getBluetoothService(); - if (bluetoothProxy == null) { - throw new IOException("Bluetooth is off"); - } - - if (DBG) Log.d(TAG, "requestMaximumTxDataLength"); - bluetoothProxy.getSocketManager().requestMaximumTxDataLength(mDevice); - } catch (RemoteException e) { - Log.e(TAG, Log.getStackTraceString(new Throwable())); - throw new IOException("unable to send RPC: " + e.getMessage()); - } - } - - private String convertAddr(final byte[] addr) { - return String.format(Locale.US, "%02X:%02X:%02X:%02X:%02X:%02X", - addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]); - } - - private String waitSocketSignal(InputStream is) throws IOException { - byte[] sig = new byte[SOCK_SIGNAL_SIZE]; - int ret = readAll(is, sig); - if (VDBG) { - Log.d(TAG, "waitSocketSignal read " + SOCK_SIGNAL_SIZE + " bytes signal ret: " + ret); - } - ByteBuffer bb = ByteBuffer.wrap(sig); - /* the struct in native is decorated with __attribute__((packed)), hence this is possible */ - bb.order(ByteOrder.nativeOrder()); - int size = bb.getShort(); - if (size != SOCK_SIGNAL_SIZE) { - throw new IOException("Connection failure, wrong signal size: " + size); - } - byte[] addr = new byte[6]; - bb.get(addr); - int channel = bb.getInt(); - int status = bb.getInt(); - mMaxTxPacketSize = (bb.getShort() & 0xffff); // Convert to unsigned value - mMaxRxPacketSize = (bb.getShort() & 0xffff); // Convert to unsigned value - String RemoteAddr = convertAddr(addr); - if (VDBG) { - Log.d(TAG, "waitSocketSignal: sig size: " + size + ", remote addr: " - + RemoteAddr + ", channel: " + channel + ", status: " + status - + " MaxRxPktSize: " + mMaxRxPacketSize + " MaxTxPktSize: " + mMaxTxPacketSize); - } - if (status != 0) { - throw new IOException("Connection failure, status: " + status); - } - return RemoteAddr; - } - - private void createL2capRxBuffer() { - if ((mType == TYPE_L2CAP) || (mType == TYPE_L2CAP_LE)) { - // Allocate the buffer to use for reads. - if (VDBG) Log.v(TAG, " Creating mL2capBuffer: mMaxPacketSize: " + mMaxRxPacketSize); - mL2capBuffer = ByteBuffer.wrap(new byte[mMaxRxPacketSize]); - if (VDBG) Log.v(TAG, "mL2capBuffer.remaining()" + mL2capBuffer.remaining()); - mL2capBuffer.limit(0); // Ensure we do a real read at the first read-request - if (VDBG) { - Log.v(TAG, "mL2capBuffer.remaining() after limit(0):" + mL2capBuffer.remaining()); - } - } - } - - private int readAll(InputStream is, byte[] b) throws IOException { - int left = b.length; - while (left > 0) { - int ret = is.read(b, b.length - left, left); - if (ret <= 0) { - throw new IOException("read failed, socket might closed or timeout, read ret: " - + ret); - } - left -= ret; - if (left != 0) { - Log.w(TAG, "readAll() looping, read partial size: " + (b.length - left) - + ", expect size: " + b.length); - } - } - return b.length; - } - - private int readInt(InputStream is) throws IOException { - byte[] ibytes = new byte[4]; - int ret = readAll(is, ibytes); - if (VDBG) Log.d(TAG, "inputStream.read ret: " + ret); - ByteBuffer bb = ByteBuffer.wrap(ibytes); - bb.order(ByteOrder.nativeOrder()); - return bb.getInt(); - } - - private int fillL2capRxBuffer() throws IOException { - mL2capBuffer.rewind(); - int ret = mSocketIS.read(mL2capBuffer.array()); - if (ret == -1) { - // reached end of stream - return -1 - mL2capBuffer.limit(0); - return -1; - } - mL2capBuffer.limit(ret); - return ret; - } - - -} diff --git a/core/java/android/bluetooth/BluetoothStatusCodes.java b/core/java/android/bluetooth/BluetoothStatusCodes.java deleted file mode 100644 index 9dafa073ab3fc96dffb2e5ac84a29e5e1aa03d67..0000000000000000000000000000000000000000 --- a/core/java/android/bluetooth/BluetoothStatusCodes.java +++ /dev/null @@ -1,292 +0,0 @@ -/* - * 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.bluetooth; - -import android.annotation.SystemApi; - -/** - * A class with constants representing possible return values for Bluetooth APIs. General return - * values occupy the range 0 to 99. Profile-specific return values occupy the range 100-999. - * API-specific return values start at 1000. The exception to this is the "UNKNOWN" error code which - * occupies the max integer value. - */ -public final class BluetoothStatusCodes { - - private BluetoothStatusCodes() {} - - /** - * Indicates that the API call was successful - */ - public static final int SUCCESS = 0; - - /** - * Error code indicating that Bluetooth is not enabled - */ - public static final int ERROR_BLUETOOTH_NOT_ENABLED = 1; - - /** - * Error code indicating that the API call was initiated by neither the system nor the active - * Zuser - */ - public static final int ERROR_BLUETOOTH_NOT_ALLOWED = 2; - - /** - * Error code indicating that the Bluetooth Device specified is not bonded - */ - public static final int ERROR_DEVICE_NOT_BONDED = 3; - - /** - * Error code indicating that the Bluetooth Device specified is not connected, but is bonded - * - * @hide - */ - public static final int ERROR_DEVICE_NOT_CONNECTED = 4; - - /** - * Error code indicating that the caller does not have the - * {@link android.Manifest.permission#BLUETOOTH_ADVERTISE} permission - * - * @hide - */ - public static final int ERROR_MISSING_BLUETOOTH_ADVERTISE_PERMISSION = 5; - - /** - * Error code indicating that the caller does not have the - * {@link android.Manifest.permission#BLUETOOTH_CONNECT} permission - */ - public static final int ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION = 6; - - /** - * Error code indicating that the caller does not have the - * {@link android.Manifest.permission#BLUETOOTH_SCAN} permission - * - * @hide - */ - public static final int ERROR_MISSING_BLUETOOTH_SCAN_PERMISSION = 7; - - /** - * Error code indicating that the caller does not have the - * {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED} permission - */ - public static final int ERROR_MISSING_BLUETOOTH_PRIVILEGED_PERMISSION = 8; - - /** - * Error code indicating that the profile service is not bound. You can bind a profile service - * by calling {@link BluetoothAdapter#getProfileProxy} - */ - public static final int ERROR_PROFILE_SERVICE_NOT_BOUND = 9; - - /** - * Error code indicating that the feature is not supported. - */ - public static final int ERROR_FEATURE_NOT_SUPPORTED = 10; - - /** - * A GATT writeCharacteristic request is not permitted on the remote device. - */ - public static final int ERROR_GATT_WRITE_NOT_ALLOWED = 101; - - /** - * A GATT writeCharacteristic request is issued to a busy remote device. - */ - public static final int ERROR_GATT_WRITE_REQUEST_BUSY = 102; - - /** - * If another application has already requested {@link OobData} then another fetch will be - * disallowed until the callback is removed. - * - * @hide - */ - @SystemApi - public static final int ERROR_ANOTHER_ACTIVE_OOB_REQUEST = 1000; - - /** - * Indicates that the ACL disconnected due to an explicit request from the local device. - *

    - * Example cause: This is a normal disconnect reason, e.g., user/app initiates - * disconnection. - * - * @hide - */ - public static final int ERROR_DISCONNECT_REASON_LOCAL_REQUEST = 1100; - - /** - * Indicates that the ACL disconnected due to an explicit request from the remote device. - *

    - * Example cause: This is a normal disconnect reason, e.g., user/app initiates - * disconnection. - *

    - * Example solution: The app can also prompt the user to check their remote device. - * - * @hide - */ - public static final int ERROR_DISCONNECT_REASON_REMOTE_REQUEST = 1101; - - /** - * Generic disconnect reason indicating the ACL disconnected due to an error on the local - * device. - *

    - * Example solution: Prompt the user to check their local device (e.g., phone, car - * headunit). - * - * @hide - */ - public static final int ERROR_DISCONNECT_REASON_LOCAL = 1102; - - /** - * Generic disconnect reason indicating the ACL disconnected due to an error on the remote - * device. - *

    - * Example solution: Prompt the user to check their remote device (e.g., headset, car - * headunit, watch). - * - * @hide - */ - public static final int ERROR_DISCONNECT_REASON_REMOTE = 1103; - - /** - * Indicates that the ACL disconnected due to a timeout. - *

    - * Example cause: remote device might be out of range. - *

    - * Example solution: Prompt user to verify their remote device is on or in - * connection/pairing mode. - * - * @hide - */ - public static final int ERROR_DISCONNECT_REASON_TIMEOUT = 1104; - - /** - * Indicates that the ACL disconnected due to link key issues. - *

    - * Example cause: Devices are either unpaired or remote device is refusing our pairing - * request. - *

    - * Example solution: Prompt user to unpair and pair again. - * - * @hide - */ - public static final int ERROR_DISCONNECT_REASON_SECURITY = 1105; - - /** - * Indicates that the ACL disconnected due to the local device's system policy. - *

    - * Example cause: privacy policy, power management policy, permissions, etc. - *

    - * Example solution: Prompt the user to check settings, or check with their system - * administrator (e.g. some corp-managed devices do not allow OPP connection). - * - * @hide - */ - public static final int ERROR_DISCONNECT_REASON_SYSTEM_POLICY = 1106; - - /** - * Indicates that the ACL disconnected due to resource constraints, either on the local - * device or the remote device. - *

    - * Example cause: controller is busy, memory limit reached, maximum number of connections - * reached. - *

    - * Example solution: The app should wait and try again. If still failing, prompt the user - * to disconnect some devices, or toggle Bluetooth on the local and/or the remote device. - * - * @hide - */ - public static final int ERROR_DISCONNECT_REASON_RESOURCE_LIMIT_REACHED = 1107; - - /** - * Indicates that the ACL disconnected because another ACL connection already exists. - * - * @hide - */ - public static final int ERROR_DISCONNECT_REASON_CONNECTION_ALREADY_EXISTS = 1108; - - /** - * Indicates that the ACL disconnected due to incorrect parameters passed in from the app. - *

    - * Example solution: Change parameters and try again. If error persists, the app can report - * telemetry and/or log the error in a bugreport. - * - * @hide - */ - public static final int ERROR_DISCONNECT_REASON_BAD_PARAMETERS = 1109; - - /** - * Indicates that setting the LE Audio Broadcast mode failed. - *

    - * Example solution: Change parameters and try again. If error persists, the app can report - * telemetry and/or log the error in a bugreport. - * - * @hide - */ - public static final int ERROR_LE_AUDIO_BROADCAST_SOURCE_SET_BROADCAST_MODE_FAILED = 1110; - - /** - * Indicates that setting a new encryption key for Bluetooth LE Audio Broadcast Source failed. - *

    - * Example solution: Change parameters and try again. If error persists, the app can report - * telemetry and/or log the error in a bugreport. - * - * @hide - */ - public static final int ERROR_LE_AUDIO_BROADCAST_SOURCE_SET_ENCRYPTION_KEY_FAILED = 1111; - - /** - * Indicates that connecting to a remote Broadcast Audio Scan Service failed. - *

    - * Example solution: Change parameters and try again. If error persists, the app can report - * telemetry and/or log the error in a bugreport. - * - * @hide - */ - public static final int ERROR_LE_AUDIO_BROADCAST_AUDIO_SCAN_SERVICE_CONNECT_FAILED = 1112; - - /** - * Indicates that disconnecting from a remote Broadcast Audio Scan Service failed. - *

    - * Example solution: Change parameters and try again. If error persists, the app can report - * telemetry and/or log the error in a bugreport. - * - * @hide - */ - public static final int ERROR_LE_AUDIO_BROADCAST_AUDIO_SCAN_SERVICE_DISCONNECT_FAILED = 1113; - - /** - * Indicates that enabling LE Audio Broadcast encryption failed - *

    - * Example solution: Change parameters and try again. If error persists, the app can report - * telemetry and/or log the error in a bugreport. - * - * @hide - */ - public static final int ERROR_LE_AUDIO_BROADCAST_SOURCE_ENABLE_ENCRYPTION_FAILED = 1114; - - /** - * Indicates that disabling LE Audio Broadcast encryption failed - *

    - * Example solution: Change parameters and try again. If error persists, the app can report - * telemetry and/or log the error in a bugreport. - * - * @hide - */ - public static final int ERROR_LE_AUDIO_BROADCAST_SOURCE_DISABLE_ENCRYPTION_FAILED = 1115; - - /** - * Indicates that an unknown error has occurred has occurred. - */ - public static final int ERROR_UNKNOWN = Integer.MAX_VALUE; -} diff --git a/core/java/android/bluetooth/BluetoothUtils.java b/core/java/android/bluetooth/BluetoothUtils.java deleted file mode 100644 index 867469241f84c778e66bc000817b2fdea18919f6..0000000000000000000000000000000000000000 --- a/core/java/android/bluetooth/BluetoothUtils.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * 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.bluetooth; - -import java.time.Duration; - -/** - * {@hide} - */ -public final class BluetoothUtils { - /** - * This utility class cannot be instantiated - */ - private BluetoothUtils() {} - - /** - * Timeout value for synchronous binder call - */ - private static final Duration SYNC_CALLS_TIMEOUT = Duration.ofSeconds(5); - - /** - * @return timeout value for synchronous binder call - */ - static Duration getSyncTimeout() { - return SYNC_CALLS_TIMEOUT; - } -} diff --git a/core/java/android/bluetooth/BluetoothUuid.java b/core/java/android/bluetooth/BluetoothUuid.java deleted file mode 100644 index 2a8ff5185085b91f50270ca28d58f5d2a11344d7..0000000000000000000000000000000000000000 --- a/core/java/android/bluetooth/BluetoothUuid.java +++ /dev/null @@ -1,394 +0,0 @@ -/* - * Copyright (C) 2009 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.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; - -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.util.Arrays; -import java.util.HashSet; -import java.util.UUID; - -/** - * Static helper methods and constants to decode the ParcelUuid of remote devices. - * - * @hide - */ -@SystemApi -@SuppressLint("AndroidFrameworkBluetoothPermission") -public final class BluetoothUuid { - - /* See Bluetooth Assigned Numbers document - SDP section, to get the values of UUIDs - * for the various services. - * - * The following 128 bit values are calculated as: - * uuid * 2^96 + BASE_UUID - */ - - /** @hide */ - @NonNull - @SystemApi - public static final ParcelUuid A2DP_SINK = - ParcelUuid.fromString("0000110B-0000-1000-8000-00805F9B34FB"); - /** @hide */ - @NonNull - @SystemApi - public static final ParcelUuid A2DP_SOURCE = - ParcelUuid.fromString("0000110A-0000-1000-8000-00805F9B34FB"); - /** @hide */ - @NonNull - @SystemApi - public static final ParcelUuid ADV_AUDIO_DIST = - ParcelUuid.fromString("0000110D-0000-1000-8000-00805F9B34FB"); - /** @hide */ - @NonNull - @SystemApi - public static final ParcelUuid HSP = - ParcelUuid.fromString("00001108-0000-1000-8000-00805F9B34FB"); - /** @hide */ - @NonNull - @SystemApi - public static final ParcelUuid HSP_AG = - ParcelUuid.fromString("00001112-0000-1000-8000-00805F9B34FB"); - /** @hide */ - @NonNull - @SystemApi - public static final ParcelUuid HFP = - ParcelUuid.fromString("0000111E-0000-1000-8000-00805F9B34FB"); - /** @hide */ - @NonNull - @SystemApi - public static final ParcelUuid HFP_AG = - ParcelUuid.fromString("0000111F-0000-1000-8000-00805F9B34FB"); - /** @hide */ - @NonNull - @SystemApi - public static final ParcelUuid AVRCP_CONTROLLER = - ParcelUuid.fromString("0000110E-0000-1000-8000-00805F9B34FB"); - /** @hide */ - @NonNull - @SystemApi - public static final ParcelUuid AVRCP_TARGET = - ParcelUuid.fromString("0000110C-0000-1000-8000-00805F9B34FB"); - /** @hide */ - @NonNull - @SystemApi - public static final ParcelUuid OBEX_OBJECT_PUSH = - ParcelUuid.fromString("00001105-0000-1000-8000-00805f9b34fb"); - /** @hide */ - @NonNull - @SystemApi - public static final ParcelUuid HID = - ParcelUuid.fromString("00001124-0000-1000-8000-00805f9b34fb"); - /** @hide */ - @NonNull - @SystemApi - public static final ParcelUuid HOGP = - ParcelUuid.fromString("00001812-0000-1000-8000-00805f9b34fb"); - /** @hide */ - @NonNull - @SystemApi - public static final ParcelUuid PANU = - ParcelUuid.fromString("00001115-0000-1000-8000-00805F9B34FB"); - /** @hide */ - @NonNull - @SystemApi - public static final ParcelUuid NAP = - ParcelUuid.fromString("00001116-0000-1000-8000-00805F9B34FB"); - /** @hide */ - @NonNull - @SystemApi - public static final ParcelUuid BNEP = - ParcelUuid.fromString("0000000f-0000-1000-8000-00805F9B34FB"); - /** @hide */ - @NonNull - @SystemApi - public static final ParcelUuid PBAP_PCE = - ParcelUuid.fromString("0000112e-0000-1000-8000-00805F9B34FB"); - /** @hide */ - @NonNull - @SystemApi - public static final ParcelUuid PBAP_PSE = - ParcelUuid.fromString("0000112f-0000-1000-8000-00805F9B34FB"); - /** @hide */ - @NonNull - @SystemApi - public static final ParcelUuid MAP = - ParcelUuid.fromString("00001134-0000-1000-8000-00805F9B34FB"); - /** @hide */ - @NonNull - @SystemApi - public static final ParcelUuid MNS = - ParcelUuid.fromString("00001133-0000-1000-8000-00805F9B34FB"); - /** @hide */ - @NonNull - @SystemApi - public static final ParcelUuid MAS = - ParcelUuid.fromString("00001132-0000-1000-8000-00805F9B34FB"); - /** @hide */ - @NonNull - @SystemApi - public static final ParcelUuid SAP = - ParcelUuid.fromString("0000112D-0000-1000-8000-00805F9B34FB"); - /** @hide */ - @NonNull - @SystemApi - public static final ParcelUuid HEARING_AID = - ParcelUuid.fromString("0000FDF0-0000-1000-8000-00805f9b34fb"); - /** @hide */ - @NonNull - @SystemApi - public static final ParcelUuid LE_AUDIO = - ParcelUuid.fromString("0000184E-0000-1000-8000-00805F9B34FB"); - /** @hide */ - @NonNull - @SystemApi - public static final ParcelUuid DIP = - ParcelUuid.fromString("00001200-0000-1000-8000-00805F9B34FB"); - /** @hide */ - @NonNull - @SystemApi - public static final ParcelUuid VOLUME_CONTROL = - ParcelUuid.fromString("00001844-0000-1000-8000-00805F9B34FB"); - /** @hide */ - @NonNull - @SystemApi - public static final ParcelUuid GENERIC_MEDIA_CONTROL = - ParcelUuid.fromString("00001849-0000-1000-8000-00805F9B34FB"); - /** @hide */ - @NonNull - @SystemApi - public static final ParcelUuid MEDIA_CONTROL = - ParcelUuid.fromString("00001848-0000-1000-8000-00805F9B34FB"); - /** @hide */ - @NonNull - @SystemApi - public static final ParcelUuid COORDINATED_SET = - ParcelUuid.fromString("00001846-0000-1000-8000-00805F9B34FB"); - /** @hide */ - @NonNull - @SystemApi - public static final ParcelUuid CAP = - ParcelUuid.fromString("00001853-0000-1000-8000-00805F9B34FB"); - /** @hide */ - @NonNull - @SystemApi - public static final ParcelUuid BASE_UUID = - ParcelUuid.fromString("00000000-0000-1000-8000-00805F9B34FB"); - - /** - * Length of bytes for 16 bit UUID - * - * @hide - */ - @SystemApi - public static final int UUID_BYTES_16_BIT = 2; - /** - * Length of bytes for 32 bit UUID - * - * @hide - */ - @SystemApi - public static final int UUID_BYTES_32_BIT = 4; - /** - * Length of bytes for 128 bit UUID - * - * @hide - */ - @SystemApi - public static final int UUID_BYTES_128_BIT = 16; - - /** - * Returns true if there any common ParcelUuids in uuidA and uuidB. - * - * @param uuidA - List of ParcelUuids - * @param uuidB - List of ParcelUuids - * - * @hide - */ - @SystemApi - public static boolean containsAnyUuid(@Nullable ParcelUuid[] uuidA, - @Nullable ParcelUuid[] uuidB) { - if (uuidA == null && uuidB == null) return true; - - if (uuidA == null) { - return uuidB.length == 0; - } - - if (uuidB == null) { - return uuidA.length == 0; - } - - HashSet uuidSet = new HashSet(Arrays.asList(uuidA)); - for (ParcelUuid uuid : uuidB) { - if (uuidSet.contains(uuid)) return true; - } - return false; - } - - /** - * Extract the Service Identifier or the actual uuid from the Parcel Uuid. - * For example, if 0000110B-0000-1000-8000-00805F9B34FB is the parcel Uuid, - * this function will return 110B - * - * @param parcelUuid - * @return the service identifier. - */ - private static int getServiceIdentifierFromParcelUuid(ParcelUuid parcelUuid) { - UUID uuid = parcelUuid.getUuid(); - long value = (uuid.getMostSignificantBits() & 0xFFFFFFFF00000000L) >>> 32; - return (int) value; - } - - /** - * Parse UUID from bytes. The {@code uuidBytes} can represent a 16-bit, 32-bit or 128-bit UUID, - * but the returned UUID is always in 128-bit format. - * Note UUID is little endian in Bluetooth. - * - * @param uuidBytes Byte representation of uuid. - * @return {@link ParcelUuid} parsed from bytes. - * @throws IllegalArgumentException If the {@code uuidBytes} cannot be parsed. - * - * @hide - */ - @NonNull - @SystemApi - public static ParcelUuid parseUuidFrom(@Nullable byte[] uuidBytes) { - if (uuidBytes == null) { - throw new IllegalArgumentException("uuidBytes cannot be null"); - } - int length = uuidBytes.length; - if (length != UUID_BYTES_16_BIT && length != UUID_BYTES_32_BIT - && length != UUID_BYTES_128_BIT) { - throw new IllegalArgumentException("uuidBytes length invalid - " + length); - } - - // Construct a 128 bit UUID. - if (length == UUID_BYTES_128_BIT) { - ByteBuffer buf = ByteBuffer.wrap(uuidBytes).order(ByteOrder.LITTLE_ENDIAN); - long msb = buf.getLong(8); - long lsb = buf.getLong(0); - return new ParcelUuid(new UUID(msb, lsb)); - } - - // For 16 bit and 32 bit UUID we need to convert them to 128 bit value. - // 128_bit_value = uuid * 2^96 + BASE_UUID - long shortUuid; - if (length == UUID_BYTES_16_BIT) { - shortUuid = uuidBytes[0] & 0xFF; - shortUuid += (uuidBytes[1] & 0xFF) << 8; - } else { - shortUuid = uuidBytes[0] & 0xFF; - shortUuid += (uuidBytes[1] & 0xFF) << 8; - shortUuid += (uuidBytes[2] & 0xFF) << 16; - shortUuid += (uuidBytes[3] & 0xFF) << 24; - } - long msb = BASE_UUID.getUuid().getMostSignificantBits() + (shortUuid << 32); - long lsb = BASE_UUID.getUuid().getLeastSignificantBits(); - return new ParcelUuid(new UUID(msb, lsb)); - } - - /** - * Parse UUID to bytes. The returned value is shortest representation, a 16-bit, 32-bit or - * 128-bit UUID, Note returned value is little endian (Bluetooth). - * - * @param uuid uuid to parse. - * @return shortest representation of {@code uuid} as bytes. - * @throws IllegalArgumentException If the {@code uuid} is null. - * - * @hide - */ - public static byte[] uuidToBytes(ParcelUuid uuid) { - if (uuid == null) { - throw new IllegalArgumentException("uuid cannot be null"); - } - - if (is16BitUuid(uuid)) { - byte[] uuidBytes = new byte[UUID_BYTES_16_BIT]; - int uuidVal = getServiceIdentifierFromParcelUuid(uuid); - uuidBytes[0] = (byte) (uuidVal & 0xFF); - uuidBytes[1] = (byte) ((uuidVal & 0xFF00) >> 8); - return uuidBytes; - } - - if (is32BitUuid(uuid)) { - byte[] uuidBytes = new byte[UUID_BYTES_32_BIT]; - int uuidVal = getServiceIdentifierFromParcelUuid(uuid); - uuidBytes[0] = (byte) (uuidVal & 0xFF); - uuidBytes[1] = (byte) ((uuidVal & 0xFF00) >> 8); - uuidBytes[2] = (byte) ((uuidVal & 0xFF0000) >> 16); - uuidBytes[3] = (byte) ((uuidVal & 0xFF000000) >> 24); - return uuidBytes; - } - - // Construct a 128 bit UUID. - long msb = uuid.getUuid().getMostSignificantBits(); - long lsb = uuid.getUuid().getLeastSignificantBits(); - - byte[] uuidBytes = new byte[UUID_BYTES_128_BIT]; - ByteBuffer buf = ByteBuffer.wrap(uuidBytes).order(ByteOrder.LITTLE_ENDIAN); - buf.putLong(8, msb); - buf.putLong(0, lsb); - return uuidBytes; - } - - /** - * Check whether the given parcelUuid can be converted to 16 bit bluetooth uuid. - * - * @param parcelUuid - * @return true if the parcelUuid can be converted to 16 bit uuid, false otherwise. - * - * @hide - */ - @UnsupportedAppUsage - public static boolean is16BitUuid(ParcelUuid parcelUuid) { - UUID uuid = parcelUuid.getUuid(); - if (uuid.getLeastSignificantBits() != BASE_UUID.getUuid().getLeastSignificantBits()) { - return false; - } - return ((uuid.getMostSignificantBits() & 0xFFFF0000FFFFFFFFL) == 0x1000L); - } - - - /** - * Check whether the given parcelUuid can be converted to 32 bit bluetooth uuid. - * - * @param parcelUuid - * @return true if the parcelUuid can be converted to 32 bit uuid, false otherwise. - * - * @hide - */ - @UnsupportedAppUsage - public static boolean is32BitUuid(ParcelUuid parcelUuid) { - UUID uuid = parcelUuid.getUuid(); - if (uuid.getLeastSignificantBits() != BASE_UUID.getUuid().getLeastSignificantBits()) { - return false; - } - if (is16BitUuid(parcelUuid)) { - return false; - } - return ((uuid.getMostSignificantBits() & 0xFFFFFFFFL) == 0x1000L); - } - - private BluetoothUuid() {} -} diff --git a/core/java/android/bluetooth/BluetoothVolumeControl.java b/core/java/android/bluetooth/BluetoothVolumeControl.java deleted file mode 100644 index 27532aabc3fcd79f819a73c6a304d26fb6391c5e..0000000000000000000000000000000000000000 --- a/core/java/android/bluetooth/BluetoothVolumeControl.java +++ /dev/null @@ -1,337 +0,0 @@ -/* - * Copyright 2021 HIMSA II K/S - www.himsa.com. - * Represented by EHIMA - www.ehima.com - * - * 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.bluetooth; - -import static android.bluetooth.BluetoothUtils.getSyncTimeout; - -import android.Manifest; -import android.annotation.IntRange; -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.annotation.RequiresPermission; -import android.annotation.SdkConstant; -import android.annotation.SdkConstant.SdkConstantType; -import android.annotation.SuppressLint; -import android.annotation.SystemApi; -import android.bluetooth.annotations.RequiresBluetoothConnectPermission; -import android.content.AttributionSource; -import android.content.Context; -import android.os.IBinder; -import android.os.RemoteException; -import android.util.CloseGuard; -import android.util.Log; - -import com.android.modules.utils.SynchronousResultReceiver; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.TimeoutException; - -/** - * This class provides the public APIs to control the Bluetooth Volume Control service. - * - *

    BluetoothVolumeControl is a proxy object for controlling the Bluetooth VC - * Service via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get - * the BluetoothVolumeControl proxy object. - * @hide - */ -@SystemApi -public final class BluetoothVolumeControl implements BluetoothProfile, AutoCloseable { - private static final String TAG = "BluetoothVolumeControl"; - private static final boolean DBG = true; - private static final boolean VDBG = false; - - private CloseGuard mCloseGuard; - - /** - * Intent used to broadcast the change in connection state of the Volume Control - * profile. - * - *

    This intent will have 3 extras: - *

      - *
    • {@link #EXTRA_STATE} - The current state of the profile.
    • - *
    • {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile.
    • - *
    • {@link BluetoothDevice#EXTRA_DEVICE} - The remote device.
    • - *
    - * - *

    {@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of - * {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING}, - * {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}. - * - * @hide - */ - @SystemApi - @SuppressLint("ActionValue") - @RequiresBluetoothConnectPermission - @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT) - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - public static final String ACTION_CONNECTION_STATE_CHANGED = - "android.bluetooth.volume-control.profile.action.CONNECTION_STATE_CHANGED"; - - private BluetoothAdapter mAdapter; - private final AttributionSource mAttributionSource; - private final BluetoothProfileConnector mProfileConnector = - new BluetoothProfileConnector(this, BluetoothProfile.VOLUME_CONTROL, TAG, - IBluetoothVolumeControl.class.getName()) { - @Override - public IBluetoothVolumeControl getServiceInterface(IBinder service) { - return IBluetoothVolumeControl.Stub.asInterface(service); - } - }; - - /** - * Create a BluetoothVolumeControl proxy object for interacting with the local - * Bluetooth Volume Control service. - */ - /*package*/ BluetoothVolumeControl(Context context, ServiceListener listener, - BluetoothAdapter adapter) { - mAdapter = adapter; - mAttributionSource = adapter.getAttributionSource(); - mProfileConnector.connect(context, listener); - mCloseGuard = new CloseGuard(); - mCloseGuard.open("close"); - } - - @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) - protected void finalize() { - if (mCloseGuard != null) { - mCloseGuard.warnIfOpen(); - } - close(); - } - - @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) - public void close() { - mProfileConnector.disconnect(); - } - - private IBluetoothVolumeControl getService() { return mProfileConnector.getService(); } - - /** - * Get the list of connected devices. Currently at most one. - * - * @return list of connected devices - * - * @hide - */ - @SystemApi - @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) - public @NonNull List getConnectedDevices() { - if (DBG) log("getConnectedDevices()"); - final IBluetoothVolumeControl service = getService(); - final List defaultValue = new ArrayList(); - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled()) { - try { - final SynchronousResultReceiver> recv = - new SynchronousResultReceiver(); - service.getConnectedDevices(mAttributionSource, recv); - return Attributable.setAttributionSource( - recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue), - mAttributionSource); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Get the list of devices matching specified states. Currently at most one. - * - * @return list of matching devices - * - * @hide - */ - @RequiresBluetoothConnectPermission - @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT) - public List getDevicesMatchingConnectionStates(int[] states) { - if (DBG) log("getDevicesMatchingStates()"); - final IBluetoothVolumeControl service = getService(); - final List defaultValue = new ArrayList(); - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled()) { - try { - final SynchronousResultReceiver> recv = - new SynchronousResultReceiver(); - service.getDevicesMatchingConnectionStates(states, mAttributionSource, recv); - return Attributable.setAttributionSource( - recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue), - mAttributionSource); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Get connection state of device - * - * @return device connection state - * - * @hide - */ - @RequiresBluetoothConnectPermission - @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT) - public int getConnectionState(BluetoothDevice device) { - if (DBG) log("getConnectionState(" + device + ")"); - final IBluetoothVolumeControl service = getService(); - final int defaultValue = BluetoothProfile.STATE_DISCONNECTED; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device)) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.getConnectionState(device, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Tells remote device to set an absolute volume. - * - * @param volume Absolute volume to be set on remote device. - * Minimum value is 0 and maximum value is 255 - * @hide - */ - @SystemApi - @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) - public void setVolume(@Nullable BluetoothDevice device, - @IntRange(from = 0, to = 255) int volume) { - if (DBG) log("setVolume(" + volume + ")"); - final IBluetoothVolumeControl service = getService(); - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled()) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.setVolume(device, volume, mAttributionSource, recv); - recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(null); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - } - - /** - * Set connection policy of the profile - * - *

    The device should already be paired. - * Connection policy can be one of {@link #CONNECTION_POLICY_ALLOWED}, - * {@link #CONNECTION_POLICY_FORBIDDEN}, {@link #CONNECTION_POLICY_UNKNOWN} - * - * @param device Paired bluetooth device - * @param connectionPolicy is the connection policy to set to for this profile - * @return true if connectionPolicy is set, false on error - * @hide - */ - @SystemApi - @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) - public boolean setConnectionPolicy(@NonNull BluetoothDevice device, - @ConnectionPolicy int connectionPolicy) { - if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")"); - final IBluetoothVolumeControl service = getService(); - final boolean defaultValue = false; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device) - && (connectionPolicy == BluetoothProfile.CONNECTION_POLICY_FORBIDDEN - || connectionPolicy == BluetoothProfile.CONNECTION_POLICY_ALLOWED)) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.setConnectionPolicy(device, connectionPolicy, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - /** - * Get the connection policy of the profile. - * - *

    The connection policy can be any of: - * {@link #CONNECTION_POLICY_ALLOWED}, {@link #CONNECTION_POLICY_FORBIDDEN}, - * {@link #CONNECTION_POLICY_UNKNOWN} - * - * @param device Bluetooth device - * @return connection policy of the device - * @hide - */ - @SystemApi - @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) - public @ConnectionPolicy int getConnectionPolicy(@NonNull BluetoothDevice device) { - if (VDBG) log("getConnectionPolicy(" + device + ")"); - final IBluetoothVolumeControl service = getService(); - final int defaultValue = BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device)) { - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.getConnectionPolicy(device, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } - } - return defaultValue; - } - - private boolean isEnabled() { - return mAdapter.getState() == BluetoothAdapter.STATE_ON; - } - - private static boolean isValidDevice(@Nullable BluetoothDevice device) { - return device != null && BluetoothAdapter.checkBluetoothAddress(device.getAddress()); - } - - private static void log(String msg) { - Log.d(TAG, msg); - } -} diff --git a/core/java/android/bluetooth/BufferConstraint.java b/core/java/android/bluetooth/BufferConstraint.java deleted file mode 100644 index cbffc788c35dcbccd7dcb22c65be44d84768b623..0000000000000000000000000000000000000000 --- a/core/java/android/bluetooth/BufferConstraint.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright (C) 2020 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.bluetooth; - -import android.annotation.NonNull; -import android.annotation.SystemApi; -import android.os.Parcel; -import android.os.Parcelable; - -/** - * Stores a codec's constraints on buffering length in milliseconds. - * - * {@hide} - */ -@SystemApi -public final class BufferConstraint implements Parcelable { - - private static final String TAG = "BufferConstraint"; - private int mDefaultMillis; - private int mMaxMillis; - private int mMinMillis; - - public BufferConstraint(int defaultMillis, int maxMillis, - int minMillis) { - mDefaultMillis = defaultMillis; - mMaxMillis = maxMillis; - mMinMillis = minMillis; - } - - BufferConstraint(Parcel in) { - mDefaultMillis = in.readInt(); - mMaxMillis = in.readInt(); - mMinMillis = in.readInt(); - } - - public static final @NonNull Parcelable.Creator CREATOR = - new Parcelable.Creator() { - public BufferConstraint createFromParcel(Parcel in) { - return new BufferConstraint(in); - } - - public BufferConstraint[] newArray(int size) { - return new BufferConstraint[size]; - } - }; - - @Override - public void writeToParcel(@NonNull Parcel out, int flags) { - out.writeInt(mDefaultMillis); - out.writeInt(mMaxMillis); - out.writeInt(mMinMillis); - } - - @Override - public int describeContents() { - return 0; - } - - /** - * Get the default buffer millis - * - * @return default buffer millis - * @hide - */ - @SystemApi - public int getDefaultMillis() { - return mDefaultMillis; - } - - /** - * Get the maximum buffer millis - * - * @return maximum buffer millis - * @hide - */ - @SystemApi - public int getMaxMillis() { - return mMaxMillis; - } - - /** - * Get the minimum buffer millis - * - * @return minimum buffer millis - * @hide - */ - @SystemApi - public int getMinMillis() { - return mMinMillis; - } -} diff --git a/core/java/android/bluetooth/BufferConstraints.java b/core/java/android/bluetooth/BufferConstraints.java deleted file mode 100644 index 97d97232b7a682c34dab5ebca8116a17a30df1d0..0000000000000000000000000000000000000000 --- a/core/java/android/bluetooth/BufferConstraints.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright (C) 2020 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.bluetooth; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.annotation.SystemApi; -import android.os.Parcel; -import android.os.Parcelable; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - - -/** - * A parcelable collection of buffer constraints by codec type. - * - * {@hide} - */ -@SystemApi -public final class BufferConstraints implements Parcelable { - public static final int BUFFER_CODEC_MAX_NUM = 32; - - private static final String TAG = "BufferConstraints"; - - private Map mBufferConstraints; - private List mBufferConstraintList; - - public BufferConstraints(@NonNull List - bufferConstraintList) { - - mBufferConstraintList = new ArrayList(bufferConstraintList); - mBufferConstraints = new HashMap(); - for (int i = 0; i < BUFFER_CODEC_MAX_NUM; i++) { - mBufferConstraints.put(i, bufferConstraintList.get(i)); - } - } - - BufferConstraints(Parcel in) { - mBufferConstraintList = new ArrayList(); - mBufferConstraints = new HashMap(); - in.readList(mBufferConstraintList, BufferConstraint.class.getClassLoader()); - for (int i = 0; i < mBufferConstraintList.size(); i++) { - mBufferConstraints.put(i, mBufferConstraintList.get(i)); - } - } - - public static final @NonNull Parcelable.Creator CREATOR = - new Parcelable.Creator() { - public BufferConstraints createFromParcel(Parcel in) { - return new BufferConstraints(in); - } - - public BufferConstraints[] newArray(int size) { - return new BufferConstraints[size]; - } - }; - - @Override - public void writeToParcel(@NonNull Parcel out, int flags) { - out.writeList(mBufferConstraintList); - } - - @Override - public int describeContents() { - return 0; - } - - /** - * Get the buffer constraints by codec type. - * - * @param codec Audio codec - * @return buffer constraints by codec type. - * @hide - */ - @SystemApi - public @Nullable BufferConstraint forCodec(@BluetoothCodecConfig.SourceCodecType int codec) { - return mBufferConstraints.get(codec); - } -} diff --git a/core/java/android/bluetooth/OWNERS b/core/java/android/bluetooth/OWNERS deleted file mode 100644 index 8e9d7b74bf09022d725547d64c0285d397689a12..0000000000000000000000000000000000000000 --- a/core/java/android/bluetooth/OWNERS +++ /dev/null @@ -1,4 +0,0 @@ -# Bug component: 27441 - -sattiraju@google.com -baligh@google.com diff --git a/core/java/android/bluetooth/OobData.java b/core/java/android/bluetooth/OobData.java deleted file mode 100644 index bb0b95649b179536c48220543f74f503acfed0b8..0000000000000000000000000000000000000000 --- a/core/java/android/bluetooth/OobData.java +++ /dev/null @@ -1,958 +0,0 @@ -/** - * Copyright (C) 2016 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.bluetooth; - -import static java.util.Objects.requireNonNull; - -import android.annotation.IntDef; -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.annotation.SystemApi; -import android.os.Parcel; -import android.os.Parcelable; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -/** - * Out Of Band Data for Bluetooth device pairing. - * - *

    This object represents optional data obtained from a remote device through - * an out-of-band channel (eg. NFC, QR). - * - *

    References: - * NFC AD Forum SSP 1.1 (AD) - * {@link https://members.nfc-forum.org//apps/group_public/download.php/24620/NFCForum-AD-BTSSP_1_1.pdf} - * Core Specification Supplement (CSS) V9 - * - *

    There are several BR/EDR Examples - * - *

    Negotiated Handover: - * Bluetooth Carrier Configuration Record: - * - OOB Data Length - * - Device Address - * - Class of Device - * - Simple Pairing Hash C - * - Simple Pairing Randomizer R - * - Service Class UUID - * - Bluetooth Local Name - * - *

    Static Handover: - * Bluetooth Carrier Configuration Record: - * - OOB Data Length - * - Device Address - * - Class of Device - * - Service Class UUID - * - Bluetooth Local Name - * - *

    Simplified Tag Format for Single BT Carrier: - * Bluetooth OOB Data Record: - * - OOB Data Length - * - Device Address - * - Class of Device - * - Service Class UUID - * - Bluetooth Local Name - * - * @hide - */ -@SystemApi -public final class OobData implements Parcelable { - - private static final String TAG = "OobData"; - /** The {@link OobData#mClassicLength} may be. (AD 3.1.1) (CSS 1.6.2) @hide */ - @SystemApi - public static final int OOB_LENGTH_OCTETS = 2; - /** - * The length for the {@link OobData#mDeviceAddressWithType}(6) and Address Type(1). - * (AD 3.1.2) (CSS 1.6.2) - * @hide - */ - @SystemApi - public static final int DEVICE_ADDRESS_OCTETS = 7; - /** The Class of Device is 3 octets. (AD 3.1.3) (CSS 1.6.2) @hide */ - @SystemApi - public static final int CLASS_OF_DEVICE_OCTETS = 3; - /** The Confirmation data must be 16 octets. (AD 3.2.2) (CSS 1.6.2) @hide */ - @SystemApi - public static final int CONFIRMATION_OCTETS = 16; - /** The Randomizer data must be 16 octets. (AD 3.2.3) (CSS 1.6.2) @hide */ - @SystemApi - public static final int RANDOMIZER_OCTETS = 16; - /** The LE Device Role length is 1 octet. (AD 3.3.2) (CSS 1.17) @hide */ - @SystemApi - public static final int LE_DEVICE_ROLE_OCTETS = 1; - /** The {@link OobData#mLeTemporaryKey} length. (3.4.1) @hide */ - @SystemApi - public static final int LE_TK_OCTETS = 16; - /** The {@link OobData#mLeAppearance} length. (3.4.1) @hide */ - @SystemApi - public static final int LE_APPEARANCE_OCTETS = 2; - /** The {@link OobData#mLeFlags} length. (3.4.1) @hide */ - @SystemApi - public static final int LE_DEVICE_FLAG_OCTETS = 1; // 1 octet to hold the 0-4 value. - - // Le Roles - /** @hide */ - @Retention(RetentionPolicy.SOURCE) - @IntDef( - prefix = { "LE_DEVICE_ROLE_" }, - value = { - LE_DEVICE_ROLE_PERIPHERAL_ONLY, - LE_DEVICE_ROLE_CENTRAL_ONLY, - LE_DEVICE_ROLE_BOTH_PREFER_PERIPHERAL, - LE_DEVICE_ROLE_BOTH_PREFER_CENTRAL - } - ) - public @interface LeRole {} - - /** @hide */ - @SystemApi - public static final int LE_DEVICE_ROLE_PERIPHERAL_ONLY = 0x00; - /** @hide */ - @SystemApi - public static final int LE_DEVICE_ROLE_CENTRAL_ONLY = 0x01; - /** @hide */ - @SystemApi - public static final int LE_DEVICE_ROLE_BOTH_PREFER_PERIPHERAL = 0x02; - /** @hide */ - @SystemApi - public static final int LE_DEVICE_ROLE_BOTH_PREFER_CENTRAL = 0x03; - - // Le Flags - /** @hide */ - @Retention(RetentionPolicy.SOURCE) - @IntDef( - prefix = { "LE_FLAG_" }, - value = { - LE_FLAG_LIMITED_DISCOVERY_MODE, - LE_FLAG_GENERAL_DISCOVERY_MODE, - LE_FLAG_BREDR_NOT_SUPPORTED, - LE_FLAG_SIMULTANEOUS_CONTROLLER, - LE_FLAG_SIMULTANEOUS_HOST - } - ) - public @interface LeFlag {} - - /** @hide */ - @SystemApi - public static final int LE_FLAG_LIMITED_DISCOVERY_MODE = 0x00; - /** @hide */ - @SystemApi - public static final int LE_FLAG_GENERAL_DISCOVERY_MODE = 0x01; - /** @hide */ - @SystemApi - public static final int LE_FLAG_BREDR_NOT_SUPPORTED = 0x02; - /** @hide */ - @SystemApi - public static final int LE_FLAG_SIMULTANEOUS_CONTROLLER = 0x03; - /** @hide */ - @SystemApi - public static final int LE_FLAG_SIMULTANEOUS_HOST = 0x04; - - /** - * Builds an {@link OobData} object and validates that the required combination - * of values are present to create the LE specific OobData type. - * - * @hide - */ - @SystemApi - public static final class LeBuilder { - - /** - * It is recommended that this Hash C is generated anew for each - * pairing. - * - *

    It should be noted that on passive NFC this isn't possible as the data is static - * and immutable. - */ - private byte[] mConfirmationHash = null; - - /** - * Optional, but adds more validity to the pairing. - * - *

    If not present a value of 0 is assumed. - */ - private byte[] mRandomizerHash = new byte[] { - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - }; - - /** - * The Bluetooth Device user-friendly name presented over Bluetooth Technology. - * - *

    This is the name that may be displayed to the device user as part of the UI. - */ - private byte[] mDeviceName = null; - - /** - * Sets the Bluetooth Device name to be used for UI purposes. - * - *

    Optional attribute. - * - * @param deviceName byte array representing the name, may be 0 in length, not null. - * - * @return {@link OobData#ClassicBuilder} - * - * @throws NullPointerException if deviceName is null. - * - * @hide - */ - @NonNull - @SystemApi - public LeBuilder setDeviceName(@NonNull byte[] deviceName) { - requireNonNull(deviceName); - this.mDeviceName = deviceName; - return this; - } - - /** - * The Bluetooth Device Address is the address to which the OOB data belongs. - * - *

    The length MUST be {@link OobData#DEVICE_ADDRESS_OCTETS} octets. - * - *

    Address is encoded in Little Endian order. - * - *

    e.g. 00:01:02:03:04:05 would be x05x04x03x02x01x00 - */ - private final byte[] mDeviceAddressWithType; - - /** - * During an LE connection establishment, one must be in the Peripheral mode and the other - * in the Central role. - * - *

    Possible Values: - * {@link LE_DEVICE_ROLE_PERIPHERAL_ONLY} Only Peripheral supported - * {@link LE_DEVICE_ROLE_CENTRAL_ONLY} Only Central supported - * {@link LE_DEVICE_ROLE_BOTH_PREFER_PERIPHERAL} Central & Peripheral supported; - * Peripheral Preferred - * {@link LE_DEVICE_ROLE_BOTH_PREFER_CENTRAL} Only peripheral supported; Central Preferred - * 0x04 - 0xFF Reserved - */ - private final @LeRole int mLeDeviceRole; - - /** - * Temporary key value from the Security Manager. - * - *

    Must be {@link LE_TK_OCTETS} in size - */ - private byte[] mLeTemporaryKey = null; - - /** - * Defines the representation of the external appearance of the device. - * - *

    For example, a mouse, remote control, or keyboard. - * - *

    Used for visual on discovering device to represent icon/string/etc... - */ - private byte[] mLeAppearance = null; - - /** - * Contains which discoverable mode to use, BR/EDR support and capability. - * - *

    Possible LE Flags: - * {@link LE_FLAG_LIMITED_DISCOVERY_MODE} LE Limited Discoverable Mode. - * {@link LE_FLAG_GENERAL_DISCOVERY_MODE} LE General Discoverable Mode. - * {@link LE_FLAG_BREDR_NOT_SUPPORTED} BR/EDR Not Supported. Bit 37 of - * LMP Feature Mask Definitions. - * {@link LE_FLAG_SIMULTANEOUS_CONTROLLER} Simultaneous LE and BR/EDR to - * Same Device Capable (Controller). - * Bit 49 of LMP Feature Mask Definitions. - * {@link LE_FLAG_SIMULTANEOUS_HOST} Simultaneous LE and BR/EDR to - * Same Device Capable (Host). - * Bit 55 of LMP Feature Mask Definitions. - * 0x05- 0x07 Reserved - */ - private @LeFlag int mLeFlags = LE_FLAG_GENERAL_DISCOVERY_MODE; // Invalid default - - /** - * Main creation method for creating a LE version of {@link OobData}. - * - *

    This object will allow the caller to call {@link LeBuilder#build()} - * to build the data object or add any option information to the builder. - * - * @param deviceAddressWithType the LE device address plus the address type (7 octets); - * not null. - * @param leDeviceRole whether the device supports Peripheral, Central, - * Both including preference; not null. (1 octet) - * @param confirmationHash Array consisting of {@link OobData#CONFIRMATION_OCTETS} octets - * of data. Data is derived from controller/host stack and is - * required for pairing OOB. - * - *

    Possible Values: - * {@link LE_DEVICE_ROLE_PERIPHERAL_ONLY} Only Peripheral supported - * {@link LE_DEVICE_ROLE_CENTRAL_ONLY} Only Central supported - * {@link LE_DEVICE_ROLE_BOTH_PREFER_PERIPHERAL} Central & Peripheral supported; - * Peripheral Preferred - * {@link LE_DEVICE_ROLE_BOTH_PREFER_CENTRAL} Only peripheral supported; Central Preferred - * 0x04 - 0xFF Reserved - * - * @throws IllegalArgumentException if any of the values fail to be set. - * @throws NullPointerException if any argument is null. - * - * @hide - */ - @SystemApi - public LeBuilder(@NonNull byte[] confirmationHash, @NonNull byte[] deviceAddressWithType, - @LeRole int leDeviceRole) { - requireNonNull(confirmationHash); - requireNonNull(deviceAddressWithType); - if (confirmationHash.length != OobData.CONFIRMATION_OCTETS) { - throw new IllegalArgumentException("confirmationHash must be " - + OobData.CONFIRMATION_OCTETS + " octets in length."); - } - this.mConfirmationHash = confirmationHash; - if (deviceAddressWithType.length != OobData.DEVICE_ADDRESS_OCTETS) { - throw new IllegalArgumentException("confirmationHash must be " - + OobData.DEVICE_ADDRESS_OCTETS+ " octets in length."); - } - this.mDeviceAddressWithType = deviceAddressWithType; - if (leDeviceRole < LE_DEVICE_ROLE_PERIPHERAL_ONLY - || leDeviceRole > LE_DEVICE_ROLE_BOTH_PREFER_CENTRAL) { - throw new IllegalArgumentException("leDeviceRole must be a valid value."); - } - this.mLeDeviceRole = leDeviceRole; - } - - /** - * Sets the Temporary Key value to be used by the LE Security Manager during - * LE pairing. - * - * @param leTemporaryKey byte array that shall be 16 bytes. Please see Bluetooth CSSv6, - * Part A 1.8 for a detailed description. - * - * @return {@link OobData#Builder} - * - * @throws IllegalArgumentException if the leTemporaryKey is an invalid format. - * @throws NullinterException if leTemporaryKey is null. - * - * @hide - */ - @NonNull - @SystemApi - public LeBuilder setLeTemporaryKey(@NonNull byte[] leTemporaryKey) { - requireNonNull(leTemporaryKey); - if (leTemporaryKey.length != LE_TK_OCTETS) { - throw new IllegalArgumentException("leTemporaryKey must be " - + LE_TK_OCTETS + " octets in length."); - } - this.mLeTemporaryKey = leTemporaryKey; - return this; - } - - /** - * @param randomizerHash byte array consisting of {@link OobData#RANDOMIZER_OCTETS} octets - * of data. Data is derived from controller/host stack and is required for pairing OOB. - * Also, randomizerHash may be all 0s or null in which case it becomes all 0s. - * - * @throws IllegalArgumentException if null or incorrect length randomizerHash was passed. - * @throws NullPointerException if randomizerHash is null. - * - * @hide - */ - @NonNull - @SystemApi - public LeBuilder setRandomizerHash(@NonNull byte[] randomizerHash) { - requireNonNull(randomizerHash); - if (randomizerHash.length != OobData.RANDOMIZER_OCTETS) { - throw new IllegalArgumentException("randomizerHash must be " - + OobData.RANDOMIZER_OCTETS + " octets in length."); - } - this.mRandomizerHash = randomizerHash; - return this; - } - - /** - * Sets the LE Flags necessary for the pairing scenario or discovery mode. - * - * @param leFlags enum value representing the 1 octet of data about discovery modes. - * - *

    Possible LE Flags: - * {@link LE_FLAG_LIMITED_DISCOVERY_MODE} LE Limited Discoverable Mode. - * {@link LE_FLAG_GENERAL_DISCOVERY_MODE} LE General Discoverable Mode. - * {@link LE_FLAG_BREDR_NOT_SUPPORTED} BR/EDR Not Supported. Bit 37 of - * LMP Feature Mask Definitions. - * {@link LE_FLAG_SIMULTANEOUS_CONTROLLER} Simultaneous LE and BR/EDR to - * Same Device Capable (Controller) Bit 49 of LMP Feature Mask Definitions. - * {@link LE_FLAG_SIMULTANEOUS_HOST} Simultaneous LE and BR/EDR to - * Same Device Capable (Host). - * Bit 55 of LMP Feature Mask Definitions. - * 0x05- 0x07 Reserved - * - * @throws IllegalArgumentException for invalid flag - * @hide - */ - @NonNull - @SystemApi - public LeBuilder setLeFlags(@LeFlag int leFlags) { - if (leFlags < LE_FLAG_LIMITED_DISCOVERY_MODE || leFlags > LE_FLAG_SIMULTANEOUS_HOST) { - throw new IllegalArgumentException("leFlags must be a valid value."); - } - this.mLeFlags = leFlags; - return this; - } - - /** - * Validates and builds the {@link OobData} object for LE Security. - * - * @return {@link OobData} with given builder values - * - * @throws IllegalStateException if either of the 2 required fields were not set. - * - * @hide - */ - @NonNull - @SystemApi - public OobData build() { - final OobData oob = - new OobData(this.mDeviceAddressWithType, this.mLeDeviceRole, - this.mConfirmationHash); - - // If we have values, set them, otherwise use default - oob.mLeTemporaryKey = - (this.mLeTemporaryKey != null) ? this.mLeTemporaryKey : oob.mLeTemporaryKey; - oob.mLeAppearance = (this.mLeAppearance != null) - ? this.mLeAppearance : oob.mLeAppearance; - oob.mLeFlags = (this.mLeFlags != 0xF) ? this.mLeFlags : oob.mLeFlags; - oob.mDeviceName = (this.mDeviceName != null) ? this.mDeviceName : oob.mDeviceName; - oob.mRandomizerHash = this.mRandomizerHash; - return oob; - } - } - - /** - * Builds an {@link OobData} object and validates that the required combination - * of values are present to create the Classic specific OobData type. - * - * @hide - */ - @SystemApi - public static final class ClassicBuilder { - // Used by both Classic and LE - /** - * It is recommended that this Hash C is generated anew for each - * pairing. - * - *

    It should be noted that on passive NFC this isn't possible as the data is static - * and immutable. - * - * @hide - */ - private byte[] mConfirmationHash = null; - - /** - * Optional, but adds more validity to the pairing. - * - *

    If not present a value of 0 is assumed. - * - * @hide - */ - private byte[] mRandomizerHash = new byte[] { - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - }; - - /** - * The Bluetooth Device user-friendly name presented over Bluetooth Technology. - * - *

    This is the name that may be displayed to the device user as part of the UI. - * - * @hide - */ - private byte[] mDeviceName = null; - - /** - * This length value provides the absolute length of total OOB data block used for - * Bluetooth BR/EDR - * - *

    OOB communication, which includes the length field itself and the Bluetooth - * Device Address. - * - *

    The minimum length that may be represented in this field is 8. - * - * @hide - */ - private final byte[] mClassicLength; - - /** - * The Bluetooth Device Address is the address to which the OOB data belongs. - * - *

    The length MUST be {@link OobData#DEVICE_ADDRESS_OCTETS} octets. - * - *

    Address is encoded in Little Endian order. - * - *

    e.g. 00:01:02:03:04:05 would be x05x04x03x02x01x00 - * - * @hide - */ - private final byte[] mDeviceAddressWithType; - - /** - * Class of Device information is to be used to provide a graphical representation - * to the user as part of UI involving operations. - * - *

    This is not to be used to determine a particular service can be used. - * - *

    The length MUST be {@link OobData#CLASS_OF_DEVICE_OCTETS} octets. - * - * @hide - */ - private byte[] mClassOfDevice = null; - - /** - * Main creation method for creating a Classic version of {@link OobData}. - * - *

    This object will allow the caller to call {@link ClassicBuilder#build()} - * to build the data object or add any option information to the builder. - * - * @param confirmationHash byte array consisting of {@link OobData#CONFIRMATION_OCTETS} - * octets of data. Data is derived from controller/host stack and is required for pairing - * OOB. - * @param classicLength byte array representing the length of data from 8-65535 across 2 - * octets (0xXXXX). - * @param deviceAddressWithType byte array representing the Bluetooth Address of the device - * that owns the OOB data. (i.e. the originator) [6 octets] - * - * @throws IllegalArgumentException if any of the values fail to be set. - * @throws NullPointerException if any argument is null. - * - * @hide - */ - @SystemApi - public ClassicBuilder(@NonNull byte[] confirmationHash, @NonNull byte[] classicLength, - @NonNull byte[] deviceAddressWithType) { - requireNonNull(confirmationHash); - requireNonNull(classicLength); - requireNonNull(deviceAddressWithType); - if (confirmationHash.length != OobData.CONFIRMATION_OCTETS) { - throw new IllegalArgumentException("confirmationHash must be " - + OobData.CONFIRMATION_OCTETS + " octets in length."); - } - this.mConfirmationHash = confirmationHash; - if (classicLength.length != OOB_LENGTH_OCTETS) { - throw new IllegalArgumentException("classicLength must be " - + OOB_LENGTH_OCTETS + " octets in length."); - } - this.mClassicLength = classicLength; - if (deviceAddressWithType.length != DEVICE_ADDRESS_OCTETS) { - throw new IllegalArgumentException("deviceAddressWithType must be " - + DEVICE_ADDRESS_OCTETS + " octets in length."); - } - this.mDeviceAddressWithType = deviceAddressWithType; - } - - /** - * @param randomizerHash byte array consisting of {@link OobData#RANDOMIZER_OCTETS} octets - * of data. Data is derived from controller/host stack and is required for pairing OOB. - * Also, randomizerHash may be all 0s or null in which case it becomes all 0s. - * - * @throws IllegalArgumentException if null or incorrect length randomizerHash was passed. - * @throws NullPointerException if randomizerHash is null. - * - * @hide - */ - @NonNull - @SystemApi - public ClassicBuilder setRandomizerHash(@NonNull byte[] randomizerHash) { - requireNonNull(randomizerHash); - if (randomizerHash.length != OobData.RANDOMIZER_OCTETS) { - throw new IllegalArgumentException("randomizerHash must be " - + OobData.RANDOMIZER_OCTETS + " octets in length."); - } - this.mRandomizerHash = randomizerHash; - return this; - } - - /** - * Sets the Bluetooth Device name to be used for UI purposes. - * - *

    Optional attribute. - * - * @param deviceName byte array representing the name, may be 0 in length, not null. - * - * @return {@link OobData#ClassicBuilder} - * - * @throws NullPointerException if deviceName is null - * - * @hide - */ - @NonNull - @SystemApi - public ClassicBuilder setDeviceName(@NonNull byte[] deviceName) { - requireNonNull(deviceName); - this.mDeviceName = deviceName; - return this; - } - - /** - * Sets the Bluetooth Class of Device; used for UI purposes only. - * - *

    Not an indicator of available services! - * - *

    Optional attribute. - * - * @param classOfDevice byte array of {@link OobData#CLASS_OF_DEVICE_OCTETS} octets. - * - * @return {@link OobData#ClassicBuilder} - * - * @throws IllegalArgumentException if length is not equal to - * {@link OobData#CLASS_OF_DEVICE_OCTETS} octets. - * @throws NullPointerException if classOfDevice is null. - * - * @hide - */ - @NonNull - @SystemApi - public ClassicBuilder setClassOfDevice(@NonNull byte[] classOfDevice) { - requireNonNull(classOfDevice); - if (classOfDevice.length != OobData.CLASS_OF_DEVICE_OCTETS) { - throw new IllegalArgumentException("classOfDevice must be " - + OobData.CLASS_OF_DEVICE_OCTETS + " octets in length."); - } - this.mClassOfDevice = classOfDevice; - return this; - } - - /** - * Validates and builds the {@link OobDat object for Classic Security. - * - * @return {@link OobData} with previously given builder values. - * - * @hide - */ - @NonNull - @SystemApi - public OobData build() { - final OobData oob = - new OobData(this.mClassicLength, this.mDeviceAddressWithType, - this.mConfirmationHash); - // If we have values, set them, otherwise use default - oob.mDeviceName = (this.mDeviceName != null) ? this.mDeviceName : oob.mDeviceName; - oob.mClassOfDevice = (this.mClassOfDevice != null) - ? this.mClassOfDevice : oob.mClassOfDevice; - oob.mRandomizerHash = this.mRandomizerHash; - return oob; - } - } - - // Members (Defaults for Optionals must be set or Parceling fails on NPE) - // Both - private final byte[] mDeviceAddressWithType; - private final byte[] mConfirmationHash; - private byte[] mRandomizerHash = new byte[] { - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - }; - // Default the name to "Bluetooth Device" - private byte[] mDeviceName = new byte[] { - // Bluetooth - 0x42, 0x6c, 0x75, 0x65, 0x74, 0x6f, 0x6f, 0x74, 0x68, - // Device - 0x20, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65 - }; - - // Classic - private final byte[] mClassicLength; - private byte[] mClassOfDevice = new byte[CLASS_OF_DEVICE_OCTETS]; - - // LE - private final @LeRole int mLeDeviceRole; - private byte[] mLeTemporaryKey = new byte[LE_TK_OCTETS]; - private byte[] mLeAppearance = new byte[LE_APPEARANCE_OCTETS]; - private @LeFlag int mLeFlags = LE_FLAG_LIMITED_DISCOVERY_MODE; - - /** - * @return byte array representing the MAC address of a bluetooth device. - * The Address is 6 octets long with a 1 octet address type associated with the address. - * - *

    For classic this will be 6 byte address plus the default of PUBLIC_ADDRESS Address Type. - * For LE there are more choices for Address Type. - * - * @hide - */ - @NonNull - @SystemApi - public byte[] getDeviceAddressWithType() { - return mDeviceAddressWithType; - } - - /** - * @return byte array representing the confirmationHash value - * which is used to confirm the identity to the controller. - * - * @hide - */ - @NonNull - @SystemApi - public byte[] getConfirmationHash() { - return mConfirmationHash; - } - - /** - * @return byte array representing the randomizerHash value - * which is used to verify the identity of the controller. - * - * @hide - */ - @NonNull - @SystemApi - public byte[] getRandomizerHash() { - return mRandomizerHash; - } - - /** - * @return Device Name used for displaying name in UI. - * - *

    Also, this will be populated with the LE Local Name if the data is for LE. - * - * @hide - */ - @Nullable - @SystemApi - public byte[] getDeviceName() { - return mDeviceName; - } - - /** - * @return byte array representing the oob data length which is the length - * of all of the data including these octets. - * - * @hide - */ - @NonNull - @SystemApi - public byte[] getClassicLength() { - return mClassicLength; - } - - /** - * @return byte array representing the class of device for UI display. - * - *

    Does not indicate services available; for display only. - * - * @hide - */ - @NonNull - @SystemApi - public byte[] getClassOfDevice() { - return mClassOfDevice; - } - - /** - * @return Temporary Key used for LE pairing. - * - * @hide - */ - @Nullable - @SystemApi - public byte[] getLeTemporaryKey() { - return mLeTemporaryKey; - } - - /** - * @return Appearance used for LE pairing. For use in UI situations - * when determining what sort of icons or text to display regarding - * the device. - * - * @hide - */ - @Nullable - @SystemApi - public byte[] getLeAppearance() { - return mLeAppearance; - } - - /** - * @return Flags used to determing discoverable mode to use, BR/EDR Support, and Capability. - * - *

    Possible LE Flags: - * {@link LE_FLAG_LIMITED_DISCOVERY_MODE} LE Limited Discoverable Mode. - * {@link LE_FLAG_GENERAL_DISCOVERY_MODE} LE General Discoverable Mode. - * {@link LE_FLAG_BREDR_NOT_SUPPORTED} BR/EDR Not Supported. Bit 37 of - * LMP Feature Mask Definitions. - * {@link LE_FLAG_SIMULTANEOUS_CONTROLLER} Simultaneous LE and BR/EDR to - * Same Device Capable (Controller). - * Bit 49 of LMP Feature Mask Definitions. - * {@link LE_FLAG_SIMULTANEOUS_HOST} Simultaneous LE and BR/EDR to - * Same Device Capable (Host). - * Bit 55 of LMP Feature Mask Definitions. - * 0x05- 0x07 Reserved - * - * @hide - */ - @NonNull - @SystemApi - @LeFlag - public int getLeFlags() { - return mLeFlags; - } - - /** - * @return the supported and preferred roles of the LE device. - * - *

    Possible Values: - * {@link LE_DEVICE_ROLE_PERIPHERAL_ONLY} Only Peripheral supported - * {@link LE_DEVICE_ROLE_CENTRAL_ONLY} Only Central supported - * {@link LE_DEVICE_ROLE_BOTH_PREFER_PERIPHERAL} Central & Peripheral supported; - * Peripheral Preferred - * {@link LE_DEVICE_ROLE_BOTH_PREFER_CENTRAL} Only peripheral supported; Central Preferred - * 0x04 - 0xFF Reserved - * - * @hide - */ - @NonNull - @SystemApi - @LeRole - public int getLeDeviceRole() { - return mLeDeviceRole; - } - - /** - * Classic Security Constructor - */ - private OobData(@NonNull byte[] classicLength, @NonNull byte[] deviceAddressWithType, - @NonNull byte[] confirmationHash) { - mClassicLength = classicLength; - mDeviceAddressWithType = deviceAddressWithType; - mConfirmationHash = confirmationHash; - mLeDeviceRole = -1; // Satisfy final - } - - /** - * LE Security Constructor - */ - private OobData(@NonNull byte[] deviceAddressWithType, @LeRole int leDeviceRole, - @NonNull byte[] confirmationHash) { - mDeviceAddressWithType = deviceAddressWithType; - mLeDeviceRole = leDeviceRole; - mConfirmationHash = confirmationHash; - mClassicLength = new byte[OOB_LENGTH_OCTETS]; // Satisfy final - } - - private OobData(Parcel in) { - // Both - mDeviceAddressWithType = in.createByteArray(); - mConfirmationHash = in.createByteArray(); - mRandomizerHash = in.createByteArray(); - mDeviceName = in.createByteArray(); - - // Classic - mClassicLength = in.createByteArray(); - mClassOfDevice = in.createByteArray(); - - // LE - mLeDeviceRole = in.readInt(); - mLeTemporaryKey = in.createByteArray(); - mLeAppearance = in.createByteArray(); - mLeFlags = in.readInt(); - } - - /** - * @hide - */ - @Override - public int describeContents() { - return 0; - } - - /** - * @hide - */ - @Override - public void writeToParcel(@NonNull Parcel out, int flags) { - // Both - // Required - out.writeByteArray(mDeviceAddressWithType); - // Required - out.writeByteArray(mConfirmationHash); - // Optional - out.writeByteArray(mRandomizerHash); - // Optional - out.writeByteArray(mDeviceName); - - // Classic - // Required - out.writeByteArray(mClassicLength); - // Optional - out.writeByteArray(mClassOfDevice); - - // LE - // Required - out.writeInt(mLeDeviceRole); - // Required - out.writeByteArray(mLeTemporaryKey); - // Optional - out.writeByteArray(mLeAppearance); - // Optional - out.writeInt(mLeFlags); - } - - // For Parcelable - public static final @android.annotation.NonNull Parcelable.Creator CREATOR = - new Parcelable.Creator() { - public OobData createFromParcel(Parcel in) { - return new OobData(in); - } - - public OobData[] newArray(int size) { - return new OobData[size]; - } - }; - - /** - * @return a {@link String} representation of the OobData object. - * - * @hide - */ - @Override - @NonNull - public String toString() { - return "OobData: \n\t" - // Both - + "Device Address With Type: " + toHexString(mDeviceAddressWithType) + "\n\t" - + "Confirmation: " + toHexString(mConfirmationHash) + "\n\t" - + "Randomizer: " + toHexString(mRandomizerHash) + "\n\t" - + "Device Name: " + toHexString(mDeviceName) + "\n\t" - // Classic - + "OobData Length: " + toHexString(mClassicLength) + "\n\t" - + "Class of Device: " + toHexString(mClassOfDevice) + "\n\t" - // LE - + "LE Device Role: " + toHexString(mLeDeviceRole) + "\n\t" - + "LE Temporary Key: " + toHexString(mLeTemporaryKey) + "\n\t" - + "LE Appearance: " + toHexString(mLeAppearance) + "\n\t" - + "LE Flags: " + toHexString(mLeFlags) + "\n\t"; - } - - @NonNull - private String toHexString(int b) { - return toHexString(new byte[] {(byte) b}); - } - - @NonNull - private String toHexString(byte b) { - return toHexString(new byte[] {b}); - } - - @NonNull - private String toHexString(byte[] array) { - if (array == null) return "null"; - StringBuilder builder = new StringBuilder(array.length * 2); - for (byte b: array) { - builder.append(String.format("%02x", b)); - } - return builder.toString(); - } -} diff --git a/core/java/android/bluetooth/SdpDipRecord.java b/core/java/android/bluetooth/SdpDipRecord.java deleted file mode 100644 index 84b0eef0593ea0a54a2a0d5575bb0d158922e8e8..0000000000000000000000000000000000000000 --- a/core/java/android/bluetooth/SdpDipRecord.java +++ /dev/null @@ -1,104 +0,0 @@ -/* -* Copyright (C) 2015 Samsung System LSI -* 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.bluetooth; - -import java.util.Arrays; - -import android.os.Parcel; -import android.os.Parcelable; - -/** - * Data representation of a Object Push Profile Server side SDP record. - */ -/** @hide */ -public class SdpDipRecord implements Parcelable { - private final int mSpecificationId; - private final int mVendorId; - private final int mVendorIdSource; - private final int mProductId; - private final int mVersion; - private final boolean mPrimaryRecord; - - public SdpDipRecord(int specificationId, - int vendorId, int vendorIdSource, - int productId, int version, - boolean primaryRecord) { - super(); - this.mSpecificationId = specificationId; - this.mVendorId = vendorId; - this.mVendorIdSource = vendorIdSource; - this.mProductId = productId; - this.mVersion = version; - this.mPrimaryRecord = primaryRecord; - } - - public SdpDipRecord(Parcel in) { - this.mSpecificationId = in.readInt(); - this.mVendorId = in.readInt(); - this.mVendorIdSource = in.readInt(); - this.mProductId = in.readInt(); - this.mVersion = in.readInt(); - this.mPrimaryRecord = in.readBoolean(); - } - - public int getSpecificationId() { - return mSpecificationId; - } - - public int getVendorId() { - return mVendorId; - } - - public int getVendorIdSource() { - return mVendorIdSource; - } - - public int getProductId() { - return mProductId; - } - - public int getVersion() { - return mVersion; - } - - public boolean getPrimaryRecord() { - return mPrimaryRecord; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeInt(mSpecificationId); - dest.writeInt(mVendorId); - dest.writeInt(mVendorIdSource); - dest.writeInt(mProductId); - dest.writeInt(mVersion); - dest.writeBoolean(mPrimaryRecord); - } - - @Override - public int describeContents() { - /* No special objects */ - return 0; - } - - public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { - public SdpDipRecord createFromParcel(Parcel in) { - return new SdpDipRecord(in); - } - public SdpDipRecord[] newArray(int size) { - return new SdpDipRecord[size]; - } - }; -} diff --git a/core/java/android/bluetooth/SdpMasRecord.java b/core/java/android/bluetooth/SdpMasRecord.java deleted file mode 100644 index 72d49380b713aa2472ce830f5712d7946db0fd94..0000000000000000000000000000000000000000 --- a/core/java/android/bluetooth/SdpMasRecord.java +++ /dev/null @@ -1,150 +0,0 @@ -/* -* Copyright (C) 2015 Samsung System LSI -* 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.bluetooth; - -import android.os.Parcel; -import android.os.Parcelable; - -/** @hide */ -public class SdpMasRecord implements Parcelable { - private final int mMasInstanceId; - private final int mL2capPsm; - private final int mRfcommChannelNumber; - private final int mProfileVersion; - private final int mSupportedFeatures; - private final int mSupportedMessageTypes; - private final String mServiceName; - - /** Message type */ - public static final class MessageType { - public static final int EMAIL = 0x01; - public static final int SMS_GSM = 0x02; - public static final int SMS_CDMA = 0x04; - public static final int MMS = 0x08; - } - - public SdpMasRecord(int masInstanceId, - int l2capPsm, - int rfcommChannelNumber, - int profileVersion, - int supportedFeatures, - int supportedMessageTypes, - String serviceName) { - mMasInstanceId = masInstanceId; - mL2capPsm = l2capPsm; - mRfcommChannelNumber = rfcommChannelNumber; - mProfileVersion = profileVersion; - mSupportedFeatures = supportedFeatures; - mSupportedMessageTypes = supportedMessageTypes; - mServiceName = serviceName; - } - - public SdpMasRecord(Parcel in) { - mMasInstanceId = in.readInt(); - mL2capPsm = in.readInt(); - mRfcommChannelNumber = in.readInt(); - mProfileVersion = in.readInt(); - mSupportedFeatures = in.readInt(); - mSupportedMessageTypes = in.readInt(); - mServiceName = in.readString(); - } - - @Override - public int describeContents() { - // TODO Auto-generated method stub - return 0; - } - - public int getMasInstanceId() { - return mMasInstanceId; - } - - public int getL2capPsm() { - return mL2capPsm; - } - - public int getRfcommCannelNumber() { - return mRfcommChannelNumber; - } - - public int getProfileVersion() { - return mProfileVersion; - } - - public int getSupportedFeatures() { - return mSupportedFeatures; - } - - public int getSupportedMessageTypes() { - return mSupportedMessageTypes; - } - - public boolean msgSupported(int msg) { - return (mSupportedMessageTypes & msg) != 0; - } - - public String getServiceName() { - return mServiceName; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeInt(mMasInstanceId); - dest.writeInt(mL2capPsm); - dest.writeInt(mRfcommChannelNumber); - dest.writeInt(mProfileVersion); - dest.writeInt(mSupportedFeatures); - dest.writeInt(mSupportedMessageTypes); - dest.writeString(mServiceName); - } - - @Override - public String toString() { - String ret = "Bluetooth MAS SDP Record:\n"; - - if (mMasInstanceId != -1) { - ret += "Mas Instance Id: " + mMasInstanceId + "\n"; - } - if (mRfcommChannelNumber != -1) { - ret += "RFCOMM Chan Number: " + mRfcommChannelNumber + "\n"; - } - if (mL2capPsm != -1) { - ret += "L2CAP PSM: " + mL2capPsm + "\n"; - } - if (mServiceName != null) { - ret += "Service Name: " + mServiceName + "\n"; - } - if (mProfileVersion != -1) { - ret += "Profile version: " + mProfileVersion + "\n"; - } - if (mSupportedMessageTypes != -1) { - ret += "Supported msg types: " + mSupportedMessageTypes + "\n"; - } - if (mSupportedFeatures != -1) { - ret += "Supported features: " + mSupportedFeatures + "\n"; - } - return ret; - } - - public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { - public SdpMasRecord createFromParcel(Parcel in) { - return new SdpMasRecord(in); - } - - public SdpRecord[] newArray(int size) { - return new SdpRecord[size]; - } - }; -} diff --git a/core/java/android/bluetooth/SdpMnsRecord.java b/core/java/android/bluetooth/SdpMnsRecord.java deleted file mode 100644 index a781d5df7dd0f2c798ecda1c4fae008f8921edd4..0000000000000000000000000000000000000000 --- a/core/java/android/bluetooth/SdpMnsRecord.java +++ /dev/null @@ -1,114 +0,0 @@ -/* -* Copyright (C) 2015 Samsung System LSI -* 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.bluetooth; - -import android.os.Parcel; -import android.os.Parcelable; - -/** @hide */ -public class SdpMnsRecord implements Parcelable { - private final int mL2capPsm; - private final int mRfcommChannelNumber; - private final int mSupportedFeatures; - private final int mProfileVersion; - private final String mServiceName; - - public SdpMnsRecord(int l2capPsm, - int rfcommChannelNumber, - int profileVersion, - int supportedFeatures, - String serviceName) { - mL2capPsm = l2capPsm; - mRfcommChannelNumber = rfcommChannelNumber; - mSupportedFeatures = supportedFeatures; - mServiceName = serviceName; - mProfileVersion = profileVersion; - } - - public SdpMnsRecord(Parcel in) { - mRfcommChannelNumber = in.readInt(); - mL2capPsm = in.readInt(); - mServiceName = in.readString(); - mSupportedFeatures = in.readInt(); - mProfileVersion = in.readInt(); - } - - @Override - public int describeContents() { - // TODO Auto-generated method stub - return 0; - } - - - public int getL2capPsm() { - return mL2capPsm; - } - - public int getRfcommChannelNumber() { - return mRfcommChannelNumber; - } - - public int getSupportedFeatures() { - return mSupportedFeatures; - } - - public String getServiceName() { - return mServiceName; - } - - public int getProfileVersion() { - return mProfileVersion; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeInt(mRfcommChannelNumber); - dest.writeInt(mL2capPsm); - dest.writeString(mServiceName); - dest.writeInt(mSupportedFeatures); - dest.writeInt(mProfileVersion); - } - - public String toString() { - String ret = "Bluetooth MNS SDP Record:\n"; - - if (mRfcommChannelNumber != -1) { - ret += "RFCOMM Chan Number: " + mRfcommChannelNumber + "\n"; - } - if (mL2capPsm != -1) { - ret += "L2CAP PSM: " + mL2capPsm + "\n"; - } - if (mServiceName != null) { - ret += "Service Name: " + mServiceName + "\n"; - } - if (mSupportedFeatures != -1) { - ret += "Supported features: " + mSupportedFeatures + "\n"; - } - if (mProfileVersion != -1) { - ret += "Profile_version: " + mProfileVersion + "\n"; - } - return ret; - } - - public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { - public SdpMnsRecord createFromParcel(Parcel in) { - return new SdpMnsRecord(in); - } - - public SdpMnsRecord[] newArray(int size) { - return new SdpMnsRecord[size]; - } - }; -} diff --git a/core/java/android/bluetooth/SdpOppOpsRecord.java b/core/java/android/bluetooth/SdpOppOpsRecord.java deleted file mode 100644 index e30745b898214fe0a79c0a0ed9d976b7a2328274..0000000000000000000000000000000000000000 --- a/core/java/android/bluetooth/SdpOppOpsRecord.java +++ /dev/null @@ -1,121 +0,0 @@ -/* -* Copyright (C) 2015 Samsung System LSI -* 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.bluetooth; - -import android.os.Parcel; -import android.os.Parcelable; - -import java.util.Arrays; - -/** - * Data representation of a Object Push Profile Server side SDP record. - */ - -/** @hide */ -public class SdpOppOpsRecord implements Parcelable { - - private final String mServiceName; - private final int mRfcommChannel; - private final int mL2capPsm; - private final int mProfileVersion; - private final byte[] mFormatsList; - - public SdpOppOpsRecord(String serviceName, int rfcommChannel, - int l2capPsm, int version, byte[] formatsList) { - super(); - mServiceName = serviceName; - mRfcommChannel = rfcommChannel; - mL2capPsm = l2capPsm; - mProfileVersion = version; - mFormatsList = formatsList; - } - - public String getServiceName() { - return mServiceName; - } - - public int getRfcommChannel() { - return mRfcommChannel; - } - - public int getL2capPsm() { - return mL2capPsm; - } - - public int getProfileVersion() { - return mProfileVersion; - } - - public byte[] getFormatsList() { - return mFormatsList; - } - - @Override - public int describeContents() { - /* No special objects */ - return 0; - } - - public SdpOppOpsRecord(Parcel in) { - mRfcommChannel = in.readInt(); - mL2capPsm = in.readInt(); - mProfileVersion = in.readInt(); - mServiceName = in.readString(); - int arrayLength = in.readInt(); - if (arrayLength > 0) { - byte[] bytes = new byte[arrayLength]; - in.readByteArray(bytes); - mFormatsList = bytes; - } else { - mFormatsList = null; - } - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeInt(mRfcommChannel); - dest.writeInt(mL2capPsm); - dest.writeInt(mProfileVersion); - dest.writeString(mServiceName); - if (mFormatsList != null && mFormatsList.length > 0) { - dest.writeInt(mFormatsList.length); - dest.writeByteArray(mFormatsList); - } else { - dest.writeInt(0); - } - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder("Bluetooth OPP Server SDP Record:\n"); - sb.append(" RFCOMM Chan Number: ").append(mRfcommChannel); - sb.append("\n L2CAP PSM: ").append(mL2capPsm); - sb.append("\n Profile version: ").append(mProfileVersion); - sb.append("\n Service Name: ").append(mServiceName); - sb.append("\n Formats List: ").append(Arrays.toString(mFormatsList)); - return sb.toString(); - } - - public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { - public SdpOppOpsRecord createFromParcel(Parcel in) { - return new SdpOppOpsRecord(in); - } - - public SdpOppOpsRecord[] newArray(int size) { - return new SdpOppOpsRecord[size]; - } - }; - -} diff --git a/core/java/android/bluetooth/SdpPseRecord.java b/core/java/android/bluetooth/SdpPseRecord.java deleted file mode 100644 index 72249d0585c63f8fd08774bd9ae4de5f1b288bcd..0000000000000000000000000000000000000000 --- a/core/java/android/bluetooth/SdpPseRecord.java +++ /dev/null @@ -1,129 +0,0 @@ -/* -* Copyright (C) 2015 Samsung System LSI -* 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.bluetooth; - -import android.os.Parcel; -import android.os.Parcelable; - -/** @hide */ -public class SdpPseRecord implements Parcelable { - private final int mL2capPsm; - private final int mRfcommChannelNumber; - private final int mProfileVersion; - private final int mSupportedFeatures; - private final int mSupportedRepositories; - private final String mServiceName; - - public SdpPseRecord(int l2capPsm, - int rfcommChannelNumber, - int profileVersion, - int supportedFeatures, - int supportedRepositories, - String serviceName) { - mL2capPsm = l2capPsm; - mRfcommChannelNumber = rfcommChannelNumber; - mProfileVersion = profileVersion; - mSupportedFeatures = supportedFeatures; - mSupportedRepositories = supportedRepositories; - mServiceName = serviceName; - } - - public SdpPseRecord(Parcel in) { - mRfcommChannelNumber = in.readInt(); - mL2capPsm = in.readInt(); - mProfileVersion = in.readInt(); - mSupportedFeatures = in.readInt(); - mSupportedRepositories = in.readInt(); - mServiceName = in.readString(); - } - - @Override - public int describeContents() { - // TODO Auto-generated method stub - return 0; - } - - public int getL2capPsm() { - return mL2capPsm; - } - - public int getRfcommChannelNumber() { - return mRfcommChannelNumber; - } - - public int getSupportedFeatures() { - return mSupportedFeatures; - } - - public String getServiceName() { - return mServiceName; - } - - public int getProfileVersion() { - return mProfileVersion; - } - - public int getSupportedRepositories() { - return mSupportedRepositories; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeInt(mRfcommChannelNumber); - dest.writeInt(mL2capPsm); - dest.writeInt(mProfileVersion); - dest.writeInt(mSupportedFeatures); - dest.writeInt(mSupportedRepositories); - dest.writeString(mServiceName); - - } - - @Override - public String toString() { - String ret = "Bluetooth MNS SDP Record:\n"; - - if (mRfcommChannelNumber != -1) { - ret += "RFCOMM Chan Number: " + mRfcommChannelNumber + "\n"; - } - if (mL2capPsm != -1) { - ret += "L2CAP PSM: " + mL2capPsm + "\n"; - } - if (mProfileVersion != -1) { - ret += "profile version: " + mProfileVersion + "\n"; - } - if (mServiceName != null) { - ret += "Service Name: " + mServiceName + "\n"; - } - if (mSupportedFeatures != -1) { - ret += "Supported features: " + mSupportedFeatures + "\n"; - } - if (mSupportedRepositories != -1) { - ret += "Supported repositories: " + mSupportedRepositories + "\n"; - } - - return ret; - } - - public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { - public SdpPseRecord createFromParcel(Parcel in) { - return new SdpPseRecord(in); - } - - public SdpPseRecord[] newArray(int size) { - return new SdpPseRecord[size]; - } - }; -} diff --git a/core/java/android/bluetooth/SdpRecord.java b/core/java/android/bluetooth/SdpRecord.java deleted file mode 100644 index 730862ec6f914216a2f87a0ba581386dac1b1a64..0000000000000000000000000000000000000000 --- a/core/java/android/bluetooth/SdpRecord.java +++ /dev/null @@ -1,77 +0,0 @@ -/* -* Copyright (C) 2015 Samsung System LSI -* 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.bluetooth; - -import android.os.Parcel; -import android.os.Parcelable; - -import java.util.Arrays; - -/** @hide */ -public class SdpRecord implements Parcelable { - - private final byte[] mRawData; - private final int mRawSize; - - @Override - public String toString() { - return "BluetoothSdpRecord [rawData=" + Arrays.toString(mRawData) - + ", rawSize=" + mRawSize + "]"; - } - - public SdpRecord(int sizeRecord, byte[] record) { - mRawData = record; - mRawSize = sizeRecord; - } - - public SdpRecord(Parcel in) { - mRawSize = in.readInt(); - mRawData = new byte[mRawSize]; - in.readByteArray(mRawData); - - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeInt(mRawSize); - dest.writeByteArray(mRawData); - - - } - - public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { - public SdpRecord createFromParcel(Parcel in) { - return new SdpRecord(in); - } - - public SdpRecord[] newArray(int size) { - return new SdpRecord[size]; - } - }; - - public byte[] getRawData() { - return mRawData; - } - - public int getRawSize() { - return mRawSize; - } -} diff --git a/core/java/android/bluetooth/SdpSapsRecord.java b/core/java/android/bluetooth/SdpSapsRecord.java deleted file mode 100644 index a1e2f7b51f35646a17f1ebb3e754a6d468e149be..0000000000000000000000000000000000000000 --- a/core/java/android/bluetooth/SdpSapsRecord.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * 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.bluetooth; - -import android.os.Parcel; -import android.os.Parcelable; - -/** @hide */ -public class SdpSapsRecord implements Parcelable { - private final int mRfcommChannelNumber; - private final int mProfileVersion; - private final String mServiceName; - - public SdpSapsRecord(int rfcommChannelNumber, int profileVersion, String serviceName) { - mRfcommChannelNumber = rfcommChannelNumber; - mProfileVersion = profileVersion; - mServiceName = serviceName; - } - - public SdpSapsRecord(Parcel in) { - mRfcommChannelNumber = in.readInt(); - mProfileVersion = in.readInt(); - mServiceName = in.readString(); - } - - @Override - public int describeContents() { - return 0; - } - - public int getRfcommCannelNumber() { - return mRfcommChannelNumber; - } - - public int getProfileVersion() { - return mProfileVersion; - } - - public String getServiceName() { - return mServiceName; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeInt(mRfcommChannelNumber); - dest.writeInt(mProfileVersion); - dest.writeString(mServiceName); - - } - - @Override - public String toString() { - String ret = "Bluetooth MAS SDP Record:\n"; - - if (mRfcommChannelNumber != -1) { - ret += "RFCOMM Chan Number: " + mRfcommChannelNumber + "\n"; - } - if (mServiceName != null) { - ret += "Service Name: " + mServiceName + "\n"; - } - if (mProfileVersion != -1) { - ret += "Profile version: " + mProfileVersion + "\n"; - } - return ret; - } - - public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { - public SdpSapsRecord createFromParcel(Parcel in) { - return new SdpSapsRecord(in); - } - - public SdpRecord[] newArray(int size) { - return new SdpRecord[size]; - } - }; -} diff --git a/core/java/android/bluetooth/UidTraffic.java b/core/java/android/bluetooth/UidTraffic.java deleted file mode 100644 index 9982fa6121e4ab78d80b351b009fd8981cda3dab..0000000000000000000000000000000000000000 --- a/core/java/android/bluetooth/UidTraffic.java +++ /dev/null @@ -1,126 +0,0 @@ -/* - * 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.bluetooth; - -import android.annotation.SystemApi; -import android.os.Parcel; -import android.os.Parcelable; - -/** - * Record of data traffic (in bytes) by an application identified by its UID. - * - * @hide - */ -@SystemApi(client = SystemApi.Client.PRIVILEGED_APPS) -public final class UidTraffic implements Cloneable, Parcelable { - private final int mAppUid; - private long mRxBytes; - private long mTxBytes; - - /** @hide */ - public UidTraffic(int appUid, long rx, long tx) { - mAppUid = appUid; - mRxBytes = rx; - mTxBytes = tx; - } - - /** @hide */ - private UidTraffic(Parcel in) { - mAppUid = in.readInt(); - mRxBytes = in.readLong(); - mTxBytes = in.readLong(); - } - - /** @hide */ - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeInt(mAppUid); - dest.writeLong(mRxBytes); - dest.writeLong(mTxBytes); - } - - /** @hide */ - public void setRxBytes(long bytes) { - mRxBytes = bytes; - } - - /** @hide */ - public void setTxBytes(long bytes) { - mTxBytes = bytes; - } - - /** @hide */ - public void addRxBytes(long bytes) { - mRxBytes += bytes; - } - - /** @hide */ - public void addTxBytes(long bytes) { - mTxBytes += bytes; - } - - /** - * @return corresponding app Uid - */ - public int getUid() { - return mAppUid; - } - - /** - * @return rx bytes count - */ - public long getRxBytes() { - return mRxBytes; - } - - /** - * @return tx bytes count - */ - public long getTxBytes() { - return mTxBytes; - } - - /** @hide */ - @Override - public int describeContents() { - return 0; - } - - /** @hide */ - @Override - public UidTraffic clone() { - return new UidTraffic(mAppUid, mRxBytes, mTxBytes); - } - - /** @hide */ - @Override - public String toString() { - return "UidTraffic{mAppUid=" + mAppUid + ", mRxBytes=" + mRxBytes + ", mTxBytes=" - + mTxBytes + '}'; - } - - public static final @android.annotation.NonNull Creator CREATOR = new Creator() { - @Override - public UidTraffic createFromParcel(Parcel source) { - return new UidTraffic(source); - } - - @Override - public UidTraffic[] newArray(int size) { - return new UidTraffic[size]; - } - }; -} diff --git a/core/java/android/bluetooth/annotations/RequiresBluetoothAdvertisePermission.java b/core/java/android/bluetooth/annotations/RequiresBluetoothAdvertisePermission.java deleted file mode 100644 index c508c2c9ca0b09be3891c5ee7baff99ea47cf292..0000000000000000000000000000000000000000 --- a/core/java/android/bluetooth/annotations/RequiresBluetoothAdvertisePermission.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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.bluetooth.annotations; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -import android.Manifest; -import android.os.Build; - -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -/** - * @memberDoc For apps targeting {@link Build.VERSION_CODES#S} or or higher, - * this requires the {@link Manifest.permission#BLUETOOTH_ADVERTISE} - * permission which can be gained with - * {@link android.app.Activity#requestPermissions(String[], int)}. - * @hide - */ -@Retention(SOURCE) -@Target({METHOD, FIELD}) -public @interface RequiresBluetoothAdvertisePermission { -} diff --git a/core/java/android/bluetooth/annotations/RequiresBluetoothConnectPermission.java b/core/java/android/bluetooth/annotations/RequiresBluetoothConnectPermission.java deleted file mode 100644 index e159eaafe2e48aa6edb0a30dc331a3a9afd0c452..0000000000000000000000000000000000000000 --- a/core/java/android/bluetooth/annotations/RequiresBluetoothConnectPermission.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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.bluetooth.annotations; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -import android.Manifest; -import android.os.Build; - -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -/** - * @memberDoc For apps targeting {@link Build.VERSION_CODES#S} or or higher, - * this requires the {@link Manifest.permission#BLUETOOTH_CONNECT} - * permission which can be gained with - * {@link android.app.Activity#requestPermissions(String[], int)}. - * @hide - */ -@Retention(SOURCE) -@Target({METHOD, FIELD}) -public @interface RequiresBluetoothConnectPermission { -} diff --git a/core/java/android/bluetooth/annotations/RequiresBluetoothLocationPermission.java b/core/java/android/bluetooth/annotations/RequiresBluetoothLocationPermission.java deleted file mode 100644 index 2bb320413941e98f86b56a638c0e6d522b0a1484..0000000000000000000000000000000000000000 --- a/core/java/android/bluetooth/annotations/RequiresBluetoothLocationPermission.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * 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.bluetooth.annotations; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -import android.Manifest; - -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -/** - * @memberDoc In addition, this requires either the - * {@link Manifest.permission#ACCESS_FINE_LOCATION} - * permission or a strong assertion that you will never derive the - * physical location of the device. You can make this assertion by - * declaring {@code usesPermissionFlags="neverForLocation"} on the - * relevant {@code } manifest tag, but it may - * restrict the types of Bluetooth devices you can interact with. - * @hide - */ -@Retention(SOURCE) -@Target({METHOD, FIELD}) -public @interface RequiresBluetoothLocationPermission { -} diff --git a/core/java/android/bluetooth/annotations/RequiresBluetoothScanPermission.java b/core/java/android/bluetooth/annotations/RequiresBluetoothScanPermission.java deleted file mode 100644 index 800ff39933f2ceccdc0f83ff2d4de271f54819f4..0000000000000000000000000000000000000000 --- a/core/java/android/bluetooth/annotations/RequiresBluetoothScanPermission.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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.bluetooth.annotations; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -import android.Manifest; -import android.os.Build; - -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -/** - * @memberDoc For apps targeting {@link Build.VERSION_CODES#S} or or higher, - * this requires the {@link Manifest.permission#BLUETOOTH_SCAN} - * permission which can be gained with - * {@link android.app.Activity#requestPermissions(String[], int)}. - * @hide - */ -@Retention(SOURCE) -@Target({METHOD, FIELD}) -public @interface RequiresBluetoothScanPermission { -} diff --git a/core/java/android/bluetooth/annotations/RequiresLegacyBluetoothAdminPermission.java b/core/java/android/bluetooth/annotations/RequiresLegacyBluetoothAdminPermission.java deleted file mode 100644 index 9adf695cde0f01ef0a50ac897993d4529471cc85..0000000000000000000000000000000000000000 --- a/core/java/android/bluetooth/annotations/RequiresLegacyBluetoothAdminPermission.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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.bluetooth.annotations; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -import android.Manifest; -import android.os.Build; - -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -/** - * @memberDoc For apps targeting {@link Build.VERSION_CODES#R} or lower, this - * requires the {@link Manifest.permission#BLUETOOTH_ADMIN} - * permission which can be gained with a simple - * {@code } manifest tag. - * @hide - */ -@Retention(SOURCE) -@Target({METHOD, FIELD}) -public @interface RequiresLegacyBluetoothAdminPermission { -} diff --git a/core/java/android/bluetooth/annotations/RequiresLegacyBluetoothPermission.java b/core/java/android/bluetooth/annotations/RequiresLegacyBluetoothPermission.java deleted file mode 100644 index 79621c366f591b9e8fc507cfc0d80bf88d4d28c6..0000000000000000000000000000000000000000 --- a/core/java/android/bluetooth/annotations/RequiresLegacyBluetoothPermission.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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.bluetooth.annotations; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -import android.Manifest; -import android.os.Build; - -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -/** - * @memberDoc For apps targeting {@link Build.VERSION_CODES#R} or lower, this - * requires the {@link Manifest.permission#BLUETOOTH} permission - * which can be gained with a simple {@code } - * manifest tag. - * @hide - */ -@Retention(SOURCE) -@Target({METHOD, FIELD}) -public @interface RequiresLegacyBluetoothPermission { -} diff --git a/core/java/android/bluetooth/le/AdvertiseCallback.java b/core/java/android/bluetooth/le/AdvertiseCallback.java deleted file mode 100644 index 4fa8c4f2f5393efb0ec054ff15adb05a4a4c44b2..0000000000000000000000000000000000000000 --- a/core/java/android/bluetooth/le/AdvertiseCallback.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (C) 2014 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.bluetooth.le; - -/** - * Bluetooth LE advertising callbacks, used to deliver advertising operation status. - */ -public abstract class AdvertiseCallback { - - /** - * The requested operation was successful. - * - * @hide - */ - public static final int ADVERTISE_SUCCESS = 0; - - /** - * Failed to start advertising as the advertise data to be broadcasted is larger than 31 bytes. - */ - public static final int ADVERTISE_FAILED_DATA_TOO_LARGE = 1; - - /** - * Failed to start advertising because no advertising instance is available. - */ - public static final int ADVERTISE_FAILED_TOO_MANY_ADVERTISERS = 2; - - /** - * Failed to start advertising as the advertising is already started. - */ - public static final int ADVERTISE_FAILED_ALREADY_STARTED = 3; - - /** - * Operation failed due to an internal error. - */ - public static final int ADVERTISE_FAILED_INTERNAL_ERROR = 4; - - /** - * This feature is not supported on this platform. - */ - public static final int ADVERTISE_FAILED_FEATURE_UNSUPPORTED = 5; - - /** - * Callback triggered in response to {@link BluetoothLeAdvertiser#startAdvertising} indicating - * that the advertising has been started successfully. - * - * @param settingsInEffect The actual settings used for advertising, which may be different from - * what has been requested. - */ - public void onStartSuccess(AdvertiseSettings settingsInEffect) { - } - - /** - * Callback when advertising could not be started. - * - * @param errorCode Error code (see ADVERTISE_FAILED_* constants) for advertising start - * failures. - */ - public void onStartFailure(int errorCode) { - } -} diff --git a/core/java/android/bluetooth/le/AdvertiseData.java b/core/java/android/bluetooth/le/AdvertiseData.java deleted file mode 100644 index fdf62ec3a647082045f98289a68fe979446bcfd0..0000000000000000000000000000000000000000 --- a/core/java/android/bluetooth/le/AdvertiseData.java +++ /dev/null @@ -1,374 +0,0 @@ -/* - * Copyright (C) 2014 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.bluetooth.le; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.os.Parcel; -import android.os.ParcelUuid; -import android.os.Parcelable; -import android.util.ArrayMap; -import android.util.SparseArray; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Objects; - -/** - * Advertise data packet container for Bluetooth LE advertising. This represents the data to be - * advertised as well as the scan response data for active scans. - *

    - * Use {@link AdvertiseData.Builder} to create an instance of {@link AdvertiseData} to be - * advertised. - * - * @see BluetoothLeAdvertiser - * @see ScanRecord - */ -public final class AdvertiseData implements Parcelable { - - @Nullable - private final List mServiceUuids; - - @NonNull - private final List mServiceSolicitationUuids; - - @Nullable - private final List mTransportDiscoveryData; - - private final SparseArray mManufacturerSpecificData; - private final Map mServiceData; - private final boolean mIncludeTxPowerLevel; - private final boolean mIncludeDeviceName; - - private AdvertiseData(List serviceUuids, - List serviceSolicitationUuids, - List transportDiscoveryData, - SparseArray manufacturerData, - Map serviceData, - boolean includeTxPowerLevel, - boolean includeDeviceName) { - mServiceUuids = serviceUuids; - mServiceSolicitationUuids = serviceSolicitationUuids; - mTransportDiscoveryData = transportDiscoveryData; - mManufacturerSpecificData = manufacturerData; - mServiceData = serviceData; - mIncludeTxPowerLevel = includeTxPowerLevel; - mIncludeDeviceName = includeDeviceName; - } - - /** - * Returns a list of service UUIDs within the advertisement that are used to identify the - * Bluetooth GATT services. - */ - public List getServiceUuids() { - return mServiceUuids; - } - - /** - * Returns a list of service solicitation UUIDs within the advertisement that we invite to connect. - */ - @NonNull - public List getServiceSolicitationUuids() { - return mServiceSolicitationUuids; - } - - /** - * Returns a list of {@link TransportDiscoveryData} within the advertisement. - */ - @NonNull - public List getTransportDiscoveryData() { - if (mTransportDiscoveryData == null) { - return Collections.emptyList(); - } - return mTransportDiscoveryData; - } - - /** - * Returns an array of manufacturer Id and the corresponding manufacturer specific data. The - * manufacturer id is a non-negative number assigned by Bluetooth SIG. - */ - public SparseArray getManufacturerSpecificData() { - return mManufacturerSpecificData; - } - - /** - * Returns a map of 16-bit UUID and its corresponding service data. - */ - public Map getServiceData() { - return mServiceData; - } - - /** - * Whether the transmission power level will be included in the advertisement packet. - */ - public boolean getIncludeTxPowerLevel() { - return mIncludeTxPowerLevel; - } - - /** - * Whether the device name will be included in the advertisement packet. - */ - public boolean getIncludeDeviceName() { - return mIncludeDeviceName; - } - - /** - * @hide - */ - @Override - public int hashCode() { - return Objects.hash(mServiceUuids, mServiceSolicitationUuids, mTransportDiscoveryData, - mManufacturerSpecificData, mServiceData, mIncludeDeviceName, mIncludeTxPowerLevel); - } - - /** - * @hide - */ - @Override - public boolean equals(@Nullable Object obj) { - if (this == obj) { - return true; - } - if (obj == null || getClass() != obj.getClass()) { - return false; - } - AdvertiseData other = (AdvertiseData) obj; - return Objects.equals(mServiceUuids, other.mServiceUuids) - && Objects.equals(mServiceSolicitationUuids, other.mServiceSolicitationUuids) - && Objects.equals(mTransportDiscoveryData, other.mTransportDiscoveryData) - && BluetoothLeUtils.equals(mManufacturerSpecificData, - other.mManufacturerSpecificData) - && BluetoothLeUtils.equals(mServiceData, other.mServiceData) - && mIncludeDeviceName == other.mIncludeDeviceName - && mIncludeTxPowerLevel == other.mIncludeTxPowerLevel; - } - - @Override - public String toString() { - return "AdvertiseData [mServiceUuids=" + mServiceUuids + ", mServiceSolicitationUuids=" - + mServiceSolicitationUuids + ", mTransportDiscoveryData=" - + mTransportDiscoveryData + ", mManufacturerSpecificData=" - + BluetoothLeUtils.toString(mManufacturerSpecificData) + ", mServiceData=" - + BluetoothLeUtils.toString(mServiceData) - + ", mIncludeTxPowerLevel=" + mIncludeTxPowerLevel + ", mIncludeDeviceName=" - + mIncludeDeviceName + "]"; - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeTypedArray(mServiceUuids.toArray(new ParcelUuid[mServiceUuids.size()]), flags); - dest.writeTypedArray(mServiceSolicitationUuids.toArray( - new ParcelUuid[mServiceSolicitationUuids.size()]), flags); - - dest.writeTypedList(mTransportDiscoveryData); - - // mManufacturerSpecificData could not be null. - dest.writeInt(mManufacturerSpecificData.size()); - for (int i = 0; i < mManufacturerSpecificData.size(); ++i) { - dest.writeInt(mManufacturerSpecificData.keyAt(i)); - dest.writeByteArray(mManufacturerSpecificData.valueAt(i)); - } - dest.writeInt(mServiceData.size()); - for (ParcelUuid uuid : mServiceData.keySet()) { - dest.writeTypedObject(uuid, flags); - dest.writeByteArray(mServiceData.get(uuid)); - } - dest.writeByte((byte) (getIncludeTxPowerLevel() ? 1 : 0)); - dest.writeByte((byte) (getIncludeDeviceName() ? 1 : 0)); - } - - public static final @android.annotation.NonNull Parcelable.Creator CREATOR = - new Creator() { - @Override - public AdvertiseData[] newArray(int size) { - return new AdvertiseData[size]; - } - - @Override - public AdvertiseData createFromParcel(Parcel in) { - Builder builder = new Builder(); - ArrayList uuids = in.createTypedArrayList(ParcelUuid.CREATOR); - for (ParcelUuid uuid : uuids) { - builder.addServiceUuid(uuid); - } - - ArrayList solicitationUuids = in.createTypedArrayList(ParcelUuid.CREATOR); - for (ParcelUuid uuid : solicitationUuids) { - builder.addServiceSolicitationUuid(uuid); - } - - List transportDiscoveryData = - in.createTypedArrayList(TransportDiscoveryData.CREATOR); - for (TransportDiscoveryData tdd : transportDiscoveryData) { - builder.addTransportDiscoveryData(tdd); - } - - int manufacturerSize = in.readInt(); - for (int i = 0; i < manufacturerSize; ++i) { - int manufacturerId = in.readInt(); - byte[] manufacturerData = in.createByteArray(); - builder.addManufacturerData(manufacturerId, manufacturerData); - } - int serviceDataSize = in.readInt(); - for (int i = 0; i < serviceDataSize; ++i) { - ParcelUuid serviceDataUuid = in.readTypedObject(ParcelUuid.CREATOR); - byte[] serviceData = in.createByteArray(); - builder.addServiceData(serviceDataUuid, serviceData); - } - builder.setIncludeTxPowerLevel(in.readByte() == 1); - builder.setIncludeDeviceName(in.readByte() == 1); - return builder.build(); - } - }; - - /** - * Builder for {@link AdvertiseData}. - */ - public static final class Builder { - @Nullable - private List mServiceUuids = new ArrayList(); - @NonNull - private List mServiceSolicitationUuids = new ArrayList(); - @Nullable - private List mTransportDiscoveryData = - new ArrayList(); - private SparseArray mManufacturerSpecificData = new SparseArray(); - private Map mServiceData = new ArrayMap(); - private boolean mIncludeTxPowerLevel; - private boolean mIncludeDeviceName; - - /** - * Add a service UUID to advertise data. - * - * @param serviceUuid A service UUID to be advertised. - * @throws IllegalArgumentException If the {@code serviceUuid} is null. - */ - public Builder addServiceUuid(ParcelUuid serviceUuid) { - if (serviceUuid == null) { - throw new IllegalArgumentException("serviceUuid is null"); - } - mServiceUuids.add(serviceUuid); - return this; - } - - /** - * Add a service solicitation UUID to advertise data. - * - * @param serviceSolicitationUuid A service solicitation UUID to be advertised. - * @throws IllegalArgumentException If the {@code serviceSolicitationUuid} is null. - */ - @NonNull - public Builder addServiceSolicitationUuid(@NonNull ParcelUuid serviceSolicitationUuid) { - if (serviceSolicitationUuid == null) { - throw new IllegalArgumentException("serviceSolicitationUuid is null"); - } - mServiceSolicitationUuids.add(serviceSolicitationUuid); - return this; - } - - /** - * Add service data to advertise data. - * - * @param serviceDataUuid 16-bit UUID of the service the data is associated with - * @param serviceData Service data - * @throws IllegalArgumentException If the {@code serviceDataUuid} or {@code serviceData} is - * empty. - */ - public Builder addServiceData(ParcelUuid serviceDataUuid, byte[] serviceData) { - if (serviceDataUuid == null || serviceData == null) { - throw new IllegalArgumentException( - "serviceDataUuid or serviceDataUuid is null"); - } - mServiceData.put(serviceDataUuid, serviceData); - return this; - } - - /** - * Add Transport Discovery Data to advertise data. - * - * @param transportDiscoveryData Transport Discovery Data, consisting of one or more - * Transport Blocks. Transport Discovery Data AD Type Code is already included. - * @throws IllegalArgumentException If the {@code transportDiscoveryData} is empty - */ - @NonNull - public Builder addTransportDiscoveryData( - @NonNull TransportDiscoveryData transportDiscoveryData) { - if (transportDiscoveryData == null) { - throw new IllegalArgumentException("transportDiscoveryData is null"); - } - mTransportDiscoveryData.add(transportDiscoveryData); - return this; - } - - /** - * Add manufacturer specific data. - *

    - * Please refer to the Bluetooth Assigned Numbers document provided by the Bluetooth SIG for a list of existing company - * identifiers. - * - * @param manufacturerId Manufacturer ID assigned by Bluetooth SIG. - * @param manufacturerSpecificData Manufacturer specific data - * @throws IllegalArgumentException If the {@code manufacturerId} is negative or {@code - * manufacturerSpecificData} is null. - */ - public Builder addManufacturerData(int manufacturerId, byte[] manufacturerSpecificData) { - if (manufacturerId < 0) { - throw new IllegalArgumentException( - "invalid manufacturerId - " + manufacturerId); - } - if (manufacturerSpecificData == null) { - throw new IllegalArgumentException("manufacturerSpecificData is null"); - } - mManufacturerSpecificData.put(manufacturerId, manufacturerSpecificData); - return this; - } - - /** - * Whether the transmission power level should be included in the advertise packet. Tx power - * level field takes 3 bytes in advertise packet. - */ - public Builder setIncludeTxPowerLevel(boolean includeTxPowerLevel) { - mIncludeTxPowerLevel = includeTxPowerLevel; - return this; - } - - /** - * Set whether the device name should be included in advertise packet. - */ - public Builder setIncludeDeviceName(boolean includeDeviceName) { - mIncludeDeviceName = includeDeviceName; - return this; - } - - /** - * Build the {@link AdvertiseData}. - */ - public AdvertiseData build() { - return new AdvertiseData(mServiceUuids, mServiceSolicitationUuids, - mTransportDiscoveryData, mManufacturerSpecificData, mServiceData, - mIncludeTxPowerLevel, mIncludeDeviceName); - } - } -} diff --git a/core/java/android/bluetooth/le/AdvertiseSettings.java b/core/java/android/bluetooth/le/AdvertiseSettings.java deleted file mode 100644 index c52a6ee33989bec6394bdba350431d294daeb957..0000000000000000000000000000000000000000 --- a/core/java/android/bluetooth/le/AdvertiseSettings.java +++ /dev/null @@ -1,277 +0,0 @@ -/* - * Copyright (C) 2014 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.bluetooth.le; - -import android.annotation.NonNull; -import android.annotation.SystemApi; -import android.bluetooth.le.AdvertisingSetParameters.AddressTypeStatus; -import android.os.Parcel; -import android.os.Parcelable; - -/** - * The {@link AdvertiseSettings} provide a way to adjust advertising preferences for each - * Bluetooth LE advertisement instance. Use {@link AdvertiseSettings.Builder} to create an - * instance of this class. - */ -public final class AdvertiseSettings implements Parcelable { - /** - * Perform Bluetooth LE advertising in low power mode. This is the default and preferred - * advertising mode as it consumes the least power. - */ - public static final int ADVERTISE_MODE_LOW_POWER = 0; - - /** - * Perform Bluetooth LE advertising in balanced power mode. This is balanced between advertising - * frequency and power consumption. - */ - public static final int ADVERTISE_MODE_BALANCED = 1; - - /** - * Perform Bluetooth LE advertising in low latency, high power mode. This has the highest power - * consumption and should not be used for continuous background advertising. - */ - public static final int ADVERTISE_MODE_LOW_LATENCY = 2; - - /** - * Advertise using the lowest transmission (TX) power level. Low transmission power can be used - * to restrict the visibility range of advertising packets. - */ - public static final int ADVERTISE_TX_POWER_ULTRA_LOW = 0; - - /** - * Advertise using low TX power level. - */ - public static final int ADVERTISE_TX_POWER_LOW = 1; - - /** - * Advertise using medium TX power level. - */ - public static final int ADVERTISE_TX_POWER_MEDIUM = 2; - - /** - * Advertise using high TX power level. This corresponds to largest visibility range of the - * advertising packet. - */ - public static final int ADVERTISE_TX_POWER_HIGH = 3; - - /** - * The maximum limited advertisement duration as specified by the Bluetooth SIG - */ - private static final int LIMITED_ADVERTISING_MAX_MILLIS = 180 * 1000; - - - private final int mAdvertiseMode; - private final int mAdvertiseTxPowerLevel; - private final int mAdvertiseTimeoutMillis; - private final boolean mAdvertiseConnectable; - private final int mOwnAddressType; - - private AdvertiseSettings(int advertiseMode, int advertiseTxPowerLevel, - boolean advertiseConnectable, int advertiseTimeout, - @AddressTypeStatus int ownAddressType) { - mAdvertiseMode = advertiseMode; - mAdvertiseTxPowerLevel = advertiseTxPowerLevel; - mAdvertiseConnectable = advertiseConnectable; - mAdvertiseTimeoutMillis = advertiseTimeout; - mOwnAddressType = ownAddressType; - } - - private AdvertiseSettings(Parcel in) { - mAdvertiseMode = in.readInt(); - mAdvertiseTxPowerLevel = in.readInt(); - mAdvertiseConnectable = in.readInt() != 0; - mAdvertiseTimeoutMillis = in.readInt(); - mOwnAddressType = in.readInt(); - } - - /** - * Returns the advertise mode. - */ - public int getMode() { - return mAdvertiseMode; - } - - /** - * Returns the TX power level for advertising. - */ - public int getTxPowerLevel() { - return mAdvertiseTxPowerLevel; - } - - /** - * Returns whether the advertisement will indicate connectable. - */ - public boolean isConnectable() { - return mAdvertiseConnectable; - } - - /** - * Returns the advertising time limit in milliseconds. - */ - public int getTimeout() { - return mAdvertiseTimeoutMillis; - } - - /** - * @return the own address type for advertising - * - * @hide - */ - @SystemApi - public @AddressTypeStatus int getOwnAddressType() { - return mOwnAddressType; - } - - @Override - public String toString() { - return "Settings [mAdvertiseMode=" + mAdvertiseMode - + ", mAdvertiseTxPowerLevel=" + mAdvertiseTxPowerLevel - + ", mAdvertiseConnectable=" + mAdvertiseConnectable - + ", mAdvertiseTimeoutMillis=" + mAdvertiseTimeoutMillis - + ", mOwnAddressType=" + mOwnAddressType + "]"; - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeInt(mAdvertiseMode); - dest.writeInt(mAdvertiseTxPowerLevel); - dest.writeInt(mAdvertiseConnectable ? 1 : 0); - dest.writeInt(mAdvertiseTimeoutMillis); - dest.writeInt(mOwnAddressType); - } - - public static final @android.annotation.NonNull Parcelable.Creator CREATOR = - new Creator() { - @Override - public AdvertiseSettings[] newArray(int size) { - return new AdvertiseSettings[size]; - } - - @Override - public AdvertiseSettings createFromParcel(Parcel in) { - return new AdvertiseSettings(in); - } - }; - - /** - * Builder class for {@link AdvertiseSettings}. - */ - public static final class Builder { - private int mMode = ADVERTISE_MODE_LOW_POWER; - private int mTxPowerLevel = ADVERTISE_TX_POWER_MEDIUM; - private int mTimeoutMillis = 0; - private boolean mConnectable = true; - private int mOwnAddressType = AdvertisingSetParameters.ADDRESS_TYPE_DEFAULT; - - /** - * Set advertise mode to control the advertising power and latency. - * - * @param advertiseMode Bluetooth LE Advertising mode, can only be one of {@link - * AdvertiseSettings#ADVERTISE_MODE_LOW_POWER}, - * {@link AdvertiseSettings#ADVERTISE_MODE_BALANCED}, - * or {@link AdvertiseSettings#ADVERTISE_MODE_LOW_LATENCY}. - * @throws IllegalArgumentException If the advertiseMode is invalid. - */ - public Builder setAdvertiseMode(int advertiseMode) { - if (advertiseMode < ADVERTISE_MODE_LOW_POWER - || advertiseMode > ADVERTISE_MODE_LOW_LATENCY) { - throw new IllegalArgumentException("unknown mode " + advertiseMode); - } - mMode = advertiseMode; - return this; - } - - /** - * Set advertise TX power level to control the transmission power level for the advertising. - * - * @param txPowerLevel Transmission power of Bluetooth LE Advertising, can only be one of - * {@link AdvertiseSettings#ADVERTISE_TX_POWER_ULTRA_LOW}, {@link - * AdvertiseSettings#ADVERTISE_TX_POWER_LOW}, - * {@link AdvertiseSettings#ADVERTISE_TX_POWER_MEDIUM} - * or {@link AdvertiseSettings#ADVERTISE_TX_POWER_HIGH}. - * @throws IllegalArgumentException If the {@code txPowerLevel} is invalid. - */ - public Builder setTxPowerLevel(int txPowerLevel) { - if (txPowerLevel < ADVERTISE_TX_POWER_ULTRA_LOW - || txPowerLevel > ADVERTISE_TX_POWER_HIGH) { - throw new IllegalArgumentException("unknown tx power level " + txPowerLevel); - } - mTxPowerLevel = txPowerLevel; - return this; - } - - /** - * Set whether the advertisement type should be connectable or non-connectable. - * - * @param connectable Controls whether the advertisment type will be connectable (true) or - * non-connectable (false). - */ - public Builder setConnectable(boolean connectable) { - mConnectable = connectable; - return this; - } - - /** - * Limit advertising to a given amount of time. - * - * @param timeoutMillis Advertising time limit. May not exceed 180000 milliseconds. A value - * of 0 will disable the time limit. - * @throws IllegalArgumentException If the provided timeout is over 180000 ms. - */ - public Builder setTimeout(int timeoutMillis) { - if (timeoutMillis < 0 || timeoutMillis > LIMITED_ADVERTISING_MAX_MILLIS) { - throw new IllegalArgumentException("timeoutMillis invalid (must be 0-" - + LIMITED_ADVERTISING_MAX_MILLIS + " milliseconds)"); - } - mTimeoutMillis = timeoutMillis; - return this; - } - - /** - * Set own address type for advertising to control public or privacy mode. If used to set - * address type anything other than {@link AdvertisingSetParameters#ADDRESS_TYPE_DEFAULT}, - * then it will require BLUETOOTH_PRIVILEGED permission and will be checked at the - * time of starting advertising. - * - * @throws IllegalArgumentException If the {@code ownAddressType} is invalid - * - * @hide - */ - @SystemApi - public @NonNull Builder setOwnAddressType(@AddressTypeStatus int ownAddressType) { - if (ownAddressType < AdvertisingSetParameters.ADDRESS_TYPE_DEFAULT - || ownAddressType > AdvertisingSetParameters.ADDRESS_TYPE_RANDOM) { - throw new IllegalArgumentException("unknown address type " + ownAddressType); - } - mOwnAddressType = ownAddressType; - return this; - } - - /** - * Build the {@link AdvertiseSettings} object. - */ - public AdvertiseSettings build() { - return new AdvertiseSettings(mMode, mTxPowerLevel, mConnectable, mTimeoutMillis, - mOwnAddressType); - } - } -} diff --git a/core/java/android/bluetooth/le/AdvertisingSet.java b/core/java/android/bluetooth/le/AdvertisingSet.java deleted file mode 100644 index bbdb6953afd1ae21de8203421b5bdb0080efdb78..0000000000000000000000000000000000000000 --- a/core/java/android/bluetooth/le/AdvertisingSet.java +++ /dev/null @@ -1,230 +0,0 @@ -/* - * Copyright (C) 2017 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.bluetooth.le; - -import android.annotation.RequiresNoPermission; -import android.annotation.RequiresPermission; -import android.bluetooth.BluetoothAdapter; -import android.bluetooth.IBluetoothGatt; -import android.bluetooth.IBluetoothManager; -import android.bluetooth.annotations.RequiresBluetoothAdvertisePermission; -import android.bluetooth.annotations.RequiresLegacyBluetoothAdminPermission; -import android.content.AttributionSource; -import android.os.RemoteException; -import android.util.Log; - -/** - * This class provides a way to control single Bluetooth LE advertising instance. - *

    - * To get an instance of {@link AdvertisingSet}, call the - * {@link BluetoothLeAdvertiser#startAdvertisingSet} method. - * - * @see AdvertiseData - */ -public final class AdvertisingSet { - private static final String TAG = "AdvertisingSet"; - - private final IBluetoothGatt mGatt; - private int mAdvertiserId; - private AttributionSource mAttributionSource; - - /* package */ AdvertisingSet(int advertiserId, IBluetoothManager bluetoothManager, - AttributionSource attributionSource) { - mAdvertiserId = advertiserId; - mAttributionSource = attributionSource; - try { - mGatt = bluetoothManager.getBluetoothGatt(); - } catch (RemoteException e) { - Log.e(TAG, "Failed to get Bluetooth gatt - ", e); - throw new IllegalStateException("Failed to get Bluetooth"); - } - } - - /* package */ void setAdvertiserId(int advertiserId) { - mAdvertiserId = advertiserId; - } - - /** - * Enables Advertising. This method returns immediately, the operation status is - * delivered through {@code callback.onAdvertisingEnabled()}. - * - * @param enable whether the advertising should be enabled (true), or disabled (false) - * @param duration advertising duration, in 10ms unit. Valid range is from 1 (10ms) to 65535 - * (655,350 ms) - * @param maxExtendedAdvertisingEvents maximum number of extended advertising events the - * controller shall attempt to send prior to terminating the extended advertising, even if the - * duration has not expired. Valid range is from 1 to 255. - */ - @RequiresLegacyBluetoothAdminPermission - @RequiresBluetoothAdvertisePermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE) - public void enableAdvertising(boolean enable, int duration, - int maxExtendedAdvertisingEvents) { - try { - mGatt.enableAdvertisingSet(mAdvertiserId, enable, duration, - maxExtendedAdvertisingEvents, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "remote exception - ", e); - } - } - - /** - * Set/update data being Advertised. Make sure that data doesn't exceed the size limit for - * specified AdvertisingSetParameters. This method returns immediately, the operation status is - * delivered through {@code callback.onAdvertisingDataSet()}. - *

    - * Advertising data must be empty if non-legacy scannable advertising is used. - * - * @param advertiseData Advertisement data to be broadcasted. Size must not exceed {@link - * BluetoothAdapter#getLeMaximumAdvertisingDataLength}. If the advertisement is connectable, - * three bytes will be added for flags. If the update takes place when the advertising set is - * enabled, the data can be maximum 251 bytes long. - */ - @RequiresLegacyBluetoothAdminPermission - @RequiresBluetoothAdvertisePermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE) - public void setAdvertisingData(AdvertiseData advertiseData) { - try { - mGatt.setAdvertisingData(mAdvertiserId, advertiseData, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "remote exception - ", e); - } - } - - /** - * Set/update scan response data. Make sure that data doesn't exceed the size limit for - * specified AdvertisingSetParameters. This method returns immediately, the operation status - * is delivered through {@code callback.onScanResponseDataSet()}. - * - * @param scanResponse Scan response associated with the advertisement data. Size must not - * exceed {@link BluetoothAdapter#getLeMaximumAdvertisingDataLength}. If the update takes place - * when the advertising set is enabled, the data can be maximum 251 bytes long. - */ - @RequiresLegacyBluetoothAdminPermission - @RequiresBluetoothAdvertisePermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE) - public void setScanResponseData(AdvertiseData scanResponse) { - try { - mGatt.setScanResponseData(mAdvertiserId, scanResponse, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "remote exception - ", e); - } - } - - /** - * Update advertising parameters associated with this AdvertisingSet. Must be called when - * advertising is not active. This method returns immediately, the operation status is delivered - * through {@code callback.onAdvertisingParametersUpdated}. - * - * @param parameters advertising set parameters. - */ - @RequiresLegacyBluetoothAdminPermission - @RequiresBluetoothAdvertisePermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE) - public void setAdvertisingParameters(AdvertisingSetParameters parameters) { - try { - mGatt.setAdvertisingParameters(mAdvertiserId, parameters, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "remote exception - ", e); - } - } - - /** - * Update periodic advertising parameters associated with this set. Must be called when - * periodic advertising is not enabled. This method returns immediately, the operation - * status is delivered through {@code callback.onPeriodicAdvertisingParametersUpdated()}. - */ - @RequiresLegacyBluetoothAdminPermission - @RequiresBluetoothAdvertisePermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE) - public void setPeriodicAdvertisingParameters(PeriodicAdvertisingParameters parameters) { - try { - mGatt.setPeriodicAdvertisingParameters(mAdvertiserId, parameters, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "remote exception - ", e); - } - } - - /** - * Used to set periodic advertising data, must be called after setPeriodicAdvertisingParameters, - * or after advertising was started with periodic advertising data set. This method returns - * immediately, the operation status is delivered through - * {@code callback.onPeriodicAdvertisingDataSet()}. - * - * @param periodicData Periodic advertising data. Size must not exceed {@link - * BluetoothAdapter#getLeMaximumAdvertisingDataLength}. If the update takes place when the - * periodic advertising is enabled for this set, the data can be maximum 251 bytes long. - */ - @RequiresLegacyBluetoothAdminPermission - @RequiresBluetoothAdvertisePermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE) - public void setPeriodicAdvertisingData(AdvertiseData periodicData) { - try { - mGatt.setPeriodicAdvertisingData(mAdvertiserId, periodicData, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "remote exception - ", e); - } - } - - /** - * Used to enable/disable periodic advertising. This method returns immediately, the operation - * status is delivered through {@code callback.onPeriodicAdvertisingEnable()}. - * - * @param enable whether the periodic advertising should be enabled (true), or disabled - * (false). - */ - @RequiresLegacyBluetoothAdminPermission - @RequiresBluetoothAdvertisePermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE) - public void setPeriodicAdvertisingEnabled(boolean enable) { - try { - mGatt.setPeriodicAdvertisingEnable(mAdvertiserId, enable, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "remote exception - ", e); - } - } - - /** - * Returns address associated with this advertising set. - * This method is exposed only for Bluetooth PTS tests, no app or system service - * should ever use it. - * - * @hide - */ - @RequiresBluetoothAdvertisePermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_ADVERTISE, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) - public void getOwnAddress() { - try { - mGatt.getOwnAddress(mAdvertiserId, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "remote exception - ", e); - } - } - - /** - * Returns advertiserId associated with this advertising set. - * - * @hide - */ - @RequiresNoPermission - public int getAdvertiserId() { - return mAdvertiserId; - } -} diff --git a/core/java/android/bluetooth/le/AdvertisingSetCallback.java b/core/java/android/bluetooth/le/AdvertisingSetCallback.java deleted file mode 100644 index 51324fdb01ffeed6c306ae37fa1634c8dc50f55a..0000000000000000000000000000000000000000 --- a/core/java/android/bluetooth/le/AdvertisingSetCallback.java +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Copyright (C) 2017 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.bluetooth.le; - -/** - * Bluetooth LE advertising set callbacks, used to deliver advertising operation - * status. - */ -public abstract class AdvertisingSetCallback { - - /** - * The requested operation was successful. - */ - public static final int ADVERTISE_SUCCESS = 0; - - /** - * Failed to start advertising as the advertise data to be broadcasted is too - * large. - */ - public static final int ADVERTISE_FAILED_DATA_TOO_LARGE = 1; - - /** - * Failed to start advertising because no advertising instance is available. - */ - public static final int ADVERTISE_FAILED_TOO_MANY_ADVERTISERS = 2; - - /** - * Failed to start advertising as the advertising is already started. - */ - public static final int ADVERTISE_FAILED_ALREADY_STARTED = 3; - - /** - * Operation failed due to an internal error. - */ - public static final int ADVERTISE_FAILED_INTERNAL_ERROR = 4; - - /** - * This feature is not supported on this platform. - */ - public static final int ADVERTISE_FAILED_FEATURE_UNSUPPORTED = 5; - - /** - * Callback triggered in response to {@link BluetoothLeAdvertiser#startAdvertisingSet} - * indicating result of the operation. If status is ADVERTISE_SUCCESS, then advertisingSet - * contains the started set and it is advertising. If error occurred, advertisingSet is - * null, and status will be set to proper error code. - * - * @param advertisingSet The advertising set that was started or null if error. - * @param txPower tx power that will be used for this set. - * @param status Status of the operation. - */ - public void onAdvertisingSetStarted(AdvertisingSet advertisingSet, int txPower, int status) { - } - - /** - * Callback triggered in response to {@link BluetoothLeAdvertiser#stopAdvertisingSet} - * indicating advertising set is stopped. - * - * @param advertisingSet The advertising set. - */ - public void onAdvertisingSetStopped(AdvertisingSet advertisingSet) { - } - - /** - * Callback triggered in response to {@link BluetoothLeAdvertiser#startAdvertisingSet} - * indicating result of the operation. If status is ADVERTISE_SUCCESS, then advertising set is - * advertising. - * - * @param advertisingSet The advertising set. - * @param status Status of the operation. - */ - public void onAdvertisingEnabled(AdvertisingSet advertisingSet, boolean enable, int status) { - } - - /** - * Callback triggered in response to {@link AdvertisingSet#setAdvertisingData} indicating - * result of the operation. If status is ADVERTISE_SUCCESS, then data was changed. - * - * @param advertisingSet The advertising set. - * @param status Status of the operation. - */ - public void onAdvertisingDataSet(AdvertisingSet advertisingSet, int status) { - } - - /** - * Callback triggered in response to {@link AdvertisingSet#setAdvertisingData} indicating - * result of the operation. - * - * @param advertisingSet The advertising set. - * @param status Status of the operation. - */ - public void onScanResponseDataSet(AdvertisingSet advertisingSet, int status) { - } - - /** - * Callback triggered in response to {@link AdvertisingSet#setAdvertisingParameters} - * indicating result of the operation. - * - * @param advertisingSet The advertising set. - * @param txPower tx power that will be used for this set. - * @param status Status of the operation. - */ - public void onAdvertisingParametersUpdated(AdvertisingSet advertisingSet, - int txPower, int status) { - } - - /** - * Callback triggered in response to {@link AdvertisingSet#setPeriodicAdvertisingParameters} - * indicating result of the operation. - * - * @param advertisingSet The advertising set. - * @param status Status of the operation. - */ - public void onPeriodicAdvertisingParametersUpdated(AdvertisingSet advertisingSet, int status) { - } - - /** - * Callback triggered in response to {@link AdvertisingSet#setPeriodicAdvertisingData} - * indicating result of the operation. - * - * @param advertisingSet The advertising set. - * @param status Status of the operation. - */ - public void onPeriodicAdvertisingDataSet(AdvertisingSet advertisingSet, - int status) { - } - - /** - * Callback triggered in response to {@link AdvertisingSet#setPeriodicAdvertisingEnabled} - * indicating result of the operation. - * - * @param advertisingSet The advertising set. - * @param status Status of the operation. - */ - public void onPeriodicAdvertisingEnabled(AdvertisingSet advertisingSet, boolean enable, - int status) { - } - - /** - * Callback triggered in response to {@link AdvertisingSet#getOwnAddress()} - * indicating result of the operation. - * - * @param advertisingSet The advertising set. - * @param addressType type of address. - * @param address advertising set bluetooth address. - * @hide - */ - public void onOwnAddressRead(AdvertisingSet advertisingSet, int addressType, String address) { - } -} diff --git a/core/java/android/bluetooth/le/AdvertisingSetParameters.java b/core/java/android/bluetooth/le/AdvertisingSetParameters.java deleted file mode 100644 index 5c8fae65193d2e261b8977f93b1576930efa38f9..0000000000000000000000000000000000000000 --- a/core/java/android/bluetooth/le/AdvertisingSetParameters.java +++ /dev/null @@ -1,513 +0,0 @@ -/* - * Copyright (C) 2017 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.bluetooth.le; - -import android.annotation.IntDef; -import android.annotation.NonNull; -import android.annotation.SystemApi; -import android.bluetooth.BluetoothAdapter; -import android.bluetooth.BluetoothDevice; -import android.os.Parcel; -import android.os.Parcelable; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -/** - * The {@link AdvertisingSetParameters} provide a way to adjust advertising - * preferences for each - * Bluetooth LE advertising set. Use {@link AdvertisingSetParameters.Builder} to - * create an - * instance of this class. - */ -public final class AdvertisingSetParameters implements Parcelable { - - /** - * Advertise on low frequency, around every 1000ms. This is the default and - * preferred advertising mode as it consumes the least power. - */ - public static final int INTERVAL_HIGH = 1600; - - /** - * Advertise on medium frequency, around every 250ms. This is balanced - * between advertising frequency and power consumption. - */ - public static final int INTERVAL_MEDIUM = 400; - - /** - * Perform high frequency, low latency advertising, around every 100ms. This - * has the highest power consumption and should not be used for continuous - * background advertising. - */ - public static final int INTERVAL_LOW = 160; - - /** - * Minimum value for advertising interval. - */ - public static final int INTERVAL_MIN = 160; - - /** - * Maximum value for advertising interval. - */ - public static final int INTERVAL_MAX = 16777215; - - /** - * Advertise using the lowest transmission (TX) power level. Low transmission - * power can be used to restrict the visibility range of advertising packets. - */ - public static final int TX_POWER_ULTRA_LOW = -21; - - /** - * Advertise using low TX power level. - */ - public static final int TX_POWER_LOW = -15; - - /** - * Advertise using medium TX power level. - */ - public static final int TX_POWER_MEDIUM = -7; - - /** - * Advertise using high TX power level. This corresponds to largest visibility - * range of the advertising packet. - */ - public static final int TX_POWER_HIGH = 1; - - /** - * Minimum value for TX power. - */ - public static final int TX_POWER_MIN = -127; - - /** - * Maximum value for TX power. - */ - public static final int TX_POWER_MAX = 1; - - /** - * The maximum limited advertisement duration as specified by the Bluetooth - * SIG - */ - private static final int LIMITED_ADVERTISING_MAX_MILLIS = 180 * 1000; - - /** @hide */ - @IntDef(prefix = "ADDRESS_TYPE_", value = { - ADDRESS_TYPE_DEFAULT, - ADDRESS_TYPE_PUBLIC, - ADDRESS_TYPE_RANDOM - }) - @Retention(RetentionPolicy.SOURCE) - public @interface AddressTypeStatus {} - - /** - * Advertise own address type that corresponds privacy settings of the device. - * - * @hide - */ - @SystemApi - public static final int ADDRESS_TYPE_DEFAULT = -1; - - /** - * Advertise own public address type. - * - * @hide - */ - @SystemApi - public static final int ADDRESS_TYPE_PUBLIC = 0; - - /** - * Generate and adverise own resolvable private address. - * - * @hide - */ - @SystemApi - public static final int ADDRESS_TYPE_RANDOM = 1; - - private final boolean mIsLegacy; - private final boolean mIsAnonymous; - private final boolean mIncludeTxPower; - private final int mPrimaryPhy; - private final int mSecondaryPhy; - private final boolean mConnectable; - private final boolean mScannable; - private final int mInterval; - private final int mTxPowerLevel; - private final int mOwnAddressType; - - private AdvertisingSetParameters(boolean connectable, boolean scannable, boolean isLegacy, - boolean isAnonymous, boolean includeTxPower, - int primaryPhy, int secondaryPhy, - int interval, int txPowerLevel, @AddressTypeStatus int ownAddressType) { - mConnectable = connectable; - mScannable = scannable; - mIsLegacy = isLegacy; - mIsAnonymous = isAnonymous; - mIncludeTxPower = includeTxPower; - mPrimaryPhy = primaryPhy; - mSecondaryPhy = secondaryPhy; - mInterval = interval; - mTxPowerLevel = txPowerLevel; - mOwnAddressType = ownAddressType; - } - - private AdvertisingSetParameters(Parcel in) { - mConnectable = in.readInt() != 0; - mScannable = in.readInt() != 0; - mIsLegacy = in.readInt() != 0; - mIsAnonymous = in.readInt() != 0; - mIncludeTxPower = in.readInt() != 0; - mPrimaryPhy = in.readInt(); - mSecondaryPhy = in.readInt(); - mInterval = in.readInt(); - mTxPowerLevel = in.readInt(); - mOwnAddressType = in.readInt(); - } - - /** - * Returns whether the advertisement will be connectable. - */ - public boolean isConnectable() { - return mConnectable; - } - - /** - * Returns whether the advertisement will be scannable. - */ - public boolean isScannable() { - return mScannable; - } - - /** - * Returns whether the legacy advertisement will be used. - */ - public boolean isLegacy() { - return mIsLegacy; - } - - /** - * Returns whether the advertisement will be anonymous. - */ - public boolean isAnonymous() { - return mIsAnonymous; - } - - /** - * Returns whether the TX Power will be included. - */ - public boolean includeTxPower() { - return mIncludeTxPower; - } - - /** - * Returns the primary advertising phy. - */ - public int getPrimaryPhy() { - return mPrimaryPhy; - } - - /** - * Returns the secondary advertising phy. - */ - public int getSecondaryPhy() { - return mSecondaryPhy; - } - - /** - * Returns the advertising interval. - */ - public int getInterval() { - return mInterval; - } - - /** - * Returns the TX power level for advertising. - */ - public int getTxPowerLevel() { - return mTxPowerLevel; - } - - /** - * @return the own address type for advertising - * - * @hide - */ - @SystemApi - public @AddressTypeStatus int getOwnAddressType() { - return mOwnAddressType; - } - - @Override - public String toString() { - return "AdvertisingSetParameters [connectable=" + mConnectable - + ", isLegacy=" + mIsLegacy - + ", isAnonymous=" + mIsAnonymous - + ", includeTxPower=" + mIncludeTxPower - + ", primaryPhy=" + mPrimaryPhy - + ", secondaryPhy=" + mSecondaryPhy - + ", interval=" + mInterval - + ", txPowerLevel=" + mTxPowerLevel - + ", ownAddressType=" + mOwnAddressType + "]"; - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeInt(mConnectable ? 1 : 0); - dest.writeInt(mScannable ? 1 : 0); - dest.writeInt(mIsLegacy ? 1 : 0); - dest.writeInt(mIsAnonymous ? 1 : 0); - dest.writeInt(mIncludeTxPower ? 1 : 0); - dest.writeInt(mPrimaryPhy); - dest.writeInt(mSecondaryPhy); - dest.writeInt(mInterval); - dest.writeInt(mTxPowerLevel); - dest.writeInt(mOwnAddressType); - } - - public static final @android.annotation.NonNull Parcelable.Creator CREATOR = - new Creator() { - @Override - public AdvertisingSetParameters[] newArray(int size) { - return new AdvertisingSetParameters[size]; - } - - @Override - public AdvertisingSetParameters createFromParcel(Parcel in) { - return new AdvertisingSetParameters(in); - } - }; - - /** - * Builder class for {@link AdvertisingSetParameters}. - */ - public static final class Builder { - private boolean mConnectable = false; - private boolean mScannable = false; - private boolean mIsLegacy = false; - private boolean mIsAnonymous = false; - private boolean mIncludeTxPower = false; - private int mPrimaryPhy = BluetoothDevice.PHY_LE_1M; - private int mSecondaryPhy = BluetoothDevice.PHY_LE_1M; - private int mInterval = INTERVAL_LOW; - private int mTxPowerLevel = TX_POWER_MEDIUM; - private int mOwnAddressType = ADDRESS_TYPE_DEFAULT; - - /** - * Set whether the advertisement type should be connectable or - * non-connectable. - * Legacy advertisements can be both connectable and scannable. Non-legacy - * advertisements can be only scannable or only connectable. - * - * @param connectable Controls whether the advertisement type will be connectable (true) or - * non-connectable (false). - */ - public Builder setConnectable(boolean connectable) { - mConnectable = connectable; - return this; - } - - /** - * Set whether the advertisement type should be scannable. - * Legacy advertisements can be both connectable and scannable. Non-legacy - * advertisements can be only scannable or only connectable. - * - * @param scannable Controls whether the advertisement type will be scannable (true) or - * non-scannable (false). - */ - public Builder setScannable(boolean scannable) { - mScannable = scannable; - return this; - } - - /** - * When set to true, advertising set will advertise 4.x Spec compliant - * advertisements. - * - * @param isLegacy whether legacy advertising mode should be used. - */ - public Builder setLegacyMode(boolean isLegacy) { - mIsLegacy = isLegacy; - return this; - } - - /** - * Set whether advertiser address should be ommited from all packets. If this - * mode is used, periodic advertising can't be enabled for this set. - * - * This is used only if legacy mode is not used. - * - * @param isAnonymous whether anonymous advertising should be used. - */ - public Builder setAnonymous(boolean isAnonymous) { - mIsAnonymous = isAnonymous; - return this; - } - - /** - * Set whether TX power should be included in the extended header. - * - * This is used only if legacy mode is not used. - * - * @param includeTxPower whether TX power should be included in extended header - */ - public Builder setIncludeTxPower(boolean includeTxPower) { - mIncludeTxPower = includeTxPower; - return this; - } - - /** - * Set the primary physical channel used for this advertising set. - * - * This is used only if legacy mode is not used. - * - * Use {@link BluetoothAdapter#isLeCodedPhySupported} to determine if LE Coded PHY is - * supported on this device. - * - * @param primaryPhy Primary advertising physical channel, can only be {@link - * BluetoothDevice#PHY_LE_1M} or {@link BluetoothDevice#PHY_LE_CODED}. - * @throws IllegalArgumentException If the primaryPhy is invalid. - */ - public Builder setPrimaryPhy(int primaryPhy) { - if (primaryPhy != BluetoothDevice.PHY_LE_1M - && primaryPhy != BluetoothDevice.PHY_LE_CODED) { - throw new IllegalArgumentException("bad primaryPhy " + primaryPhy); - } - mPrimaryPhy = primaryPhy; - return this; - } - - /** - * Set the secondary physical channel used for this advertising set. - * - * This is used only if legacy mode is not used. - * - * Use {@link BluetoothAdapter#isLeCodedPhySupported} and - * {@link BluetoothAdapter#isLe2MPhySupported} to determine if LE Coded PHY or 2M PHY is - * supported on this device. - * - * @param secondaryPhy Secondary advertising physical channel, can only be one of {@link - * BluetoothDevice#PHY_LE_1M}, {@link BluetoothDevice#PHY_LE_2M} or {@link - * BluetoothDevice#PHY_LE_CODED}. - * @throws IllegalArgumentException If the secondaryPhy is invalid. - */ - public Builder setSecondaryPhy(int secondaryPhy) { - if (secondaryPhy != BluetoothDevice.PHY_LE_1M - && secondaryPhy != BluetoothDevice.PHY_LE_2M - && secondaryPhy != BluetoothDevice.PHY_LE_CODED) { - throw new IllegalArgumentException("bad secondaryPhy " + secondaryPhy); - } - mSecondaryPhy = secondaryPhy; - return this; - } - - /** - * Set advertising interval. - * - * @param interval Bluetooth LE Advertising interval, in 0.625ms unit. Valid range is from - * 160 (100ms) to 16777215 (10,485.759375 s). Recommended values are: {@link - * AdvertisingSetParameters#INTERVAL_LOW}, {@link AdvertisingSetParameters#INTERVAL_MEDIUM}, - * or {@link AdvertisingSetParameters#INTERVAL_HIGH}. - * @throws IllegalArgumentException If the interval is invalid. - */ - public Builder setInterval(int interval) { - if (interval < INTERVAL_MIN || interval > INTERVAL_MAX) { - throw new IllegalArgumentException("unknown interval " + interval); - } - mInterval = interval; - return this; - } - - /** - * Set the transmission power level for the advertising. - * - * @param txPowerLevel Transmission power of Bluetooth LE Advertising, in dBm. The valid - * range is [-127, 1] Recommended values are: - * {@link AdvertisingSetParameters#TX_POWER_ULTRA_LOW}, - * {@link AdvertisingSetParameters#TX_POWER_LOW}, - * {@link AdvertisingSetParameters#TX_POWER_MEDIUM}, - * or {@link AdvertisingSetParameters#TX_POWER_HIGH}. - * @throws IllegalArgumentException If the {@code txPowerLevel} is invalid. - */ - public Builder setTxPowerLevel(int txPowerLevel) { - if (txPowerLevel < TX_POWER_MIN || txPowerLevel > TX_POWER_MAX) { - throw new IllegalArgumentException("unknown txPowerLevel " + txPowerLevel); - } - mTxPowerLevel = txPowerLevel; - return this; - } - - /** - * Set own address type for advertising to control public or privacy mode. If used to set - * address type anything other than {@link AdvertisingSetParameters#ADDRESS_TYPE_DEFAULT}, - * then it will require BLUETOOTH_PRIVILEGED permission and will be checked at the - * time of starting advertising. - * - * @throws IllegalArgumentException If the {@code ownAddressType} is invalid - * - * @hide - */ - @SystemApi - public @NonNull Builder setOwnAddressType(@AddressTypeStatus int ownAddressType) { - if (ownAddressType < AdvertisingSetParameters.ADDRESS_TYPE_DEFAULT - || ownAddressType > AdvertisingSetParameters.ADDRESS_TYPE_RANDOM) { - throw new IllegalArgumentException("unknown address type " + ownAddressType); - } - mOwnAddressType = ownAddressType; - return this; - } - - /** - * Build the {@link AdvertisingSetParameters} object. - * - * @throws IllegalStateException if invalid combination of parameters is used. - */ - public AdvertisingSetParameters build() { - if (mIsLegacy) { - if (mIsAnonymous) { - throw new IllegalArgumentException("Legacy advertising can't be anonymous"); - } - - if (mConnectable && !mScannable) { - throw new IllegalStateException( - "Legacy advertisement can't be connectable and non-scannable"); - } - - if (mIncludeTxPower) { - throw new IllegalStateException( - "Legacy advertising can't include TX power level in header"); - } - } else { - if (mConnectable && mScannable) { - throw new IllegalStateException( - "Advertising can't be both connectable and scannable"); - } - - if (mIsAnonymous && mConnectable) { - throw new IllegalStateException( - "Advertising can't be both connectable and anonymous"); - } - } - - return new AdvertisingSetParameters(mConnectable, mScannable, mIsLegacy, mIsAnonymous, - mIncludeTxPower, mPrimaryPhy, mSecondaryPhy, mInterval, mTxPowerLevel, - mOwnAddressType); - } - } -} diff --git a/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java b/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java deleted file mode 100644 index 879dceedaaec1413bb939fbc7f0b85bb23927e70..0000000000000000000000000000000000000000 --- a/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java +++ /dev/null @@ -1,756 +0,0 @@ -/* - * Copyright (C) 2014 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.bluetooth.le; - -import android.annotation.RequiresNoPermission; -import android.annotation.RequiresPermission; -import android.annotation.SuppressLint; -import android.bluetooth.BluetoothAdapter; -import android.bluetooth.BluetoothDevice; -import android.bluetooth.BluetoothUuid; -import android.bluetooth.IBluetoothGatt; -import android.bluetooth.IBluetoothManager; -import android.bluetooth.annotations.RequiresBluetoothAdvertisePermission; -import android.bluetooth.annotations.RequiresLegacyBluetoothAdminPermission; -import android.content.AttributionSource; -import android.os.Handler; -import android.os.Looper; -import android.os.ParcelUuid; -import android.os.RemoteException; -import android.util.Log; - -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; -import java.util.Objects; - -/** - * This class provides a way to perform Bluetooth LE advertise operations, such as starting and - * stopping advertising. An advertiser can broadcast up to 31 bytes of advertisement data - * represented by {@link AdvertiseData}. - *

    - * To get an instance of {@link BluetoothLeAdvertiser}, call the - * {@link BluetoothAdapter#getBluetoothLeAdvertiser()} method. - * - * @see AdvertiseData - */ -public final class BluetoothLeAdvertiser { - - private static final String TAG = "BluetoothLeAdvertiser"; - - private static final int MAX_ADVERTISING_DATA_BYTES = 1650; - private static final int MAX_LEGACY_ADVERTISING_DATA_BYTES = 31; - // Each fields need one byte for field length and another byte for field type. - private static final int OVERHEAD_BYTES_PER_FIELD = 2; - // Flags field will be set by system. - private static final int FLAGS_FIELD_BYTES = 3; - private static final int MANUFACTURER_SPECIFIC_DATA_LENGTH = 2; - - private final BluetoothAdapter mBluetoothAdapter; - private final IBluetoothManager mBluetoothManager; - private final AttributionSource mAttributionSource; - - private final Handler mHandler; - private final Map - mLegacyAdvertisers = new HashMap<>(); - private final Map - mCallbackWrappers = Collections.synchronizedMap(new HashMap<>()); - private final Map - mAdvertisingSets = Collections.synchronizedMap(new HashMap<>()); - - /** - * Use BluetoothAdapter.getLeAdvertiser() instead. - * - * @param bluetoothManager BluetoothManager that conducts overall Bluetooth Management - * @hide - */ - public BluetoothLeAdvertiser(BluetoothAdapter bluetoothAdapter) { - mBluetoothAdapter = Objects.requireNonNull(bluetoothAdapter); - mBluetoothManager = mBluetoothAdapter.getBluetoothManager(); - mAttributionSource = mBluetoothAdapter.getAttributionSource(); - mHandler = new Handler(Looper.getMainLooper()); - } - - /** - * Start Bluetooth LE Advertising. On success, the {@code advertiseData} will be broadcasted. - * Returns immediately, the operation status is delivered through {@code callback}. - * - * @param settings Settings for Bluetooth LE advertising. - * @param advertiseData Advertisement data to be broadcasted. - * @param callback Callback for advertising status. - */ - @RequiresLegacyBluetoothAdminPermission - @RequiresBluetoothAdvertisePermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE) - public void startAdvertising(AdvertiseSettings settings, - AdvertiseData advertiseData, final AdvertiseCallback callback) { - startAdvertising(settings, advertiseData, null, callback); - } - - /** - * Start Bluetooth LE Advertising. The {@code advertiseData} will be broadcasted if the - * operation succeeds. The {@code scanResponse} is returned when a scanning device sends an - * active scan request. This method returns immediately, the operation status is delivered - * through {@code callback}. - * - * @param settings Settings for Bluetooth LE advertising. - * @param advertiseData Advertisement data to be advertised in advertisement packet. - * @param scanResponse Scan response associated with the advertisement data. - * @param callback Callback for advertising status. - */ - @RequiresLegacyBluetoothAdminPermission - @RequiresBluetoothAdvertisePermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE) - public void startAdvertising(AdvertiseSettings settings, - AdvertiseData advertiseData, AdvertiseData scanResponse, - final AdvertiseCallback callback) { - synchronized (mLegacyAdvertisers) { - BluetoothLeUtils.checkAdapterStateOn(mBluetoothAdapter); - if (callback == null) { - throw new IllegalArgumentException("callback cannot be null"); - } - boolean isConnectable = settings.isConnectable(); - if (totalBytes(advertiseData, isConnectable) > MAX_LEGACY_ADVERTISING_DATA_BYTES - || totalBytes(scanResponse, false) > MAX_LEGACY_ADVERTISING_DATA_BYTES) { - postStartFailure(callback, AdvertiseCallback.ADVERTISE_FAILED_DATA_TOO_LARGE); - return; - } - if (mLegacyAdvertisers.containsKey(callback)) { - postStartFailure(callback, AdvertiseCallback.ADVERTISE_FAILED_ALREADY_STARTED); - return; - } - - AdvertisingSetParameters.Builder parameters = new AdvertisingSetParameters.Builder(); - parameters.setLegacyMode(true); - parameters.setConnectable(isConnectable); - parameters.setScannable(true); // legacy advertisements we support are always scannable - parameters.setOwnAddressType(settings.getOwnAddressType()); - if (settings.getMode() == AdvertiseSettings.ADVERTISE_MODE_LOW_POWER) { - parameters.setInterval(1600); // 1s - } else if (settings.getMode() == AdvertiseSettings.ADVERTISE_MODE_BALANCED) { - parameters.setInterval(400); // 250ms - } else if (settings.getMode() == AdvertiseSettings.ADVERTISE_MODE_LOW_LATENCY) { - parameters.setInterval(160); // 100ms - } - - if (settings.getTxPowerLevel() == AdvertiseSettings.ADVERTISE_TX_POWER_ULTRA_LOW) { - parameters.setTxPowerLevel(-21); - } else if (settings.getTxPowerLevel() == AdvertiseSettings.ADVERTISE_TX_POWER_LOW) { - parameters.setTxPowerLevel(-15); - } else if (settings.getTxPowerLevel() == AdvertiseSettings.ADVERTISE_TX_POWER_MEDIUM) { - parameters.setTxPowerLevel(-7); - } else if (settings.getTxPowerLevel() == AdvertiseSettings.ADVERTISE_TX_POWER_HIGH) { - parameters.setTxPowerLevel(1); - } - - int duration = 0; - int timeoutMillis = settings.getTimeout(); - if (timeoutMillis > 0) { - duration = (timeoutMillis < 10) ? 1 : timeoutMillis / 10; - } - - AdvertisingSetCallback wrapped = wrapOldCallback(callback, settings); - mLegacyAdvertisers.put(callback, wrapped); - startAdvertisingSet(parameters.build(), advertiseData, scanResponse, null, null, - duration, 0, wrapped); - } - } - - @SuppressLint({ - "AndroidFrameworkBluetoothPermission", - "AndroidFrameworkRequiresPermission", - }) - AdvertisingSetCallback wrapOldCallback(AdvertiseCallback callback, AdvertiseSettings settings) { - return new AdvertisingSetCallback() { - @Override - public void onAdvertisingSetStarted(AdvertisingSet advertisingSet, int txPower, - int status) { - if (status != AdvertisingSetCallback.ADVERTISE_SUCCESS) { - postStartFailure(callback, status); - return; - } - - postStartSuccess(callback, settings); - } - - /* Legacy advertiser is disabled on timeout */ - @Override - public void onAdvertisingEnabled(AdvertisingSet advertisingSet, boolean enabled, - int status) { - if (enabled) { - Log.e(TAG, "Legacy advertiser should be only disabled on timeout," - + " but was enabled!"); - return; - } - - stopAdvertising(callback); - } - - }; - } - - /** - * Stop Bluetooth LE advertising. The {@code callback} must be the same one use in - * {@link BluetoothLeAdvertiser#startAdvertising}. - * - * @param callback {@link AdvertiseCallback} identifies the advertising instance to stop. - */ - @RequiresLegacyBluetoothAdminPermission - @RequiresBluetoothAdvertisePermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE) - public void stopAdvertising(final AdvertiseCallback callback) { - synchronized (mLegacyAdvertisers) { - if (callback == null) { - throw new IllegalArgumentException("callback cannot be null"); - } - AdvertisingSetCallback wrapper = mLegacyAdvertisers.get(callback); - if (wrapper == null) return; - - stopAdvertisingSet(wrapper); - - mLegacyAdvertisers.remove(callback); - } - } - - /** - * Creates a new advertising set. If operation succeed, device will start advertising. This - * method returns immediately, the operation status is delivered through - * {@code callback.onAdvertisingSetStarted()}. - *

    - * - * @param parameters advertising set parameters. - * @param advertiseData Advertisement data to be broadcasted. Size must not exceed {@link - * BluetoothAdapter#getLeMaximumAdvertisingDataLength}. If the advertisement is connectable, - * three bytes will be added for flags. - * @param scanResponse Scan response associated with the advertisement data. Size must not - * exceed {@link BluetoothAdapter#getLeMaximumAdvertisingDataLength}. - * @param periodicParameters periodic advertisng parameters. If null, periodic advertising will - * not be started. - * @param periodicData Periodic advertising data. Size must not exceed {@link - * BluetoothAdapter#getLeMaximumAdvertisingDataLength}. - * @param callback Callback for advertising set. - * @throws IllegalArgumentException when any of the data parameter exceed the maximum allowable - * size, or unsupported advertising PHY is selected, or when attempt to use Periodic Advertising - * feature is made when it's not supported by the controller. - */ - @RequiresLegacyBluetoothAdminPermission - @RequiresBluetoothAdvertisePermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE) - public void startAdvertisingSet(AdvertisingSetParameters parameters, - AdvertiseData advertiseData, AdvertiseData scanResponse, - PeriodicAdvertisingParameters periodicParameters, - AdvertiseData periodicData, AdvertisingSetCallback callback) { - startAdvertisingSet(parameters, advertiseData, scanResponse, periodicParameters, - periodicData, 0, 0, callback, new Handler(Looper.getMainLooper())); - } - - /** - * Creates a new advertising set. If operation succeed, device will start advertising. This - * method returns immediately, the operation status is delivered through - * {@code callback.onAdvertisingSetStarted()}. - *

    - * - * @param parameters advertising set parameters. - * @param advertiseData Advertisement data to be broadcasted. Size must not exceed {@link - * BluetoothAdapter#getLeMaximumAdvertisingDataLength}. If the advertisement is connectable, - * three bytes will be added for flags. - * @param scanResponse Scan response associated with the advertisement data. Size must not - * exceed {@link BluetoothAdapter#getLeMaximumAdvertisingDataLength}. - * @param periodicParameters periodic advertisng parameters. If null, periodic advertising will - * not be started. - * @param periodicData Periodic advertising data. Size must not exceed {@link - * BluetoothAdapter#getLeMaximumAdvertisingDataLength}. - * @param callback Callback for advertising set. - * @param handler thread upon which the callbacks will be invoked. - * @throws IllegalArgumentException when any of the data parameter exceed the maximum allowable - * size, or unsupported advertising PHY is selected, or when attempt to use Periodic Advertising - * feature is made when it's not supported by the controller. - */ - @RequiresLegacyBluetoothAdminPermission - @RequiresBluetoothAdvertisePermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE) - public void startAdvertisingSet(AdvertisingSetParameters parameters, - AdvertiseData advertiseData, AdvertiseData scanResponse, - PeriodicAdvertisingParameters periodicParameters, - AdvertiseData periodicData, AdvertisingSetCallback callback, - Handler handler) { - startAdvertisingSet(parameters, advertiseData, scanResponse, periodicParameters, - periodicData, 0, 0, callback, handler); - } - - /** - * Creates a new advertising set. If operation succeed, device will start advertising. This - * method returns immediately, the operation status is delivered through - * {@code callback.onAdvertisingSetStarted()}. - *

    - * - * @param parameters advertising set parameters. - * @param advertiseData Advertisement data to be broadcasted. Size must not exceed {@link - * BluetoothAdapter#getLeMaximumAdvertisingDataLength}. If the advertisement is connectable, - * three bytes will be added for flags. - * @param scanResponse Scan response associated with the advertisement data. Size must not - * exceed {@link BluetoothAdapter#getLeMaximumAdvertisingDataLength}. - * @param periodicParameters periodic advertisng parameters. If null, periodic advertising will - * not be started. - * @param periodicData Periodic advertising data. Size must not exceed {@link - * BluetoothAdapter#getLeMaximumAdvertisingDataLength}. - * @param duration advertising duration, in 10ms unit. Valid range is from 1 (10ms) to 65535 - * (655,350 ms). 0 means advertising should continue until stopped. - * @param maxExtendedAdvertisingEvents maximum number of extended advertising events the - * controller shall attempt to send prior to terminating the extended advertising, even if the - * duration has not expired. Valid range is from 1 to 255. 0 means no maximum. - * @param callback Callback for advertising set. - * @throws IllegalArgumentException when any of the data parameter exceed the maximum allowable - * size, or unsupported advertising PHY is selected, or when attempt to use Periodic Advertising - * feature is made when it's not supported by the controller. - */ - @RequiresLegacyBluetoothAdminPermission - @RequiresBluetoothAdvertisePermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE) - public void startAdvertisingSet(AdvertisingSetParameters parameters, - AdvertiseData advertiseData, AdvertiseData scanResponse, - PeriodicAdvertisingParameters periodicParameters, - AdvertiseData periodicData, int duration, - int maxExtendedAdvertisingEvents, - AdvertisingSetCallback callback) { - startAdvertisingSet(parameters, advertiseData, scanResponse, periodicParameters, - periodicData, duration, maxExtendedAdvertisingEvents, callback, - new Handler(Looper.getMainLooper())); - } - - /** - * Creates a new advertising set. If operation succeed, device will start advertising. This - * method returns immediately, the operation status is delivered through - * {@code callback.onAdvertisingSetStarted()}. - *

    - * - * @param parameters Advertising set parameters. - * @param advertiseData Advertisement data to be broadcasted. Size must not exceed {@link - * BluetoothAdapter#getLeMaximumAdvertisingDataLength}. If the advertisement is connectable, - * three bytes will be added for flags. - * @param scanResponse Scan response associated with the advertisement data. Size must not - * exceed {@link BluetoothAdapter#getLeMaximumAdvertisingDataLength} - * @param periodicParameters Periodic advertisng parameters. If null, periodic advertising will - * not be started. - * @param periodicData Periodic advertising data. Size must not exceed {@link - * BluetoothAdapter#getLeMaximumAdvertisingDataLength} - * @param duration advertising duration, in 10ms unit. Valid range is from 1 (10ms) to 65535 - * (655,350 ms). 0 means advertising should continue until stopped. - * @param maxExtendedAdvertisingEvents maximum number of extended advertising events the - * controller shall attempt to send prior to terminating the extended advertising, even if the - * duration has not expired. Valid range is from 1 to 255. 0 means no maximum. - * @param callback Callback for advertising set. - * @param handler Thread upon which the callbacks will be invoked. - * @throws IllegalArgumentException When any of the data parameter exceed the maximum allowable - * size, or unsupported advertising PHY is selected, or when attempt to use Periodic Advertising - * feature is made when it's not supported by the controller, or when - * maxExtendedAdvertisingEvents is used on a controller that doesn't support the LE Extended - * Advertising - */ - @RequiresLegacyBluetoothAdminPermission - @RequiresBluetoothAdvertisePermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE) - public void startAdvertisingSet(AdvertisingSetParameters parameters, - AdvertiseData advertiseData, AdvertiseData scanResponse, - PeriodicAdvertisingParameters periodicParameters, - AdvertiseData periodicData, int duration, - int maxExtendedAdvertisingEvents, AdvertisingSetCallback callback, - Handler handler) { - BluetoothLeUtils.checkAdapterStateOn(mBluetoothAdapter); - if (callback == null) { - throw new IllegalArgumentException("callback cannot be null"); - } - - boolean isConnectable = parameters.isConnectable(); - if (parameters.isLegacy()) { - if (totalBytes(advertiseData, isConnectable) > MAX_LEGACY_ADVERTISING_DATA_BYTES) { - throw new IllegalArgumentException("Legacy advertising data too big"); - } - - if (totalBytes(scanResponse, false) > MAX_LEGACY_ADVERTISING_DATA_BYTES) { - throw new IllegalArgumentException("Legacy scan response data too big"); - } - } else { - boolean supportCodedPhy = mBluetoothAdapter.isLeCodedPhySupported(); - boolean support2MPhy = mBluetoothAdapter.isLe2MPhySupported(); - int pphy = parameters.getPrimaryPhy(); - int sphy = parameters.getSecondaryPhy(); - if (pphy == BluetoothDevice.PHY_LE_CODED && !supportCodedPhy) { - throw new IllegalArgumentException("Unsupported primary PHY selected"); - } - - if ((sphy == BluetoothDevice.PHY_LE_CODED && !supportCodedPhy) - || (sphy == BluetoothDevice.PHY_LE_2M && !support2MPhy)) { - throw new IllegalArgumentException("Unsupported secondary PHY selected"); - } - - int maxData = mBluetoothAdapter.getLeMaximumAdvertisingDataLength(); - if (totalBytes(advertiseData, isConnectable) > maxData) { - throw new IllegalArgumentException("Advertising data too big"); - } - - if (totalBytes(scanResponse, false) > maxData) { - throw new IllegalArgumentException("Scan response data too big"); - } - - if (totalBytes(periodicData, false) > maxData) { - throw new IllegalArgumentException("Periodic advertising data too big"); - } - - boolean supportPeriodic = mBluetoothAdapter.isLePeriodicAdvertisingSupported(); - if (periodicParameters != null && !supportPeriodic) { - throw new IllegalArgumentException( - "Controller does not support LE Periodic Advertising"); - } - } - - if (maxExtendedAdvertisingEvents < 0 || maxExtendedAdvertisingEvents > 255) { - throw new IllegalArgumentException( - "maxExtendedAdvertisingEvents out of range: " + maxExtendedAdvertisingEvents); - } - - if (maxExtendedAdvertisingEvents != 0 - && !mBluetoothAdapter.isLePeriodicAdvertisingSupported()) { - throw new IllegalArgumentException( - "Can't use maxExtendedAdvertisingEvents with controller that don't support " - + "LE Extended Advertising"); - } - - if (duration < 0 || duration > 65535) { - throw new IllegalArgumentException("duration out of range: " + duration); - } - - IBluetoothGatt gatt; - try { - gatt = mBluetoothManager.getBluetoothGatt(); - } catch (RemoteException e) { - Log.e(TAG, "Failed to get Bluetooth GATT - ", e); - postStartSetFailure(handler, callback, - AdvertiseCallback.ADVERTISE_FAILED_INTERNAL_ERROR); - return; - } - - if (gatt == null) { - Log.e(TAG, "Bluetooth GATT is null"); - postStartSetFailure(handler, callback, - AdvertiseCallback.ADVERTISE_FAILED_INTERNAL_ERROR); - return; - } - - IAdvertisingSetCallback wrapped = wrap(callback, handler); - if (mCallbackWrappers.putIfAbsent(callback, wrapped) != null) { - throw new IllegalArgumentException( - "callback instance already associated with advertising"); - } - - try { - gatt.startAdvertisingSet(parameters, advertiseData, scanResponse, periodicParameters, - periodicData, duration, maxExtendedAdvertisingEvents, wrapped, - mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "Failed to start advertising set - ", e); - postStartSetFailure(handler, callback, - AdvertiseCallback.ADVERTISE_FAILED_INTERNAL_ERROR); - return; - } - } - - /** - * Used to dispose of a {@link AdvertisingSet} object, obtained with {@link - * BluetoothLeAdvertiser#startAdvertisingSet}. - */ - @RequiresLegacyBluetoothAdminPermission - @RequiresBluetoothAdvertisePermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE) - public void stopAdvertisingSet(AdvertisingSetCallback callback) { - if (callback == null) { - throw new IllegalArgumentException("callback cannot be null"); - } - - IAdvertisingSetCallback wrapped = mCallbackWrappers.remove(callback); - if (wrapped == null) { - return; - } - - IBluetoothGatt gatt; - try { - gatt = mBluetoothManager.getBluetoothGatt(); - gatt.stopAdvertisingSet(wrapped, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "Failed to stop advertising - ", e); - } - } - - /** - * Cleans up advertisers. Should be called when bluetooth is down. - * - * @hide - */ - @RequiresNoPermission - public void cleanup() { - mLegacyAdvertisers.clear(); - mCallbackWrappers.clear(); - mAdvertisingSets.clear(); - } - - // 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; - // Flags field is omitted if the advertising is not connectable. - int size = (isFlagsIncluded) ? FLAGS_FIELD_BYTES : 0; - if (data.getServiceUuids() != null) { - int num16BitUuids = 0; - int num32BitUuids = 0; - int num128BitUuids = 0; - for (ParcelUuid uuid : data.getServiceUuids()) { - if (BluetoothUuid.is16BitUuid(uuid)) { - ++num16BitUuids; - } else if (BluetoothUuid.is32BitUuid(uuid)) { - ++num32BitUuids; - } else { - ++num128BitUuids; - } - } - // 16 bit service uuids are grouped into one field when doing advertising. - if (num16BitUuids != 0) { - size += OVERHEAD_BYTES_PER_FIELD + num16BitUuids * BluetoothUuid.UUID_BYTES_16_BIT; - } - // 32 bit service uuids are grouped into one field when doing advertising. - if (num32BitUuids != 0) { - size += OVERHEAD_BYTES_PER_FIELD + num32BitUuids * BluetoothUuid.UUID_BYTES_32_BIT; - } - // 128 bit service uuids are grouped into one field when doing advertising. - if (num128BitUuids != 0) { - size += OVERHEAD_BYTES_PER_FIELD - + num128BitUuids * BluetoothUuid.UUID_BYTES_128_BIT; - } - } - if (data.getServiceSolicitationUuids() != null) { - int num16BitUuids = 0; - int num32BitUuids = 0; - int num128BitUuids = 0; - for (ParcelUuid uuid : data.getServiceSolicitationUuids()) { - if (BluetoothUuid.is16BitUuid(uuid)) { - ++num16BitUuids; - } else if (BluetoothUuid.is32BitUuid(uuid)) { - ++num32BitUuids; - } else { - ++num128BitUuids; - } - } - // 16 bit service uuids are grouped into one field when doing advertising. - if (num16BitUuids != 0) { - size += OVERHEAD_BYTES_PER_FIELD + num16BitUuids * BluetoothUuid.UUID_BYTES_16_BIT; - } - // 32 bit service uuids are grouped into one field when doing advertising. - if (num32BitUuids != 0) { - size += OVERHEAD_BYTES_PER_FIELD + num32BitUuids * BluetoothUuid.UUID_BYTES_32_BIT; - } - // 128 bit service uuids are grouped into one field when doing advertising. - if (num128BitUuids != 0) { - size += OVERHEAD_BYTES_PER_FIELD - + num128BitUuids * BluetoothUuid.UUID_BYTES_128_BIT; - } - } - for (TransportDiscoveryData transportDiscoveryData : data.getTransportDiscoveryData()) { - size += OVERHEAD_BYTES_PER_FIELD + transportDiscoveryData.totalBytes(); - } - for (ParcelUuid uuid : data.getServiceData().keySet()) { - int uuidLen = BluetoothUuid.uuidToBytes(uuid).length; - size += OVERHEAD_BYTES_PER_FIELD + uuidLen - + byteLength(data.getServiceData().get(uuid)); - } - for (int i = 0; i < data.getManufacturerSpecificData().size(); ++i) { - size += OVERHEAD_BYTES_PER_FIELD + MANUFACTURER_SPECIFIC_DATA_LENGTH - + byteLength(data.getManufacturerSpecificData().valueAt(i)); - } - if (data.getIncludeTxPowerLevel()) { - size += OVERHEAD_BYTES_PER_FIELD + 1; // tx power level value is one byte. - } - if (data.getIncludeDeviceName()) { - final int length = mBluetoothAdapter.getNameLengthForAdvertise(); - if (length >= 0) { - size += OVERHEAD_BYTES_PER_FIELD + length; - } - } - return size; - } - - private int byteLength(byte[] array) { - return array == null ? 0 : array.length; - } - - @SuppressLint("AndroidFrameworkBluetoothPermission") - IAdvertisingSetCallback wrap(AdvertisingSetCallback callback, Handler handler) { - return new IAdvertisingSetCallback.Stub() { - @Override - public void onAdvertisingSetStarted(int advertiserId, int txPower, int status) { - handler.post(new Runnable() { - @Override - public void run() { - if (status != AdvertisingSetCallback.ADVERTISE_SUCCESS) { - callback.onAdvertisingSetStarted(null, 0, status); - mCallbackWrappers.remove(callback); - return; - } - - AdvertisingSet advertisingSet = new AdvertisingSet( - advertiserId, mBluetoothManager, mAttributionSource); - mAdvertisingSets.put(advertiserId, advertisingSet); - callback.onAdvertisingSetStarted(advertisingSet, txPower, status); - } - }); - } - - @Override - public void onOwnAddressRead(int advertiserId, int addressType, String address) { - handler.post(new Runnable() { - @Override - public void run() { - AdvertisingSet advertisingSet = mAdvertisingSets.get(advertiserId); - callback.onOwnAddressRead(advertisingSet, addressType, address); - } - }); - } - - @Override - public void onAdvertisingSetStopped(int advertiserId) { - handler.post(new Runnable() { - @Override - public void run() { - AdvertisingSet advertisingSet = mAdvertisingSets.get(advertiserId); - callback.onAdvertisingSetStopped(advertisingSet); - mAdvertisingSets.remove(advertiserId); - mCallbackWrappers.remove(callback); - } - }); - } - - @Override - public void onAdvertisingEnabled(int advertiserId, boolean enabled, int status) { - handler.post(new Runnable() { - @Override - public void run() { - AdvertisingSet advertisingSet = mAdvertisingSets.get(advertiserId); - callback.onAdvertisingEnabled(advertisingSet, enabled, status); - } - }); - } - - @Override - public void onAdvertisingDataSet(int advertiserId, int status) { - handler.post(new Runnable() { - @Override - public void run() { - AdvertisingSet advertisingSet = mAdvertisingSets.get(advertiserId); - callback.onAdvertisingDataSet(advertisingSet, status); - } - }); - } - - @Override - public void onScanResponseDataSet(int advertiserId, int status) { - handler.post(new Runnable() { - @Override - public void run() { - AdvertisingSet advertisingSet = mAdvertisingSets.get(advertiserId); - callback.onScanResponseDataSet(advertisingSet, status); - } - }); - } - - @Override - public void onAdvertisingParametersUpdated(int advertiserId, int txPower, int status) { - handler.post(new Runnable() { - @Override - public void run() { - AdvertisingSet advertisingSet = mAdvertisingSets.get(advertiserId); - callback.onAdvertisingParametersUpdated(advertisingSet, txPower, status); - } - }); - } - - @Override - public void onPeriodicAdvertisingParametersUpdated(int advertiserId, int status) { - handler.post(new Runnable() { - @Override - public void run() { - AdvertisingSet advertisingSet = mAdvertisingSets.get(advertiserId); - callback.onPeriodicAdvertisingParametersUpdated(advertisingSet, status); - } - }); - } - - @Override - public void onPeriodicAdvertisingDataSet(int advertiserId, int status) { - handler.post(new Runnable() { - @Override - public void run() { - AdvertisingSet advertisingSet = mAdvertisingSets.get(advertiserId); - callback.onPeriodicAdvertisingDataSet(advertisingSet, status); - } - }); - } - - @Override - public void onPeriodicAdvertisingEnabled(int advertiserId, boolean enable, int status) { - handler.post(new Runnable() { - @Override - public void run() { - AdvertisingSet advertisingSet = mAdvertisingSets.get(advertiserId); - callback.onPeriodicAdvertisingEnabled(advertisingSet, enable, status); - } - }); - } - }; - } - - @SuppressLint("AndroidFrameworkBluetoothPermission") - private void postStartSetFailure(Handler handler, final AdvertisingSetCallback callback, - final int error) { - handler.post(new Runnable() { - @Override - public void run() { - callback.onAdvertisingSetStarted(null, 0, error); - } - }); - } - - @SuppressLint("AndroidFrameworkBluetoothPermission") - private void postStartFailure(final AdvertiseCallback callback, final int error) { - mHandler.post(new Runnable() { - @Override - public void run() { - callback.onStartFailure(error); - } - }); - } - - @SuppressLint("AndroidFrameworkBluetoothPermission") - private void postStartSuccess(final AdvertiseCallback callback, - final AdvertiseSettings settings) { - mHandler.post(new Runnable() { - - @Override - public void run() { - callback.onStartSuccess(settings); - } - }); - } -} diff --git a/core/java/android/bluetooth/le/BluetoothLeScanner.java b/core/java/android/bluetooth/le/BluetoothLeScanner.java deleted file mode 100644 index 540e5a778c27a24092ca4b09a71b060daa7c92d6..0000000000000000000000000000000000000000 --- a/core/java/android/bluetooth/le/BluetoothLeScanner.java +++ /dev/null @@ -1,658 +0,0 @@ -/* - * Copyright (C) 2014 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.bluetooth.le; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.annotation.RequiresNoPermission; -import android.annotation.RequiresPermission; -import android.annotation.SuppressLint; -import android.annotation.SystemApi; -import android.app.PendingIntent; -import android.bluetooth.Attributable; -import android.bluetooth.BluetoothAdapter; -import android.bluetooth.BluetoothGatt; -import android.bluetooth.IBluetoothGatt; -import android.bluetooth.IBluetoothManager; -import android.bluetooth.annotations.RequiresBluetoothLocationPermission; -import android.bluetooth.annotations.RequiresBluetoothScanPermission; -import android.bluetooth.annotations.RequiresLegacyBluetoothAdminPermission; -import android.content.AttributionSource; -import android.os.Handler; -import android.os.Looper; -import android.os.RemoteException; -import android.os.WorkSource; -import android.util.Log; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; - -/** - * This class provides methods to perform scan related operations for Bluetooth LE devices. An - * application can scan for a particular type of Bluetooth LE devices using {@link ScanFilter}. It - * can also request different types of callbacks for delivering the result. - *

    - * Use {@link BluetoothAdapter#getBluetoothLeScanner()} to get an instance of - * {@link BluetoothLeScanner}. - * - * @see ScanFilter - */ -public final class BluetoothLeScanner { - - private static final String TAG = "BluetoothLeScanner"; - private static final boolean DBG = true; - private static final boolean VDBG = false; - - /** - * Extra containing a list of ScanResults. It can have one or more results if there was no - * error. In case of error, {@link #EXTRA_ERROR_CODE} will contain the error code and this - * extra will not be available. - */ - public static final String EXTRA_LIST_SCAN_RESULT = - "android.bluetooth.le.extra.LIST_SCAN_RESULT"; - - /** - * Optional extra indicating the error code, if any. The error code will be one of the - * SCAN_FAILED_* codes in {@link ScanCallback}. - */ - public static final String EXTRA_ERROR_CODE = "android.bluetooth.le.extra.ERROR_CODE"; - - /** - * Optional extra indicating the callback type, which will be one of - * CALLBACK_TYPE_* constants in {@link ScanSettings}. - * - * @see ScanCallback#onScanResult(int, ScanResult) - */ - public static final String EXTRA_CALLBACK_TYPE = "android.bluetooth.le.extra.CALLBACK_TYPE"; - - private final BluetoothAdapter mBluetoothAdapter; - private final IBluetoothManager mBluetoothManager; - private final AttributionSource mAttributionSource; - - private final Handler mHandler; - private final Map mLeScanClients; - - /** - * Use {@link BluetoothAdapter#getBluetoothLeScanner()} instead. - * - * @param bluetoothManager BluetoothManager that conducts overall Bluetooth Management. - * @param opPackageName The opPackageName of the context this object was created from - * @param featureId The featureId of the context this object was created from - * @hide - */ - public BluetoothLeScanner(BluetoothAdapter bluetoothAdapter) { - mBluetoothAdapter = Objects.requireNonNull(bluetoothAdapter); - mBluetoothManager = mBluetoothAdapter.getBluetoothManager(); - mAttributionSource = mBluetoothAdapter.getAttributionSource(); - mHandler = new Handler(Looper.getMainLooper()); - mLeScanClients = new HashMap(); - } - - /** - * Start Bluetooth LE scan with default parameters and no filters. The scan results will be - * delivered through {@code callback}. For unfiltered scans, scanning is stopped on screen - * off to save power. Scanning is resumed when screen is turned on again. To avoid this, use - * {@link #startScan(List, ScanSettings, ScanCallback)} with desired {@link ScanFilter}. - *

    - * An app must have - * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION ACCESS_COARSE_LOCATION} permission - * in order to get results. An App targeting Android Q or later must have - * {@link android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION} permission - * in order to get results. - * - * @param callback Callback used to deliver scan results. - * @throws IllegalArgumentException If {@code callback} is null. - */ - @RequiresLegacyBluetoothAdminPermission - @RequiresBluetoothScanPermission - @RequiresBluetoothLocationPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) - public void startScan(final ScanCallback callback) { - startScan(null, new ScanSettings.Builder().build(), callback); - } - - /** - * Start Bluetooth LE scan. The scan results will be delivered through {@code callback}. - * For unfiltered scans, scanning is stopped on screen off to save power. Scanning is - * resumed when screen is turned on again. To avoid this, do filetered scanning by - * using proper {@link ScanFilter}. - *

    - * An app must have - * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION ACCESS_COARSE_LOCATION} permission - * in order to get results. An App targeting Android Q or later must have - * {@link android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION} permission - * in order to get results. - * - * @param filters {@link ScanFilter}s for finding exact BLE devices. - * @param settings Settings for the scan. - * @param callback Callback used to deliver scan results. - * @throws IllegalArgumentException If {@code settings} or {@code callback} is null. - */ - @RequiresLegacyBluetoothAdminPermission - @RequiresBluetoothScanPermission - @RequiresBluetoothLocationPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) - public void startScan(List filters, ScanSettings settings, - final ScanCallback callback) { - startScan(filters, settings, null, callback, /*callbackIntent=*/ null); - } - - /** - * Start Bluetooth LE scan using a {@link PendingIntent}. The scan results will be delivered via - * the PendingIntent. Use this method of scanning if your process is not always running and it - * should be started when scan results are available. - *

    - * An app must have - * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION ACCESS_COARSE_LOCATION} permission - * in order to get results. An App targeting Android Q or later must have - * {@link android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION} permission - * in order to get results. - *

    - * When the PendingIntent is delivered, the Intent passed to the receiver or activity - * will contain one or more of the extras {@link #EXTRA_CALLBACK_TYPE}, - * {@link #EXTRA_ERROR_CODE} and {@link #EXTRA_LIST_SCAN_RESULT} to indicate the result of - * the scan. - * - * @param filters Optional list of ScanFilters for finding exact BLE devices. - * @param settings Optional settings for the scan. - * @param callbackIntent The PendingIntent to deliver the result to. - * @return Returns 0 for success or an error code from {@link ScanCallback} if the scan request - * could not be sent. - * @see #stopScan(PendingIntent) - */ - @RequiresLegacyBluetoothAdminPermission - @RequiresBluetoothScanPermission - @RequiresBluetoothLocationPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) - public int startScan(@Nullable List filters, @Nullable ScanSettings settings, - @NonNull PendingIntent callbackIntent) { - return startScan(filters, - settings != null ? settings : new ScanSettings.Builder().build(), - null, null, callbackIntent); - } - - /** - * Start Bluetooth LE scan. Same as {@link #startScan(ScanCallback)} but allows the caller to - * specify on behalf of which application(s) the work is being done. - * - * @param workSource {@link WorkSource} identifying the application(s) for which to blame for - * the scan. - * @param callback Callback used to deliver scan results. - * @hide - */ - @SystemApi - @RequiresLegacyBluetoothAdminPermission - @RequiresBluetoothScanPermission - @RequiresBluetoothLocationPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_SCAN, - android.Manifest.permission.UPDATE_DEVICE_STATS - }) - public void startScanFromSource(final WorkSource workSource, final ScanCallback callback) { - startScanFromSource(null, new ScanSettings.Builder().build(), workSource, callback); - } - - /** - * Start Bluetooth LE scan. Same as {@link #startScan(List, ScanSettings, ScanCallback)} but - * allows the caller to specify on behalf of which application(s) the work is being done. - * - * @param filters {@link ScanFilter}s for finding exact BLE devices. - * @param settings Settings for the scan. - * @param workSource {@link WorkSource} identifying the application(s) for which to blame for - * the scan. - * @param callback Callback used to deliver scan results. - * @hide - */ - @SystemApi - @RequiresLegacyBluetoothAdminPermission - @RequiresBluetoothScanPermission - @RequiresBluetoothLocationPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_SCAN, - android.Manifest.permission.UPDATE_DEVICE_STATS - }) - @SuppressLint("AndroidFrameworkRequiresPermission") - public void startScanFromSource(List filters, ScanSettings settings, - final WorkSource workSource, final ScanCallback callback) { - startScan(filters, settings, workSource, callback, null); - } - - @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) - private int startScan(List filters, ScanSettings settings, - final WorkSource workSource, final ScanCallback callback, - final PendingIntent callbackIntent) { - BluetoothLeUtils.checkAdapterStateOn(mBluetoothAdapter); - if (callback == null && callbackIntent == null) { - throw new IllegalArgumentException("callback is null"); - } - if (settings == null) { - throw new IllegalArgumentException("settings is null"); - } - synchronized (mLeScanClients) { - if (callback != null && mLeScanClients.containsKey(callback)) { - return postCallbackErrorOrReturn(callback, - ScanCallback.SCAN_FAILED_ALREADY_STARTED); - } - IBluetoothGatt gatt; - try { - gatt = mBluetoothManager.getBluetoothGatt(); - } catch (RemoteException e) { - gatt = null; - } - if (gatt == null) { - return postCallbackErrorOrReturn(callback, ScanCallback.SCAN_FAILED_INTERNAL_ERROR); - } - if (!isSettingsConfigAllowedForScan(settings)) { - return postCallbackErrorOrReturn(callback, - ScanCallback.SCAN_FAILED_FEATURE_UNSUPPORTED); - } - if (!isHardwareResourcesAvailableForScan(settings)) { - return postCallbackErrorOrReturn(callback, - ScanCallback.SCAN_FAILED_OUT_OF_HARDWARE_RESOURCES); - } - if (!isSettingsAndFilterComboAllowed(settings, filters)) { - return postCallbackErrorOrReturn(callback, - ScanCallback.SCAN_FAILED_FEATURE_UNSUPPORTED); - } - if (callback != null) { - BleScanCallbackWrapper wrapper = new BleScanCallbackWrapper(gatt, filters, - settings, workSource, callback); - wrapper.startRegistration(); - } else { - try { - gatt.startScanForIntent(callbackIntent, settings, filters, - mAttributionSource); - } catch (RemoteException e) { - return ScanCallback.SCAN_FAILED_INTERNAL_ERROR; - } - } - } - return ScanCallback.NO_ERROR; - } - - /** - * Stops an ongoing Bluetooth LE scan. - * - * @param callback - */ - @RequiresLegacyBluetoothAdminPermission - @RequiresBluetoothScanPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) - public void stopScan(ScanCallback callback) { - BluetoothLeUtils.checkAdapterStateOn(mBluetoothAdapter); - synchronized (mLeScanClients) { - BleScanCallbackWrapper wrapper = mLeScanClients.remove(callback); - if (wrapper == null) { - if (DBG) Log.d(TAG, "could not find callback wrapper"); - return; - } - wrapper.stopLeScan(); - } - } - - /** - * Stops an ongoing Bluetooth LE scan started using a PendingIntent. When creating the - * PendingIntent parameter, please do not use the FLAG_CANCEL_CURRENT flag. Otherwise, the stop - * scan may have no effect. - * - * @param callbackIntent The PendingIntent that was used to start the scan. - * @see #startScan(List, ScanSettings, PendingIntent) - */ - @RequiresLegacyBluetoothAdminPermission - @RequiresBluetoothScanPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) - public void stopScan(PendingIntent callbackIntent) { - BluetoothLeUtils.checkAdapterStateOn(mBluetoothAdapter); - IBluetoothGatt gatt; - try { - gatt = mBluetoothManager.getBluetoothGatt(); - gatt.stopScanForIntent(callbackIntent, mAttributionSource); - } catch (RemoteException e) { - } - } - - /** - * Flush pending batch scan results stored in Bluetooth controller. This will return Bluetooth - * LE scan results batched on bluetooth controller. Returns immediately, batch scan results data - * will be delivered through the {@code callback}. - * - * @param callback Callback of the Bluetooth LE Scan, it has to be the same instance as the one - * used to start scan. - */ - @RequiresLegacyBluetoothAdminPermission - @RequiresBluetoothScanPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) - public void flushPendingScanResults(ScanCallback callback) { - BluetoothLeUtils.checkAdapterStateOn(mBluetoothAdapter); - if (callback == null) { - throw new IllegalArgumentException("callback cannot be null!"); - } - synchronized (mLeScanClients) { - BleScanCallbackWrapper wrapper = mLeScanClients.get(callback); - if (wrapper == null) { - return; - } - wrapper.flushPendingBatchResults(); - } - } - - /** - * Start truncated scan. - * - * @deprecated this is not used anywhere - * - * @hide - */ - @Deprecated - @SystemApi - @RequiresBluetoothScanPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) - public void startTruncatedScan(List truncatedFilters, ScanSettings settings, - final ScanCallback callback) { - int filterSize = truncatedFilters.size(); - List scanFilters = new ArrayList(filterSize); - for (TruncatedFilter filter : truncatedFilters) { - scanFilters.add(filter.getFilter()); - } - startScan(scanFilters, settings, null, callback, null); - } - - /** - * Cleans up scan clients. Should be called when bluetooth is down. - * - * @hide - */ - @RequiresNoPermission - public void cleanup() { - mLeScanClients.clear(); - } - - /** - * Bluetooth GATT interface callbacks - */ - @SuppressLint("AndroidFrameworkRequiresPermission") - private class BleScanCallbackWrapper extends IScannerCallback.Stub { - private static final int REGISTRATION_CALLBACK_TIMEOUT_MILLIS = 2000; - - private final ScanCallback mScanCallback; - private final List mFilters; - private final WorkSource mWorkSource; - private ScanSettings mSettings; - private IBluetoothGatt mBluetoothGatt; - - // mLeHandle 0: not registered - // -2: registration failed because app is scanning to frequently - // -1: scan stopped or registration failed - // > 0: registered and scan started - private int mScannerId; - - public BleScanCallbackWrapper(IBluetoothGatt bluetoothGatt, - List filters, ScanSettings settings, - WorkSource workSource, ScanCallback scanCallback) { - mBluetoothGatt = bluetoothGatt; - mFilters = filters; - mSettings = settings; - mWorkSource = workSource; - mScanCallback = scanCallback; - mScannerId = 0; - } - - public void startRegistration() { - synchronized (this) { - // Scan stopped. - if (mScannerId == -1 || mScannerId == -2) return; - try { - mBluetoothGatt.registerScanner(this, mWorkSource, mAttributionSource); - wait(REGISTRATION_CALLBACK_TIMEOUT_MILLIS); - } catch (InterruptedException | RemoteException e) { - Log.e(TAG, "application registeration exception", e); - postCallbackError(mScanCallback, ScanCallback.SCAN_FAILED_INTERNAL_ERROR); - } - if (mScannerId > 0) { - mLeScanClients.put(mScanCallback, this); - } else { - // Registration timed out or got exception, reset RscannerId to -1 so no - // subsequent operations can proceed. - if (mScannerId == 0) mScannerId = -1; - - // If scanning too frequently, don't report anything to the app. - if (mScannerId == -2) return; - - postCallbackError(mScanCallback, - ScanCallback.SCAN_FAILED_APPLICATION_REGISTRATION_FAILED); - } - } - } - - @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) - public void stopLeScan() { - synchronized (this) { - if (mScannerId <= 0) { - Log.e(TAG, "Error state, mLeHandle: " + mScannerId); - return; - } - try { - mBluetoothGatt.stopScan(mScannerId, mAttributionSource); - mBluetoothGatt.unregisterScanner(mScannerId, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "Failed to stop scan and unregister", e); - } - mScannerId = -1; - } - } - - @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) - void flushPendingBatchResults() { - synchronized (this) { - if (mScannerId <= 0) { - Log.e(TAG, "Error state, mLeHandle: " + mScannerId); - return; - } - try { - mBluetoothGatt.flushPendingBatchResults(mScannerId, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "Failed to get pending scan results", e); - } - } - } - - /** - * Application interface registered - app is ready to go - */ - @Override - public void onScannerRegistered(int status, int scannerId) { - Log.d(TAG, "onScannerRegistered() - status=" + status - + " scannerId=" + scannerId + " mScannerId=" + mScannerId); - synchronized (this) { - if (status == BluetoothGatt.GATT_SUCCESS) { - try { - if (mScannerId == -1) { - // Registration succeeds after timeout, unregister scanner. - mBluetoothGatt.unregisterScanner(scannerId, mAttributionSource); - } else { - mScannerId = scannerId; - mBluetoothGatt.startScan(mScannerId, mSettings, mFilters, - mAttributionSource); - } - } catch (RemoteException e) { - Log.e(TAG, "fail to start le scan: " + e); - mScannerId = -1; - } - } else if (status == ScanCallback.SCAN_FAILED_SCANNING_TOO_FREQUENTLY) { - // applicaiton was scanning too frequently - mScannerId = -2; - } else { - // registration failed - mScannerId = -1; - } - notifyAll(); - } - } - - /** - * Callback reporting an LE scan result. - * - * @hide - */ - @Override - public void onScanResult(final ScanResult scanResult) { - Attributable.setAttributionSource(scanResult, mAttributionSource); - if (Log.isLoggable(TAG, Log.DEBUG)) { - Log.d(TAG, "onScanResult() - mScannerId=" + mScannerId); - } - if (VDBG) Log.d(TAG, "onScanResult() - " + scanResult.toString()); - - // Check null in case the scan has been stopped - synchronized (this) { - if (mScannerId <= 0) { - if (Log.isLoggable(TAG, Log.DEBUG)) { - Log.d(TAG, "Ignoring result as scan stopped."); - } - return; - }; - } - Handler handler = new Handler(Looper.getMainLooper()); - handler.post(new Runnable() { - @Override - public void run() { - if (Log.isLoggable(TAG, Log.DEBUG)) { - Log.d(TAG, "onScanResult() - handler run"); - } - mScanCallback.onScanResult(ScanSettings.CALLBACK_TYPE_ALL_MATCHES, scanResult); - } - }); - } - - @Override - public void onBatchScanResults(final List results) { - Attributable.setAttributionSource(results, mAttributionSource); - Handler handler = new Handler(Looper.getMainLooper()); - handler.post(new Runnable() { - @Override - public void run() { - mScanCallback.onBatchScanResults(results); - } - }); - } - - @Override - public void onFoundOrLost(final boolean onFound, final ScanResult scanResult) { - Attributable.setAttributionSource(scanResult, mAttributionSource); - if (VDBG) { - Log.d(TAG, "onFoundOrLost() - onFound = " + onFound + " " + scanResult.toString()); - } - - // Check null in case the scan has been stopped - synchronized (this) { - if (mScannerId <= 0) { - return; - } - } - Handler handler = new Handler(Looper.getMainLooper()); - handler.post(new Runnable() { - @Override - public void run() { - if (onFound) { - mScanCallback.onScanResult(ScanSettings.CALLBACK_TYPE_FIRST_MATCH, - scanResult); - } else { - mScanCallback.onScanResult(ScanSettings.CALLBACK_TYPE_MATCH_LOST, - scanResult); - } - } - }); - } - - @Override - public void onScanManagerErrorCallback(final int errorCode) { - if (VDBG) { - Log.d(TAG, "onScanManagerErrorCallback() - errorCode = " + errorCode); - } - synchronized (this) { - if (mScannerId <= 0) { - return; - } - } - postCallbackError(mScanCallback, errorCode); - } - } - - private int postCallbackErrorOrReturn(final ScanCallback callback, final int errorCode) { - if (callback == null) { - return errorCode; - } else { - postCallbackError(callback, errorCode); - return ScanCallback.NO_ERROR; - } - } - - @SuppressLint("AndroidFrameworkBluetoothPermission") - private void postCallbackError(final ScanCallback callback, final int errorCode) { - mHandler.post(new Runnable() { - @Override - public void run() { - callback.onScanFailed(errorCode); - } - }); - } - - private boolean isSettingsConfigAllowedForScan(ScanSettings settings) { - if (mBluetoothAdapter.isOffloadedFilteringSupported()) { - return true; - } - final int callbackType = settings.getCallbackType(); - // Only support regular scan if no offloaded filter support. - if (callbackType == ScanSettings.CALLBACK_TYPE_ALL_MATCHES - && settings.getReportDelayMillis() == 0) { - return true; - } - return false; - } - - private boolean isSettingsAndFilterComboAllowed(ScanSettings settings, - List filterList) { - final int callbackType = settings.getCallbackType(); - // If onlost/onfound is requested, a non-empty filter is expected - if ((callbackType & (ScanSettings.CALLBACK_TYPE_FIRST_MATCH - | ScanSettings.CALLBACK_TYPE_MATCH_LOST)) != 0) { - if (filterList == null) { - return false; - } - for (ScanFilter filter : filterList) { - if (filter.isAllFieldsEmpty()) { - return false; - } - } - } - return true; - } - - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - private boolean isHardwareResourcesAvailableForScan(ScanSettings settings) { - final int callbackType = settings.getCallbackType(); - if ((callbackType & ScanSettings.CALLBACK_TYPE_FIRST_MATCH) != 0 - || (callbackType & ScanSettings.CALLBACK_TYPE_MATCH_LOST) != 0) { - // For onlost/onfound, we required hw support be available - return (mBluetoothAdapter.isOffloadedFilteringSupported() - && mBluetoothAdapter.isHardwareTrackingFiltersAvailable()); - } - return true; - } -} diff --git a/core/java/android/bluetooth/le/BluetoothLeUtils.java b/core/java/android/bluetooth/le/BluetoothLeUtils.java deleted file mode 100644 index ed50b09597bb618141fd13aaf4813a7c77a5417b..0000000000000000000000000000000000000000 --- a/core/java/android/bluetooth/le/BluetoothLeUtils.java +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Copyright (C) 2014 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.bluetooth.le; - -import android.bluetooth.BluetoothAdapter; -import android.util.SparseArray; - -import java.util.Arrays; -import java.util.Iterator; -import java.util.Map; -import java.util.Objects; -import java.util.Set; -import java.util.UUID; - -/** - * Helper class for Bluetooth LE utils. - * - * @hide - */ -public class BluetoothLeUtils { - - /** - * Returns a string composed from a {@link SparseArray}. - */ - static String toString(SparseArray array) { - if (array == null) { - return "null"; - } - if (array.size() == 0) { - return "{}"; - } - StringBuilder buffer = new StringBuilder(); - buffer.append('{'); - for (int i = 0; i < array.size(); ++i) { - buffer.append(array.keyAt(i)).append("=").append(Arrays.toString(array.valueAt(i))); - } - buffer.append('}'); - return buffer.toString(); - } - - /** - * Returns a string composed from a {@link Map}. - */ - static String toString(Map map) { - if (map == null) { - return "null"; - } - if (map.isEmpty()) { - return "{}"; - } - StringBuilder buffer = new StringBuilder(); - buffer.append('{'); - Iterator> it = map.entrySet().iterator(); - while (it.hasNext()) { - Map.Entry entry = it.next(); - Object key = entry.getKey(); - buffer.append(key).append("=").append(Arrays.toString(map.get(key))); - if (it.hasNext()) { - buffer.append(", "); - } - } - buffer.append('}'); - return buffer.toString(); - } - - /** - * Check whether two {@link SparseArray} equal. - */ - static boolean equals(SparseArray array, SparseArray otherArray) { - if (array == otherArray) { - return true; - } - if (array == null || otherArray == null) { - return false; - } - if (array.size() != otherArray.size()) { - return false; - } - - // Keys are guaranteed in ascending order when indices are in ascending order. - for (int i = 0; i < array.size(); ++i) { - if (array.keyAt(i) != otherArray.keyAt(i) - || !Arrays.equals(array.valueAt(i), otherArray.valueAt(i))) { - return false; - } - } - return true; - } - - /** - * Check whether two {@link Map} equal. - */ - static boolean equals(Map map, Map otherMap) { - if (map == otherMap) { - return true; - } - if (map == null || otherMap == null) { - return false; - } - if (map.size() != otherMap.size()) { - return false; - } - Set keys = map.keySet(); - if (!keys.equals(otherMap.keySet())) { - return false; - } - for (T key : keys) { - if (!Objects.deepEquals(map.get(key), otherMap.get(key))) { - return false; - } - } - return true; - } - - /** - * Ensure Bluetooth is turned on. - * - * @throws IllegalStateException If {@code adapter} is null or Bluetooth state is not {@link - * BluetoothAdapter#STATE_ON}. - */ - static void checkAdapterStateOn(BluetoothAdapter adapter) { - if (adapter == null || !adapter.isLeEnabled()) { - throw new IllegalStateException("BT Adapter is not turned ON"); - } - } - - /** - * Compares two UUIDs with a UUID mask. - * - * @param data first {@link #UUID} to compare. - * @param uuid second {@link #UUID} to compare. - * @param mask mask {@link #UUID}. - * @return true if both UUIDs are equals when masked, false otherwise. - */ - static boolean maskedEquals(UUID data, UUID uuid, UUID mask) { - if (mask == null) { - return Objects.equals(data, uuid); - } - return (data.getLeastSignificantBits() & mask.getLeastSignificantBits()) - == (uuid.getLeastSignificantBits() & mask.getLeastSignificantBits()) - && (data.getMostSignificantBits() & mask.getMostSignificantBits()) - == (uuid.getMostSignificantBits() & mask.getMostSignificantBits()); - } -} diff --git a/core/java/android/bluetooth/le/OWNERS b/core/java/android/bluetooth/le/OWNERS deleted file mode 100644 index 3523ee0640abef4f6c6a1a3c735ccecb7fe499c3..0000000000000000000000000000000000000000 --- a/core/java/android/bluetooth/le/OWNERS +++ /dev/null @@ -1,4 +0,0 @@ -# Bug component: 27441 - -zachoverflow@google.com -siyuanh@google.com diff --git a/core/java/android/bluetooth/le/PeriodicAdvertisingCallback.java b/core/java/android/bluetooth/le/PeriodicAdvertisingCallback.java deleted file mode 100644 index 14ac911fcb7f317d8dc0f92d9f7cf3d00ecb229a..0000000000000000000000000000000000000000 --- a/core/java/android/bluetooth/le/PeriodicAdvertisingCallback.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (C) 2017 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.bluetooth.le; - -import android.bluetooth.BluetoothDevice; - -/** - * Bluetooth LE periodic advertising callbacks, used to deliver periodic - * advertising operation status. - * - * @hide - * @see PeriodicAdvertisingManager#createSync - */ -public abstract class PeriodicAdvertisingCallback { - - /** - * The requested operation was successful. - * - * @hide - */ - public static final int SYNC_SUCCESS = 0; - - /** - * Sync failed to be established because remote device did not respond. - */ - public static final int SYNC_NO_RESPONSE = 1; - - /** - * Sync failed to be established because controller can't support more syncs. - */ - public static final int SYNC_NO_RESOURCES = 2; - - - /** - * Callback when synchronization was established. - * - * @param syncHandle handle used to identify this synchronization. - * @param device remote device. - * @param advertisingSid synchronized advertising set id. - * @param skip The number of periodic advertising packets that can be skipped after a successful - * receive in force. @see PeriodicAdvertisingManager#createSync - * @param timeout Synchronization timeout for the periodic advertising in force. One unit is - * 10ms. @see PeriodicAdvertisingManager#createSync - * @param timeout - * @param status operation status. - */ - public void onSyncEstablished(int syncHandle, BluetoothDevice device, - int advertisingSid, int skip, int timeout, - int status) { - } - - /** - * Callback when periodic advertising report is received. - * - * @param report periodic advertising report. - */ - public void onPeriodicAdvertisingReport(PeriodicAdvertisingReport report) { - } - - /** - * Callback when periodic advertising synchronization was lost. - * - * @param syncHandle handle used to identify this synchronization. - */ - public void onSyncLost(int syncHandle) { - } -} diff --git a/core/java/android/bluetooth/le/PeriodicAdvertisingManager.java b/core/java/android/bluetooth/le/PeriodicAdvertisingManager.java deleted file mode 100644 index bbd31170bb412233a9646f21e7d75663c12da5b8..0000000000000000000000000000000000000000 --- a/core/java/android/bluetooth/le/PeriodicAdvertisingManager.java +++ /dev/null @@ -1,264 +0,0 @@ -/* - * Copyright (C) 2017 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.bluetooth.le; - -import android.annotation.RequiresPermission; -import android.annotation.SuppressLint; -import android.bluetooth.Attributable; -import android.bluetooth.BluetoothAdapter; -import android.bluetooth.BluetoothDevice; -import android.bluetooth.IBluetoothGatt; -import android.bluetooth.IBluetoothManager; -import android.bluetooth.annotations.RequiresBluetoothLocationPermission; -import android.bluetooth.annotations.RequiresBluetoothScanPermission; -import android.bluetooth.annotations.RequiresLegacyBluetoothAdminPermission; -import android.content.AttributionSource; -import android.os.Handler; -import android.os.Looper; -import android.os.RemoteException; -import android.util.Log; - -import java.util.IdentityHashMap; -import java.util.Map; -import java.util.Objects; - -/** - * This class provides methods to perform periodic advertising related - * operations. An application can register for periodic advertisements using - * {@link PeriodicAdvertisingManager#registerSync}. - *

    - * Use {@link BluetoothAdapter#getPeriodicAdvertisingManager()} to get an - * instance of {@link PeriodicAdvertisingManager}. - * - * @hide - */ -public final class PeriodicAdvertisingManager { - - private static final String TAG = "PeriodicAdvertisingManager"; - - private static final int SKIP_MIN = 0; - private static final int SKIP_MAX = 499; - private static final int TIMEOUT_MIN = 10; - private static final int TIMEOUT_MAX = 16384; - - private static final int SYNC_STARTING = -1; - - private final BluetoothAdapter mBluetoothAdapter; - private final IBluetoothManager mBluetoothManager; - private final AttributionSource mAttributionSource; - - /* maps callback, to callback wrapper and sync handle */ - Map mCallbackWrappers; - - /** - * Use {@link BluetoothAdapter#getBluetoothLeScanner()} instead. - * - * @param bluetoothManager BluetoothManager that conducts overall Bluetooth Management. - * @hide - */ - public PeriodicAdvertisingManager(BluetoothAdapter bluetoothAdapter) { - mBluetoothAdapter = Objects.requireNonNull(bluetoothAdapter); - mBluetoothManager = mBluetoothAdapter.getBluetoothManager(); - mAttributionSource = mBluetoothAdapter.getAttributionSource(); - mCallbackWrappers = new IdentityHashMap<>(); - } - - /** - * Synchronize with periodic advertising pointed to by the {@code scanResult}. - * The {@code scanResult} used must contain a valid advertisingSid. First - * call to registerSync will use the {@code skip} and {@code timeout} provided. - * Subsequent calls from other apps, trying to sync with same set will reuse - * existing sync, thus {@code skip} and {@code timeout} values will not take - * effect. The values in effect will be returned in - * {@link PeriodicAdvertisingCallback#onSyncEstablished}. - * - * @param scanResult Scan result containing advertisingSid. - * @param skip The number of periodic advertising packets that can be skipped after a successful - * receive. Must be between 0 and 499. - * @param timeout Synchronization timeout for the periodic advertising. One unit is 10ms. Must - * be between 10 (100ms) and 16384 (163.84s). - * @param callback Callback used to deliver all operations status. - * @throws IllegalArgumentException if {@code scanResult} is null or {@code skip} is invalid or - * {@code timeout} is invalid or {@code callback} is null. - */ - @RequiresLegacyBluetoothAdminPermission - @RequiresBluetoothScanPermission - @RequiresBluetoothLocationPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) - public void registerSync(ScanResult scanResult, int skip, int timeout, - PeriodicAdvertisingCallback callback) { - registerSync(scanResult, skip, timeout, callback, null); - } - - /** - * Synchronize with periodic advertising pointed to by the {@code scanResult}. - * The {@code scanResult} used must contain a valid advertisingSid. First - * call to registerSync will use the {@code skip} and {@code timeout} provided. - * Subsequent calls from other apps, trying to sync with same set will reuse - * existing sync, thus {@code skip} and {@code timeout} values will not take - * effect. The values in effect will be returned in - * {@link PeriodicAdvertisingCallback#onSyncEstablished}. - * - * @param scanResult Scan result containing advertisingSid. - * @param skip The number of periodic advertising packets that can be skipped after a successful - * receive. Must be between 0 and 499. - * @param timeout Synchronization timeout for the periodic advertising. One unit is 10ms. Must - * be between 10 (100ms) and 16384 (163.84s). - * @param callback Callback used to deliver all operations status. - * @param handler thread upon which the callbacks will be invoked. - * @throws IllegalArgumentException if {@code scanResult} is null or {@code skip} is invalid or - * {@code timeout} is invalid or {@code callback} is null. - */ - @RequiresLegacyBluetoothAdminPermission - @RequiresBluetoothScanPermission - @RequiresBluetoothLocationPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) - public void registerSync(ScanResult scanResult, int skip, int timeout, - PeriodicAdvertisingCallback callback, Handler handler) { - if (callback == null) { - throw new IllegalArgumentException("callback can't be null"); - } - - if (scanResult == null) { - throw new IllegalArgumentException("scanResult can't be null"); - } - - if (scanResult.getAdvertisingSid() == ScanResult.SID_NOT_PRESENT) { - throw new IllegalArgumentException("scanResult must contain a valid sid"); - } - - if (skip < SKIP_MIN || skip > SKIP_MAX) { - throw new IllegalArgumentException( - "timeout must be between " + TIMEOUT_MIN + " and " + TIMEOUT_MAX); - } - - if (timeout < TIMEOUT_MIN || timeout > TIMEOUT_MAX) { - throw new IllegalArgumentException( - "timeout must be between " + TIMEOUT_MIN + " and " + TIMEOUT_MAX); - } - - IBluetoothGatt gatt; - try { - gatt = mBluetoothManager.getBluetoothGatt(); - } catch (RemoteException e) { - Log.e(TAG, "Failed to get Bluetooth gatt - ", e); - callback.onSyncEstablished(0, scanResult.getDevice(), scanResult.getAdvertisingSid(), - skip, timeout, - PeriodicAdvertisingCallback.SYNC_NO_RESOURCES); - return; - } - - if (handler == null) { - handler = new Handler(Looper.getMainLooper()); - } - - IPeriodicAdvertisingCallback wrapped = wrap(callback, handler); - mCallbackWrappers.put(callback, wrapped); - - try { - gatt.registerSync( - scanResult, skip, timeout, wrapped, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "Failed to register sync - ", e); - return; - } - } - - /** - * Cancel pending attempt to create sync, or terminate existing sync. - * - * @param callback Callback used to deliver all operations status. - * @throws IllegalArgumentException if {@code callback} is null, or not a properly registered - * callback. - */ - @RequiresLegacyBluetoothAdminPermission - @RequiresBluetoothScanPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) - public void unregisterSync(PeriodicAdvertisingCallback callback) { - if (callback == null) { - throw new IllegalArgumentException("callback can't be null"); - } - - IBluetoothGatt gatt; - try { - gatt = mBluetoothManager.getBluetoothGatt(); - } catch (RemoteException e) { - Log.e(TAG, "Failed to get Bluetooth gatt - ", e); - return; - } - - IPeriodicAdvertisingCallback wrapper = mCallbackWrappers.remove(callback); - if (wrapper == null) { - throw new IllegalArgumentException("callback was not properly registered"); - } - - try { - gatt.unregisterSync(wrapper, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "Failed to cancel sync creation - ", e); - return; - } - } - - @SuppressLint("AndroidFrameworkBluetoothPermission") - private IPeriodicAdvertisingCallback wrap(PeriodicAdvertisingCallback callback, - Handler handler) { - return new IPeriodicAdvertisingCallback.Stub() { - public void onSyncEstablished(int syncHandle, BluetoothDevice device, - int advertisingSid, int skip, int timeout, int status) { - Attributable.setAttributionSource(device, mAttributionSource); - handler.post(new Runnable() { - @Override - public void run() { - callback.onSyncEstablished(syncHandle, device, advertisingSid, skip, - timeout, - status); - - if (status != PeriodicAdvertisingCallback.SYNC_SUCCESS) { - // App can still unregister the sync until notified it failed. Remove - // callback - // after app was notifed. - mCallbackWrappers.remove(callback); - } - } - }); - } - - public void onPeriodicAdvertisingReport(PeriodicAdvertisingReport report) { - handler.post(new Runnable() { - @Override - public void run() { - callback.onPeriodicAdvertisingReport(report); - } - }); - } - - public void onSyncLost(int syncHandle) { - handler.post(new Runnable() { - @Override - public void run() { - callback.onSyncLost(syncHandle); - // App can still unregister the sync until notified it's lost. - // Remove callback after app was notifed. - mCallbackWrappers.remove(callback); - } - }); - } - }; - } -} diff --git a/core/java/android/bluetooth/le/PeriodicAdvertisingParameters.java b/core/java/android/bluetooth/le/PeriodicAdvertisingParameters.java deleted file mode 100644 index 4e64dbed7017b3e8fbaa71b09e1d14c1a57d1d7e..0000000000000000000000000000000000000000 --- a/core/java/android/bluetooth/le/PeriodicAdvertisingParameters.java +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright (C) 2017 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.bluetooth.le; - -import android.os.Parcel; -import android.os.Parcelable; - -/** - * The {@link PeriodicAdvertisingParameters} provide a way to adjust periodic - * advertising preferences for each Bluetooth LE advertising set. Use {@link - * PeriodicAdvertisingParameters.Builder} to create an instance of this class. - */ -public final class PeriodicAdvertisingParameters implements Parcelable { - - private static final int INTERVAL_MIN = 80; - private static final int INTERVAL_MAX = 65519; - - private final boolean mIncludeTxPower; - private final int mInterval; - - private PeriodicAdvertisingParameters(boolean includeTxPower, int interval) { - mIncludeTxPower = includeTxPower; - mInterval = interval; - } - - private PeriodicAdvertisingParameters(Parcel in) { - mIncludeTxPower = in.readInt() != 0; - mInterval = in.readInt(); - } - - /** - * Returns whether the TX Power will be included. - */ - public boolean getIncludeTxPower() { - return mIncludeTxPower; - } - - /** - * Returns the periodic advertising interval, in 1.25ms unit. - * Valid values are from 80 (100ms) to 65519 (81.89875s). - */ - public int getInterval() { - return mInterval; - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeInt(mIncludeTxPower ? 1 : 0); - dest.writeInt(mInterval); - } - - public static final Parcelable - .Creator CREATOR = - new Creator() { - @Override - public PeriodicAdvertisingParameters[] newArray(int size) { - return new PeriodicAdvertisingParameters[size]; - } - - @Override - public PeriodicAdvertisingParameters createFromParcel(Parcel in) { - return new PeriodicAdvertisingParameters(in); - } - }; - - public static final class Builder { - private boolean mIncludeTxPower = false; - private int mInterval = INTERVAL_MAX; - - /** - * Whether the transmission power level should be included in the periodic - * packet. - */ - public Builder setIncludeTxPower(boolean includeTxPower) { - mIncludeTxPower = includeTxPower; - return this; - } - - /** - * Set advertising interval for periodic advertising, in 1.25ms unit. - * Valid values are from 80 (100ms) to 65519 (81.89875s). - * Value from range [interval, interval+20ms] will be picked as the actual value. - * - * @throws IllegalArgumentException If the interval is invalid. - */ - public Builder setInterval(int interval) { - if (interval < INTERVAL_MIN || interval > INTERVAL_MAX) { - throw new IllegalArgumentException("Invalid interval (must be " + INTERVAL_MIN - + "-" + INTERVAL_MAX + ")"); - } - mInterval = interval; - return this; - } - - /** - * Build the {@link AdvertisingSetParameters} object. - */ - public PeriodicAdvertisingParameters build() { - return new PeriodicAdvertisingParameters(mIncludeTxPower, mInterval); - } - } -} diff --git a/core/java/android/bluetooth/le/PeriodicAdvertisingReport.java b/core/java/android/bluetooth/le/PeriodicAdvertisingReport.java deleted file mode 100644 index 54b953c25c277493c81433d7ad8593afa1d110d8..0000000000000000000000000000000000000000 --- a/core/java/android/bluetooth/le/PeriodicAdvertisingReport.java +++ /dev/null @@ -1,186 +0,0 @@ -/* - * Copyright (C) 2017 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.bluetooth.le; - -import android.annotation.Nullable; -import android.os.Parcel; -import android.os.Parcelable; - -import java.util.Objects; - -/** - * PeriodicAdvertisingReport for Bluetooth LE synchronized advertising. - * - * @hide - */ -public final class PeriodicAdvertisingReport implements Parcelable { - - /** - * The data returned is complete - */ - public static final int DATA_COMPLETE = 0; - - /** - * The data returned is incomplete. The controller was unsuccessfull to - * receive all chained packets, returning only partial data. - */ - public static final int DATA_INCOMPLETE_TRUNCATED = 2; - - private int mSyncHandle; - private int mTxPower; - private int mRssi; - private int mDataStatus; - - // periodic advertising data. - @Nullable - private ScanRecord mData; - - // Device timestamp when the result was last seen. - private long mTimestampNanos; - - /** - * Constructor of periodic advertising result. - */ - public PeriodicAdvertisingReport(int syncHandle, int txPower, int rssi, - int dataStatus, ScanRecord data) { - mSyncHandle = syncHandle; - mTxPower = txPower; - mRssi = rssi; - mDataStatus = dataStatus; - mData = data; - } - - private PeriodicAdvertisingReport(Parcel in) { - readFromParcel(in); - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeInt(mSyncHandle); - dest.writeInt(mTxPower); - dest.writeInt(mRssi); - dest.writeInt(mDataStatus); - if (mData != null) { - dest.writeInt(1); - dest.writeByteArray(mData.getBytes()); - } else { - dest.writeInt(0); - } - } - - private void readFromParcel(Parcel in) { - mSyncHandle = in.readInt(); - mTxPower = in.readInt(); - mRssi = in.readInt(); - mDataStatus = in.readInt(); - if (in.readInt() == 1) { - mData = ScanRecord.parseFromBytes(in.createByteArray()); - } - } - - @Override - public int describeContents() { - return 0; - } - - /** - * Returns the synchronization handle. - */ - public int getSyncHandle() { - return mSyncHandle; - } - - /** - * Returns the transmit power in dBm. The valid range is [-127, 126]. Value - * of 127 means information was not available. - */ - public int getTxPower() { - return mTxPower; - } - - /** - * Returns the received signal strength in dBm. The valid range is [-127, 20]. - */ - public int getRssi() { - return mRssi; - } - - /** - * Returns the data status. Can be one of {@link PeriodicAdvertisingReport#DATA_COMPLETE} - * or {@link PeriodicAdvertisingReport#DATA_INCOMPLETE_TRUNCATED}. - */ - public int getDataStatus() { - return mDataStatus; - } - - /** - * Returns the data contained in this periodic advertising report. - */ - @Nullable - public ScanRecord getData() { - return mData; - } - - /** - * Returns timestamp since boot when the scan record was observed. - */ - public long getTimestampNanos() { - return mTimestampNanos; - } - - @Override - public int hashCode() { - return Objects.hash(mSyncHandle, mTxPower, mRssi, mDataStatus, mData, mTimestampNanos); - } - - @Override - public boolean equals(@Nullable Object obj) { - if (this == obj) { - return true; - } - if (obj == null || getClass() != obj.getClass()) { - return false; - } - PeriodicAdvertisingReport other = (PeriodicAdvertisingReport) obj; - return (mSyncHandle == other.mSyncHandle) - && (mTxPower == other.mTxPower) - && (mRssi == other.mRssi) - && (mDataStatus == other.mDataStatus) - && Objects.equals(mData, other.mData) - && (mTimestampNanos == other.mTimestampNanos); - } - - @Override - public String toString() { - return "PeriodicAdvertisingReport{syncHandle=" + mSyncHandle - + ", txPower=" + mTxPower + ", rssi=" + mRssi + ", dataStatus=" + mDataStatus - + ", data=" + Objects.toString(mData) + ", timestampNanos=" + mTimestampNanos + '}'; - } - - public static final @android.annotation.NonNull Parcelable.Creator CREATOR = - new Creator() { - @Override - public PeriodicAdvertisingReport createFromParcel(Parcel source) { - return new PeriodicAdvertisingReport(source); - } - - @Override - public PeriodicAdvertisingReport[] newArray(int size) { - return new PeriodicAdvertisingReport[size]; - } - }; -} diff --git a/core/java/android/bluetooth/le/ResultStorageDescriptor.java b/core/java/android/bluetooth/le/ResultStorageDescriptor.java deleted file mode 100644 index f65048975deb56763292c9826b8ed04979ab7cab..0000000000000000000000000000000000000000 --- a/core/java/android/bluetooth/le/ResultStorageDescriptor.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright (C) 2014 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.bluetooth.le; - -import android.annotation.SystemApi; -import android.os.Parcel; -import android.os.Parcelable; - -/** - * Describes the way to store scan result. - * - * @deprecated this is not used anywhere - * - * @hide - */ -@Deprecated -@SystemApi -public final class ResultStorageDescriptor implements Parcelable { - private int mType; - private int mOffset; - private int mLength; - - public int getType() { - return mType; - } - - public int getOffset() { - return mOffset; - } - - public int getLength() { - return mLength; - } - - /** - * Constructor of {@link ResultStorageDescriptor} - * - * @param type Type of the data. - * @param offset Offset from start of the advertise packet payload. - * @param length Byte length of the data - */ - public ResultStorageDescriptor(int type, int offset, int length) { - mType = type; - mOffset = offset; - mLength = length; - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeInt(mType); - dest.writeInt(mOffset); - dest.writeInt(mLength); - } - - private ResultStorageDescriptor(Parcel in) { - ReadFromParcel(in); - } - - private void ReadFromParcel(Parcel in) { - mType = in.readInt(); - mOffset = in.readInt(); - mLength = in.readInt(); - } - - public static final @android.annotation.NonNull Parcelable.Creator CREATOR = - new Creator() { - @Override - public ResultStorageDescriptor createFromParcel(Parcel source) { - return new ResultStorageDescriptor(source); - } - - @Override - public ResultStorageDescriptor[] newArray(int size) { - return new ResultStorageDescriptor[size]; - } - }; -} diff --git a/core/java/android/bluetooth/le/ScanCallback.java b/core/java/android/bluetooth/le/ScanCallback.java deleted file mode 100644 index 53d9310a12366fd9f42df67e3df1dacdddfa6750..0000000000000000000000000000000000000000 --- a/core/java/android/bluetooth/le/ScanCallback.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (C) 2014 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.bluetooth.le; - -import java.util.List; - -/** - * Bluetooth LE scan callbacks. Scan results are reported using these callbacks. - * - * @see BluetoothLeScanner#startScan - */ -public abstract class ScanCallback { - /** - * Fails to start scan as BLE scan with the same settings is already started by the app. - */ - public static final int SCAN_FAILED_ALREADY_STARTED = 1; - - /** - * Fails to start scan as app cannot be registered. - */ - public static final int SCAN_FAILED_APPLICATION_REGISTRATION_FAILED = 2; - - /** - * Fails to start scan due an internal error - */ - public static final int SCAN_FAILED_INTERNAL_ERROR = 3; - - /** - * Fails to start power optimized scan as this feature is not supported. - */ - public static final int SCAN_FAILED_FEATURE_UNSUPPORTED = 4; - - /** - * Fails to start scan as it is out of hardware resources. - * - * @hide - */ - public static final int SCAN_FAILED_OUT_OF_HARDWARE_RESOURCES = 5; - - /** - * Fails to start scan as application tries to scan too frequently. - * @hide - */ - public static final int SCAN_FAILED_SCANNING_TOO_FREQUENTLY = 6; - - static final int NO_ERROR = 0; - - /** - * Callback when a BLE advertisement has been found. - * - * @param callbackType Determines how this callback was triggered. Could be one of {@link - * ScanSettings#CALLBACK_TYPE_ALL_MATCHES}, {@link ScanSettings#CALLBACK_TYPE_FIRST_MATCH} or - * {@link ScanSettings#CALLBACK_TYPE_MATCH_LOST} - * @param result A Bluetooth LE scan result. - */ - public void onScanResult(int callbackType, ScanResult result) { - } - - /** - * Callback when batch results are delivered. - * - * @param results List of scan results that are previously scanned. - */ - public void onBatchScanResults(List results) { - } - - /** - * Callback when scan could not be started. - * - * @param errorCode Error code (one of SCAN_FAILED_*) for scan failure. - */ - public void onScanFailed(int errorCode) { - } -} diff --git a/core/java/android/bluetooth/le/ScanFilter.java b/core/java/android/bluetooth/le/ScanFilter.java deleted file mode 100644 index b059193ae03fd559733201f2afec849bc63ee54a..0000000000000000000000000000000000000000 --- a/core/java/android/bluetooth/le/ScanFilter.java +++ /dev/null @@ -1,910 +0,0 @@ -/* - * Copyright (C) 2014 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.bluetooth.le; - -import static java.util.Objects.requireNonNull; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.annotation.SystemApi; -import android.bluetooth.BluetoothAdapter; -import android.bluetooth.BluetoothDevice; -import android.bluetooth.BluetoothDevice.AddressType; -import android.os.Parcel; -import android.os.ParcelUuid; -import android.os.Parcelable; - -import java.util.Arrays; -import java.util.List; -import java.util.Objects; -import java.util.UUID; - -/** - * Criteria for filtering result from Bluetooth LE scans. A {@link ScanFilter} allows clients to - * restrict scan results to only those that are of interest to them. - *

    - * Current filtering on the following fields are supported: - *

  • Service UUIDs which identify the bluetooth gatt services running on the device. - *
  • Name of remote Bluetooth LE device. - *
  • Mac address of the remote device. - *
  • Service data which is the data associated with a service. - *
  • Manufacturer specific data which is the data associated with a particular manufacturer. - * - * @see ScanResult - * @see BluetoothLeScanner - */ -public final class ScanFilter implements Parcelable { - - @Nullable - private final String mDeviceName; - - @Nullable - private final String mDeviceAddress; - - private final @AddressType int mAddressType; - - @Nullable - private final byte[] mIrk; - - @Nullable - private final ParcelUuid mServiceUuid; - @Nullable - private final ParcelUuid mServiceUuidMask; - - @Nullable - private final ParcelUuid mServiceSolicitationUuid; - @Nullable - private final ParcelUuid mServiceSolicitationUuidMask; - - @Nullable - private final ParcelUuid mServiceDataUuid; - @Nullable - private final byte[] mServiceData; - @Nullable - private final byte[] mServiceDataMask; - - private final int mManufacturerId; - @Nullable - private final byte[] mManufacturerData; - @Nullable - private final byte[] mManufacturerDataMask; - - /** @hide */ - public static final ScanFilter EMPTY = new ScanFilter.Builder().build(); - - private ScanFilter(String name, String deviceAddress, ParcelUuid uuid, - ParcelUuid uuidMask, ParcelUuid solicitationUuid, - ParcelUuid solicitationUuidMask, ParcelUuid serviceDataUuid, - byte[] serviceData, byte[] serviceDataMask, - int manufacturerId, byte[] manufacturerData, byte[] manufacturerDataMask, - @AddressType int addressType, @Nullable byte[] irk) { - mDeviceName = name; - mServiceUuid = uuid; - mServiceUuidMask = uuidMask; - mServiceSolicitationUuid = solicitationUuid; - mServiceSolicitationUuidMask = solicitationUuidMask; - mDeviceAddress = deviceAddress; - mServiceDataUuid = serviceDataUuid; - mServiceData = serviceData; - mServiceDataMask = serviceDataMask; - mManufacturerId = manufacturerId; - mManufacturerData = manufacturerData; - mManufacturerDataMask = manufacturerDataMask; - mAddressType = addressType; - mIrk = irk; - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeInt(mDeviceName == null ? 0 : 1); - if (mDeviceName != null) { - dest.writeString(mDeviceName); - } - dest.writeInt(mDeviceAddress == null ? 0 : 1); - if (mDeviceAddress != null) { - dest.writeString(mDeviceAddress); - } - dest.writeInt(mServiceUuid == null ? 0 : 1); - if (mServiceUuid != null) { - dest.writeParcelable(mServiceUuid, flags); - dest.writeInt(mServiceUuidMask == null ? 0 : 1); - if (mServiceUuidMask != null) { - dest.writeParcelable(mServiceUuidMask, flags); - } - } - dest.writeInt(mServiceSolicitationUuid == null ? 0 : 1); - if (mServiceSolicitationUuid != null) { - dest.writeParcelable(mServiceSolicitationUuid, flags); - dest.writeInt(mServiceSolicitationUuidMask == null ? 0 : 1); - if (mServiceSolicitationUuidMask != null) { - dest.writeParcelable(mServiceSolicitationUuidMask, flags); - } - } - dest.writeInt(mServiceDataUuid == null ? 0 : 1); - if (mServiceDataUuid != null) { - dest.writeParcelable(mServiceDataUuid, flags); - dest.writeInt(mServiceData == null ? 0 : 1); - if (mServiceData != null) { - dest.writeInt(mServiceData.length); - dest.writeByteArray(mServiceData); - - dest.writeInt(mServiceDataMask == null ? 0 : 1); - if (mServiceDataMask != null) { - dest.writeInt(mServiceDataMask.length); - dest.writeByteArray(mServiceDataMask); - } - } - } - dest.writeInt(mManufacturerId); - dest.writeInt(mManufacturerData == null ? 0 : 1); - if (mManufacturerData != null) { - dest.writeInt(mManufacturerData.length); - dest.writeByteArray(mManufacturerData); - - dest.writeInt(mManufacturerDataMask == null ? 0 : 1); - if (mManufacturerDataMask != null) { - dest.writeInt(mManufacturerDataMask.length); - dest.writeByteArray(mManufacturerDataMask); - } - } - - // IRK - if (mDeviceAddress != null) { - dest.writeInt(mAddressType); - dest.writeInt(mIrk == null ? 0 : 1); - if (mIrk != null) { - dest.writeByteArray(mIrk); - } - } - } - - /** - * A {@link android.os.Parcelable.Creator} to create {@link ScanFilter} from parcel. - */ - public static final @android.annotation.NonNull Creator CREATOR = - new Creator() { - - @Override - public ScanFilter[] newArray(int size) { - return new ScanFilter[size]; - } - - @Override - public ScanFilter createFromParcel(Parcel in) { - Builder builder = new Builder(); - if (in.readInt() == 1) { - builder.setDeviceName(in.readString()); - } - String address = null; - // If we have a non-null address - if (in.readInt() == 1) { - address = in.readString(); - } - if (in.readInt() == 1) { - ParcelUuid uuid = in.readParcelable(ParcelUuid.class.getClassLoader()); - builder.setServiceUuid(uuid); - if (in.readInt() == 1) { - ParcelUuid uuidMask = in.readParcelable( - ParcelUuid.class.getClassLoader()); - builder.setServiceUuid(uuid, uuidMask); - } - } - if (in.readInt() == 1) { - ParcelUuid solicitationUuid = in.readParcelable( - ParcelUuid.class.getClassLoader()); - builder.setServiceSolicitationUuid(solicitationUuid); - if (in.readInt() == 1) { - ParcelUuid solicitationUuidMask = in.readParcelable( - ParcelUuid.class.getClassLoader()); - builder.setServiceSolicitationUuid(solicitationUuid, - solicitationUuidMask); - } - } - if (in.readInt() == 1) { - ParcelUuid servcieDataUuid = - in.readParcelable(ParcelUuid.class.getClassLoader()); - if (in.readInt() == 1) { - int serviceDataLength = in.readInt(); - byte[] serviceData = new byte[serviceDataLength]; - in.readByteArray(serviceData); - if (in.readInt() == 0) { - builder.setServiceData(servcieDataUuid, serviceData); - } else { - int serviceDataMaskLength = in.readInt(); - byte[] serviceDataMask = new byte[serviceDataMaskLength]; - in.readByteArray(serviceDataMask); - builder.setServiceData( - servcieDataUuid, serviceData, serviceDataMask); - } - } - } - - int manufacturerId = in.readInt(); - if (in.readInt() == 1) { - int manufacturerDataLength = in.readInt(); - byte[] manufacturerData = new byte[manufacturerDataLength]; - in.readByteArray(manufacturerData); - if (in.readInt() == 0) { - builder.setManufacturerData(manufacturerId, manufacturerData); - } else { - int manufacturerDataMaskLength = in.readInt(); - byte[] manufacturerDataMask = new byte[manufacturerDataMaskLength]; - in.readByteArray(manufacturerDataMask); - builder.setManufacturerData(manufacturerId, manufacturerData, - manufacturerDataMask); - } - } - - // IRK - if (address != null) { - final int addressType = in.readInt(); - if (in.readInt() == 1) { - final byte[] irk = new byte[16]; - in.readByteArray(irk); - builder.setDeviceAddress(address, addressType, irk); - } else { - builder.setDeviceAddress(address, addressType); - } - } - return builder.build(); - } - }; - - /** - * Returns the filter set the device name field of Bluetooth advertisement data. - */ - @Nullable - public String getDeviceName() { - return mDeviceName; - } - - /** - * Returns the filter set on the service uuid. - */ - @Nullable - public ParcelUuid getServiceUuid() { - return mServiceUuid; - } - - @Nullable - public ParcelUuid getServiceUuidMask() { - return mServiceUuidMask; - } - - /** - * Returns the filter set on the service Solicitation uuid. - */ - @Nullable - public ParcelUuid getServiceSolicitationUuid() { - return mServiceSolicitationUuid; - } - - /** - * Returns the filter set on the service Solicitation uuid mask. - */ - @Nullable - public ParcelUuid getServiceSolicitationUuidMask() { - return mServiceSolicitationUuidMask; - } - - @Nullable - public String getDeviceAddress() { - return mDeviceAddress; - } - - /** - * @hide - */ - @SystemApi - public @AddressType int getAddressType() { - return mAddressType; - } - - /** - * @hide - */ - @SystemApi - @Nullable - public byte[] getIrk() { - return mIrk; - } - - @Nullable - public byte[] getServiceData() { - return mServiceData; - } - - @Nullable - public byte[] getServiceDataMask() { - return mServiceDataMask; - } - - @Nullable - public ParcelUuid getServiceDataUuid() { - return mServiceDataUuid; - } - - /** - * Returns the manufacturer id. -1 if the manufacturer filter is not set. - */ - public int getManufacturerId() { - return mManufacturerId; - } - - @Nullable - public byte[] getManufacturerData() { - return mManufacturerData; - } - - @Nullable - public byte[] getManufacturerDataMask() { - return mManufacturerDataMask; - } - - /** - * Check if the scan filter matches a {@code scanResult}. A scan result is considered as a match - * if it matches all the field filters. - */ - public boolean matches(ScanResult scanResult) { - if (scanResult == null) { - return false; - } - BluetoothDevice device = scanResult.getDevice(); - // Device match. - if (mDeviceAddress != null - && (device == null || !mDeviceAddress.equals(device.getAddress()))) { - return false; - } - - ScanRecord scanRecord = scanResult.getScanRecord(); - - // Scan record is null but there exist filters on it. - if (scanRecord == null - && (mDeviceName != null || mServiceUuid != null || mManufacturerData != null - || mServiceData != null || mServiceSolicitationUuid != null)) { - return false; - } - - // Local name match. - if (mDeviceName != null && !mDeviceName.equals(scanRecord.getDeviceName())) { - return false; - } - - // UUID match. - if (mServiceUuid != null && !matchesServiceUuids(mServiceUuid, mServiceUuidMask, - scanRecord.getServiceUuids())) { - return false; - } - - // solicitation UUID match. - if (mServiceSolicitationUuid != null && !matchesServiceSolicitationUuids( - mServiceSolicitationUuid, mServiceSolicitationUuidMask, - scanRecord.getServiceSolicitationUuids())) { - return false; - } - - // Service data match - if (mServiceDataUuid != null) { - if (!matchesPartialData(mServiceData, mServiceDataMask, - scanRecord.getServiceData(mServiceDataUuid))) { - return false; - } - } - - // Manufacturer data match. - if (mManufacturerId >= 0) { - if (!matchesPartialData(mManufacturerData, mManufacturerDataMask, - scanRecord.getManufacturerSpecificData(mManufacturerId))) { - return false; - } - } - // All filters match. - return true; - } - - /** - * Check if the uuid pattern is contained in a list of parcel uuids. - * - * @hide - */ - public static boolean matchesServiceUuids(ParcelUuid uuid, ParcelUuid parcelUuidMask, - List uuids) { - if (uuid == null) { - return true; - } - if (uuids == null) { - return false; - } - - for (ParcelUuid parcelUuid : uuids) { - UUID uuidMask = parcelUuidMask == null ? null : parcelUuidMask.getUuid(); - if (matchesServiceUuid(uuid.getUuid(), uuidMask, parcelUuid.getUuid())) { - return true; - } - } - return false; - } - - // Check if the uuid pattern matches the particular service uuid. - private static boolean matchesServiceUuid(UUID uuid, UUID mask, UUID data) { - return BluetoothLeUtils.maskedEquals(data, uuid, mask); - } - - /** - * Check if the solicitation uuid pattern is contained in a list of parcel uuids. - * - */ - private static boolean matchesServiceSolicitationUuids(ParcelUuid solicitationUuid, - ParcelUuid parcelSolicitationUuidMask, List solicitationUuids) { - if (solicitationUuid == null) { - return true; - } - if (solicitationUuids == null) { - return false; - } - - for (ParcelUuid parcelSolicitationUuid : solicitationUuids) { - UUID solicitationUuidMask = parcelSolicitationUuidMask == null - ? null : parcelSolicitationUuidMask.getUuid(); - if (matchesServiceUuid(solicitationUuid.getUuid(), solicitationUuidMask, - parcelSolicitationUuid.getUuid())) { - return true; - } - } - return false; - } - - // Check if the solicitation uuid pattern matches the particular service solicitation uuid. - private static boolean matchesServiceSolicitationUuid(UUID solicitationUuid, - UUID solicitationUuidMask, UUID data) { - return BluetoothLeUtils.maskedEquals(data, solicitationUuid, solicitationUuidMask); - } - - // Check whether the data pattern matches the parsed data. - private boolean matchesPartialData(byte[] data, byte[] dataMask, byte[] parsedData) { - if (parsedData == null || parsedData.length < data.length) { - return false; - } - if (dataMask == null) { - for (int i = 0; i < data.length; ++i) { - if (parsedData[i] != data[i]) { - return false; - } - } - return true; - } - for (int i = 0; i < data.length; ++i) { - if ((dataMask[i] & parsedData[i]) != (dataMask[i] & data[i])) { - return false; - } - } - return true; - } - - @Override - public String toString() { - return "BluetoothLeScanFilter [mDeviceName=" + mDeviceName + ", mDeviceAddress=" - + mDeviceAddress - + ", mUuid=" + mServiceUuid + ", mUuidMask=" + mServiceUuidMask - + ", mServiceSolicitationUuid=" + mServiceSolicitationUuid - + ", mServiceSolicitationUuidMask=" + mServiceSolicitationUuidMask - + ", mServiceDataUuid=" + Objects.toString(mServiceDataUuid) + ", mServiceData=" - + Arrays.toString(mServiceData) + ", mServiceDataMask=" - + Arrays.toString(mServiceDataMask) + ", mManufacturerId=" + mManufacturerId - + ", mManufacturerData=" + Arrays.toString(mManufacturerData) - + ", mManufacturerDataMask=" + Arrays.toString(mManufacturerDataMask) + "]"; - } - - @Override - public int hashCode() { - return Objects.hash(mDeviceName, mDeviceAddress, mManufacturerId, - Arrays.hashCode(mManufacturerData), - Arrays.hashCode(mManufacturerDataMask), - mServiceDataUuid, - Arrays.hashCode(mServiceData), - Arrays.hashCode(mServiceDataMask), - mServiceUuid, mServiceUuidMask, - mServiceSolicitationUuid, mServiceSolicitationUuidMask); - } - - @Override - public boolean equals(@Nullable Object obj) { - if (this == obj) { - return true; - } - if (obj == null || getClass() != obj.getClass()) { - return false; - } - ScanFilter other = (ScanFilter) obj; - return Objects.equals(mDeviceName, other.mDeviceName) - && Objects.equals(mDeviceAddress, other.mDeviceAddress) - && mManufacturerId == other.mManufacturerId - && Objects.deepEquals(mManufacturerData, other.mManufacturerData) - && Objects.deepEquals(mManufacturerDataMask, other.mManufacturerDataMask) - && Objects.equals(mServiceDataUuid, other.mServiceDataUuid) - && Objects.deepEquals(mServiceData, other.mServiceData) - && Objects.deepEquals(mServiceDataMask, other.mServiceDataMask) - && Objects.equals(mServiceUuid, other.mServiceUuid) - && Objects.equals(mServiceUuidMask, other.mServiceUuidMask) - && Objects.equals(mServiceSolicitationUuid, other.mServiceSolicitationUuid) - && Objects.equals(mServiceSolicitationUuidMask, - other.mServiceSolicitationUuidMask); - } - - /** - * Checks if the scanfilter is empty - * - * @hide - */ - public boolean isAllFieldsEmpty() { - return EMPTY.equals(this); - } - - /** - * Builder class for {@link ScanFilter}. - */ - public static final class Builder { - - /** - * @hide - */ - @SystemApi - public static final int LEN_IRK_OCTETS = 16; - - private String mDeviceName; - private String mDeviceAddress; - private @AddressType int mAddressType = BluetoothDevice.ADDRESS_TYPE_PUBLIC; - private byte[] mIrk; - - private ParcelUuid mServiceUuid; - private ParcelUuid mUuidMask; - - private ParcelUuid mServiceSolicitationUuid; - private ParcelUuid mServiceSolicitationUuidMask; - - private ParcelUuid mServiceDataUuid; - private byte[] mServiceData; - private byte[] mServiceDataMask; - - private int mManufacturerId = -1; - private byte[] mManufacturerData; - private byte[] mManufacturerDataMask; - - /** - * Set filter on device name. - */ - public Builder setDeviceName(String deviceName) { - mDeviceName = deviceName; - return this; - } - - /** - * Set filter on device address. - * - * @param deviceAddress The device Bluetooth address for the filter. It needs to be in the - * format of "01:02:03:AB:CD:EF". The device address can be validated using {@link - * BluetoothAdapter#checkBluetoothAddress}. The @AddressType is defaulted to {@link - * BluetoothDevice#ADDRESS_TYPE_PUBLIC} - * @throws IllegalArgumentException If the {@code deviceAddress} is invalid. - */ - public Builder setDeviceAddress(String deviceAddress) { - if (deviceAddress == null) { - mDeviceAddress = deviceAddress; - return this; - } - return setDeviceAddress(deviceAddress, BluetoothDevice.ADDRESS_TYPE_PUBLIC); - } - - /** - * Set filter on Address with AddressType - * - *

    This key is used to resolve a private address from a public address. - * - * @param deviceAddress The device Bluetooth address for the filter. It needs to be in the - * format of "01:02:03:AB:CD:EF". The device address can be validated using {@link - * BluetoothAdapter#checkBluetoothAddress}. May be any type of address. - * @param addressType indication of the type of address - * e.g. {@link BluetoothDevice#ADDRESS_TYPE_PUBLIC} - * or {@link BluetoothDevice#ADDRESS_TYPE_RANDOM} - * - * @throws IllegalArgumentException If the {@code deviceAddress} is invalid. - * @throws IllegalArgumentException If the {@code addressType} is invalid length - * @throws NullPointerException if {@code deviceAddress} is null. - * - * @hide - */ - @NonNull - @SystemApi - public Builder setDeviceAddress(@NonNull String deviceAddress, - @AddressType int addressType) { - return setDeviceAddressInternal(deviceAddress, addressType, null); - } - - /** - * Set filter on Address with AddressType and the Identity Resolving Key (IRK). - * - *

    The IRK is used to resolve a {@link BluetoothDevice#ADDRESS_TYPE_PUBLIC} from - * a PRIVATE_ADDRESS type. - * - * @param deviceAddress The device Bluetooth address for the filter. It needs to be in the - * format of "01:02:03:AB:CD:EF". The device address can be validated using {@link - * BluetoothAdapter#checkBluetoothAddress}. This Address type must only be PUBLIC OR RANDOM - * STATIC. - * @param addressType indication of the type of address - * e.g. {@link BluetoothDevice#ADDRESS_TYPE_PUBLIC} - * or {@link BluetoothDevice#ADDRESS_TYPE_RANDOM} - * @param irk non-null byte array representing the Identity Resolving Key - * - * @throws IllegalArgumentException If the {@code deviceAddress} is invalid. - * @throws IllegalArgumentException if the {@code irk} is invalid length. - * @throws IllegalArgumentException If the {@code addressType} is invalid length or is not - * PUBLIC or RANDOM STATIC when an IRK is present. - * @throws NullPointerException if {@code deviceAddress} or {@code irk} is null. - * - * @hide - */ - @NonNull - @SystemApi - public Builder setDeviceAddress(@NonNull String deviceAddress, - @AddressType int addressType, - @NonNull byte[] irk) { - requireNonNull(irk); - if (irk.length != LEN_IRK_OCTETS) { - throw new IllegalArgumentException("'irk' is invalid length!"); - } - return setDeviceAddressInternal(deviceAddress, addressType, irk); - } - - /** - * Set filter on Address with AddressType and the Identity Resolving Key (IRK). - * - *

    Internal setter for the device address - * - * @param deviceAddress The device Bluetooth address for the filter. It needs to be in the - * format of "01:02:03:AB:CD:EF". The device address can be validated using {@link - * BluetoothAdapter#checkBluetoothAddress}. - * @param addressType indication of the type of address - * e.g. {@link BluetoothDevice#ADDRESS_TYPE_PUBLIC} - * @param irk non-null byte array representing the Identity Resolving Address; nullable - * internally. - * - * @throws IllegalArgumentException If the {@code deviceAddress} is invalid. - * @throws IllegalArgumentException If the {@code addressType} is invalid length. - * @throws NullPointerException if {@code deviceAddress} is null. - * - * @hide - */ - @NonNull - private Builder setDeviceAddressInternal(@NonNull String deviceAddress, - @AddressType int addressType, - @Nullable byte[] irk) { - - // Make sure our deviceAddress is valid! - requireNonNull(deviceAddress); - if (!BluetoothAdapter.checkBluetoothAddress(deviceAddress)) { - throw new IllegalArgumentException("invalid device address " + deviceAddress); - } - - // Verify type range - if (addressType < BluetoothDevice.ADDRESS_TYPE_PUBLIC - || addressType > BluetoothDevice.ADDRESS_TYPE_RANDOM) { - throw new IllegalArgumentException("'addressType' is invalid!"); - } - - // IRK can only be used for a PUBLIC or RANDOM (STATIC) Address. - if (addressType == BluetoothDevice.ADDRESS_TYPE_RANDOM) { - // Don't want a bad combination of address and irk! - if (irk != null) { - // Since there are 3 possible RANDOM subtypes we must check to make sure - // the correct type of address is used. - if (!BluetoothAdapter.isAddressRandomStatic(deviceAddress)) { - throw new IllegalArgumentException( - "Invalid combination: IRK requires either a PUBLIC or " - + "RANDOM (STATIC) Address"); - } - } - } - - // PUBLIC doesn't require extra work - // Without an IRK any address may be accepted - - mDeviceAddress = deviceAddress; - mAddressType = addressType; - mIrk = irk; - return this; - } - - /** - * Set filter on service uuid. - */ - public Builder setServiceUuid(ParcelUuid serviceUuid) { - mServiceUuid = serviceUuid; - mUuidMask = null; // clear uuid mask - return this; - } - - /** - * Set filter on partial service uuid. The {@code uuidMask} is the bit mask for the - * {@code serviceUuid}. Set any bit in the mask to 1 to indicate a match is needed for the - * bit in {@code serviceUuid}, and 0 to ignore that bit. - * - * @throws IllegalArgumentException If {@code serviceUuid} is {@code null} but {@code - * uuidMask} is not {@code null}. - */ - public Builder setServiceUuid(ParcelUuid serviceUuid, ParcelUuid uuidMask) { - if (mUuidMask != null && mServiceUuid == null) { - throw new IllegalArgumentException("uuid is null while uuidMask is not null!"); - } - mServiceUuid = serviceUuid; - mUuidMask = uuidMask; - return this; - } - - - /** - * Set filter on service solicitation uuid. - */ - public @NonNull Builder setServiceSolicitationUuid( - @Nullable ParcelUuid serviceSolicitationUuid) { - mServiceSolicitationUuid = serviceSolicitationUuid; - if (serviceSolicitationUuid == null) { - mServiceSolicitationUuidMask = null; - } - return this; - } - - - /** - * Set filter on partial service Solicitation uuid. The {@code SolicitationUuidMask} is the - * bit mask for the {@code serviceSolicitationUuid}. Set any bit in the mask to 1 to - * indicate a match is needed for the bit in {@code serviceSolicitationUuid}, and 0 to - * ignore that bit. - * - * @param serviceSolicitationUuid can only be null if solicitationUuidMask is null. - * @param solicitationUuidMask can be null or a mask with no restriction. - * - * @throws IllegalArgumentException If {@code serviceSolicitationUuid} is {@code null} but - * {@code serviceSolicitationUuidMask} is not {@code null}. - */ - public @NonNull Builder setServiceSolicitationUuid( - @Nullable ParcelUuid serviceSolicitationUuid, - @Nullable ParcelUuid solicitationUuidMask) { - if (solicitationUuidMask != null && serviceSolicitationUuid == null) { - throw new IllegalArgumentException( - "SolicitationUuid is null while SolicitationUuidMask is not null!"); - } - mServiceSolicitationUuid = serviceSolicitationUuid; - mServiceSolicitationUuidMask = solicitationUuidMask; - return this; - } - - /** - * Set filtering on service data. - * - * @throws IllegalArgumentException If {@code serviceDataUuid} is null. - */ - public Builder setServiceData(ParcelUuid serviceDataUuid, byte[] serviceData) { - if (serviceDataUuid == null) { - throw new IllegalArgumentException("serviceDataUuid is null"); - } - mServiceDataUuid = serviceDataUuid; - mServiceData = serviceData; - mServiceDataMask = null; // clear service data mask - return this; - } - - /** - * Set partial filter on service data. For any bit in the mask, set it to 1 if it needs to - * match the one in service data, otherwise set it to 0 to ignore that bit. - *

    - * The {@code serviceDataMask} must have the same length of the {@code serviceData}. - * - * @throws IllegalArgumentException If {@code serviceDataUuid} is null or {@code - * serviceDataMask} is {@code null} while {@code serviceData} is not or {@code - * serviceDataMask} and {@code serviceData} has different length. - */ - public Builder setServiceData(ParcelUuid serviceDataUuid, - byte[] serviceData, byte[] serviceDataMask) { - if (serviceDataUuid == null) { - throw new IllegalArgumentException("serviceDataUuid is null"); - } - if (mServiceDataMask != null) { - if (mServiceData == null) { - throw new IllegalArgumentException( - "serviceData is null while serviceDataMask is not null"); - } - // Since the mServiceDataMask is a bit mask for mServiceData, the lengths of the two - // byte array need to be the same. - if (mServiceData.length != mServiceDataMask.length) { - throw new IllegalArgumentException( - "size mismatch for service data and service data mask"); - } - } - mServiceDataUuid = serviceDataUuid; - mServiceData = serviceData; - mServiceDataMask = serviceDataMask; - return this; - } - - /** - * Set filter on on manufacturerData. A negative manufacturerId is considered as invalid id. - * - * @throws IllegalArgumentException If the {@code manufacturerId} is invalid. - */ - public Builder setManufacturerData(int manufacturerId, byte[] manufacturerData) { - if (manufacturerData != null && manufacturerId < 0) { - throw new IllegalArgumentException("invalid manufacture id"); - } - mManufacturerId = manufacturerId; - mManufacturerData = manufacturerData; - mManufacturerDataMask = null; // clear manufacturer data mask - return this; - } - - /** - * Set filter on partial manufacture data. For any bit in the mask, set it the 1 if it needs - * to match the one in manufacturer data, otherwise set it to 0. - *

    - * The {@code manufacturerDataMask} must have the same length of {@code manufacturerData}. - * - * @throws IllegalArgumentException If the {@code manufacturerId} is invalid, or {@code - * manufacturerData} is null while {@code manufacturerDataMask} is not, or {@code - * manufacturerData} and {@code manufacturerDataMask} have different length. - */ - public Builder setManufacturerData(int manufacturerId, byte[] manufacturerData, - byte[] manufacturerDataMask) { - if (manufacturerData != null && manufacturerId < 0) { - throw new IllegalArgumentException("invalid manufacture id"); - } - if (mManufacturerDataMask != null) { - if (mManufacturerData == null) { - throw new IllegalArgumentException( - "manufacturerData is null while manufacturerDataMask is not null"); - } - // Since the mManufacturerDataMask is a bit mask for mManufacturerData, the lengths - // of the two byte array need to be the same. - if (mManufacturerData.length != mManufacturerDataMask.length) { - throw new IllegalArgumentException( - "size mismatch for manufacturerData and manufacturerDataMask"); - } - } - mManufacturerId = manufacturerId; - mManufacturerData = manufacturerData; - mManufacturerDataMask = manufacturerDataMask; - return this; - } - - /** - * Build {@link ScanFilter}. - * - * @throws IllegalArgumentException If the filter cannot be built. - */ - public ScanFilter build() { - return new ScanFilter(mDeviceName, mDeviceAddress, - mServiceUuid, mUuidMask, mServiceSolicitationUuid, - mServiceSolicitationUuidMask, - mServiceDataUuid, mServiceData, mServiceDataMask, - mManufacturerId, mManufacturerData, mManufacturerDataMask, - mAddressType, mIrk); - } - } -} diff --git a/core/java/android/bluetooth/le/ScanRecord.java b/core/java/android/bluetooth/le/ScanRecord.java deleted file mode 100644 index 9b8c2eaf4d197afd2ccd29d4dc1f81788645152c..0000000000000000000000000000000000000000 --- a/core/java/android/bluetooth/le/ScanRecord.java +++ /dev/null @@ -1,378 +0,0 @@ -/* - * Copyright (C) 2014 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.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; -import android.util.ArrayMap; -import android.util.Log; -import android.util.SparseArray; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Map; -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"; - - // The following data type values are assigned by Bluetooth SIG. - // For more details refer to Bluetooth 4.1 specification, Volume 3, Part C, Section 18. - private static final int DATA_TYPE_FLAGS = 0x01; - private static final int DATA_TYPE_SERVICE_UUIDS_16_BIT_PARTIAL = 0x02; - private static final int DATA_TYPE_SERVICE_UUIDS_16_BIT_COMPLETE = 0x03; - private static final int DATA_TYPE_SERVICE_UUIDS_32_BIT_PARTIAL = 0x04; - private static final int DATA_TYPE_SERVICE_UUIDS_32_BIT_COMPLETE = 0x05; - private static final int DATA_TYPE_SERVICE_UUIDS_128_BIT_PARTIAL = 0x06; - private static final int DATA_TYPE_SERVICE_UUIDS_128_BIT_COMPLETE = 0x07; - private static final int DATA_TYPE_LOCAL_NAME_SHORT = 0x08; - private static final int DATA_TYPE_LOCAL_NAME_COMPLETE = 0x09; - private static final int DATA_TYPE_TX_POWER_LEVEL = 0x0A; - private static final int DATA_TYPE_SERVICE_DATA_16_BIT = 0x16; - private static final int DATA_TYPE_SERVICE_DATA_32_BIT = 0x20; - private static final int DATA_TYPE_SERVICE_DATA_128_BIT = 0x21; - private static final int DATA_TYPE_SERVICE_SOLICITATION_UUIDS_16_BIT = 0x14; - private static final int DATA_TYPE_SERVICE_SOLICITATION_UUIDS_32_BIT = 0x1F; - private static final int DATA_TYPE_SERVICE_SOLICITATION_UUIDS_128_BIT = 0x15; - private static final int DATA_TYPE_MANUFACTURER_SPECIFIC_DATA = 0xFF; - - // Flags of the advertising data. - private final int mAdvertiseFlags; - - @Nullable - private final List mServiceUuids; - @Nullable - private final List mServiceSolicitationUuids; - - private final SparseArray mManufacturerSpecificData; - - private final Map mServiceData; - - // Transmission power level(in dB). - private final int mTxPowerLevel; - - // Local name of the Bluetooth LE device. - private final String mDeviceName; - - // Raw bytes of scan record. - private final byte[] mBytes; - - /** - * Returns the advertising flags indicating the discoverable mode and capability of the device. - * Returns -1 if the flag field is not set. - */ - public int getAdvertiseFlags() { - return mAdvertiseFlags; - } - - /** - * Returns a list of service UUIDs within the advertisement that are used to identify the - * bluetooth GATT services. - */ - public List getServiceUuids() { - return mServiceUuids; - } - - /** - * Returns a list of service solicitation UUIDs within the advertisement that are used to - * identify the Bluetooth GATT services. - */ - @NonNull - public List getServiceSolicitationUuids() { - return mServiceSolicitationUuids; - } - - /** - * Returns a sparse array of manufacturer identifier and its corresponding manufacturer specific - * data. - */ - public SparseArray getManufacturerSpecificData() { - return mManufacturerSpecificData; - } - - /** - * Returns the manufacturer specific data associated with the manufacturer id. Returns - * {@code null} if the {@code manufacturerId} is not found. - */ - @Nullable - public byte[] getManufacturerSpecificData(int manufacturerId) { - if (mManufacturerSpecificData == null) { - return null; - } - return mManufacturerSpecificData.get(manufacturerId); - } - - /** - * Returns a map of service UUID and its corresponding service data. - */ - public Map getServiceData() { - return mServiceData; - } - - /** - * Returns the service data byte array associated with the {@code serviceUuid}. Returns - * {@code null} if the {@code serviceDataUuid} is not found. - */ - @Nullable - public byte[] getServiceData(ParcelUuid serviceDataUuid) { - if (serviceDataUuid == null || mServiceData == null) { - return null; - } - return mServiceData.get(serviceDataUuid); - } - - /** - * Returns the transmission power level of the packet in dBm. Returns {@link Integer#MIN_VALUE} - * if the field is not set. This value can be used to calculate the path loss of a received - * packet using the following equation: - *

    - * pathloss = txPowerLevel - rssi - */ - public int getTxPowerLevel() { - return mTxPowerLevel; - } - - /** - * Returns the local name of the BLE device. This is a UTF-8 encoded string. - */ - @Nullable - public String getDeviceName() { - return mDeviceName; - } - - /** - * Returns raw bytes of scan record. - */ - public byte[] getBytes() { - return mBytes; - } - - /** - * Test if any fields contained inside this scan record are matched by the - * given matcher. - * - * @hide - */ - public boolean matchesAnyField(@NonNull Predicate matcher) { - int pos = 0; - while (pos < mBytes.length) { - final int length = mBytes[pos] & 0xFF; - if (length == 0) { - break; - } - if (matcher.test(Arrays.copyOfRange(mBytes, pos, pos + length + 1))) { - return true; - } - pos += length + 1; - } - return false; - } - - private ScanRecord(List serviceUuids, - List serviceSolicitationUuids, - SparseArray manufacturerData, - Map serviceData, - int advertiseFlags, int txPowerLevel, - String localName, byte[] bytes) { - mServiceSolicitationUuids = serviceSolicitationUuids; - mServiceUuids = serviceUuids; - mManufacturerSpecificData = manufacturerData; - mServiceData = serviceData; - mDeviceName = localName; - mAdvertiseFlags = advertiseFlags; - mTxPowerLevel = txPowerLevel; - mBytes = bytes; - } - - /** - * Parse scan record bytes to {@link ScanRecord}. - *

    - * The format is defined in Bluetooth 4.1 specification, Volume 3, Part C, Section 11 and 18. - *

    - * All numerical multi-byte entities and values shall use little-endian byte - * order. - * - * @param scanRecord The scan record of Bluetooth LE advertisement and/or scan response. - * @hide - */ - @UnsupportedAppUsage - public static ScanRecord parseFromBytes(byte[] scanRecord) { - if (scanRecord == null) { - return null; - } - - int currentPos = 0; - int advertiseFlag = -1; - List serviceUuids = new ArrayList(); - List serviceSolicitationUuids = new ArrayList(); - String localName = null; - int txPowerLevel = Integer.MIN_VALUE; - - SparseArray manufacturerData = new SparseArray(); - Map serviceData = new ArrayMap(); - - try { - while (currentPos < scanRecord.length) { - // length is unsigned int. - int length = scanRecord[currentPos++] & 0xFF; - if (length == 0) { - break; - } - // Note the length includes the length of the field type itself. - int dataLength = length - 1; - // fieldType is unsigned int. - int fieldType = scanRecord[currentPos++] & 0xFF; - switch (fieldType) { - case DATA_TYPE_FLAGS: - advertiseFlag = scanRecord[currentPos] & 0xFF; - break; - case DATA_TYPE_SERVICE_UUIDS_16_BIT_PARTIAL: - case DATA_TYPE_SERVICE_UUIDS_16_BIT_COMPLETE: - parseServiceUuid(scanRecord, currentPos, - dataLength, BluetoothUuid.UUID_BYTES_16_BIT, serviceUuids); - break; - case DATA_TYPE_SERVICE_UUIDS_32_BIT_PARTIAL: - case DATA_TYPE_SERVICE_UUIDS_32_BIT_COMPLETE: - parseServiceUuid(scanRecord, currentPos, dataLength, - BluetoothUuid.UUID_BYTES_32_BIT, serviceUuids); - break; - case DATA_TYPE_SERVICE_UUIDS_128_BIT_PARTIAL: - case DATA_TYPE_SERVICE_UUIDS_128_BIT_COMPLETE: - parseServiceUuid(scanRecord, currentPos, dataLength, - BluetoothUuid.UUID_BYTES_128_BIT, serviceUuids); - break; - case DATA_TYPE_SERVICE_SOLICITATION_UUIDS_16_BIT: - parseServiceSolicitationUuid(scanRecord, currentPos, dataLength, - BluetoothUuid.UUID_BYTES_16_BIT, serviceSolicitationUuids); - break; - case DATA_TYPE_SERVICE_SOLICITATION_UUIDS_32_BIT: - parseServiceSolicitationUuid(scanRecord, currentPos, dataLength, - BluetoothUuid.UUID_BYTES_32_BIT, serviceSolicitationUuids); - break; - case DATA_TYPE_SERVICE_SOLICITATION_UUIDS_128_BIT: - parseServiceSolicitationUuid(scanRecord, currentPos, dataLength, - BluetoothUuid.UUID_BYTES_128_BIT, serviceSolicitationUuids); - break; - case DATA_TYPE_LOCAL_NAME_SHORT: - case DATA_TYPE_LOCAL_NAME_COMPLETE: - localName = new String( - extractBytes(scanRecord, currentPos, dataLength)); - break; - case DATA_TYPE_TX_POWER_LEVEL: - txPowerLevel = scanRecord[currentPos]; - break; - case DATA_TYPE_SERVICE_DATA_16_BIT: - case DATA_TYPE_SERVICE_DATA_32_BIT: - case DATA_TYPE_SERVICE_DATA_128_BIT: - int serviceUuidLength = BluetoothUuid.UUID_BYTES_16_BIT; - if (fieldType == DATA_TYPE_SERVICE_DATA_32_BIT) { - serviceUuidLength = BluetoothUuid.UUID_BYTES_32_BIT; - } else if (fieldType == DATA_TYPE_SERVICE_DATA_128_BIT) { - serviceUuidLength = BluetoothUuid.UUID_BYTES_128_BIT; - } - - byte[] serviceDataUuidBytes = extractBytes(scanRecord, currentPos, - serviceUuidLength); - ParcelUuid serviceDataUuid = BluetoothUuid.parseUuidFrom( - serviceDataUuidBytes); - byte[] serviceDataArray = extractBytes(scanRecord, - currentPos + serviceUuidLength, dataLength - serviceUuidLength); - serviceData.put(serviceDataUuid, serviceDataArray); - break; - case DATA_TYPE_MANUFACTURER_SPECIFIC_DATA: - // The first two bytes of the manufacturer specific data are - // manufacturer ids in little endian. - int manufacturerId = ((scanRecord[currentPos + 1] & 0xFF) << 8) - + (scanRecord[currentPos] & 0xFF); - byte[] manufacturerDataBytes = extractBytes(scanRecord, currentPos + 2, - dataLength - 2); - manufacturerData.put(manufacturerId, manufacturerDataBytes); - break; - default: - // Just ignore, we don't handle such data type. - break; - } - currentPos += dataLength; - } - - if (serviceUuids.isEmpty()) { - serviceUuids = null; - } - return new ScanRecord(serviceUuids, serviceSolicitationUuids, manufacturerData, - serviceData, advertiseFlag, txPowerLevel, localName, scanRecord); - } catch (Exception e) { - Log.e(TAG, "unable to parse scan record: " + Arrays.toString(scanRecord)); - // As the record is invalid, ignore all the parsed results for this packet - // and return an empty record with raw scanRecord bytes in results - return new ScanRecord(null, null, null, null, -1, Integer.MIN_VALUE, null, scanRecord); - } - } - - @Override - public String toString() { - return "ScanRecord [mAdvertiseFlags=" + mAdvertiseFlags + ", mServiceUuids=" + mServiceUuids - + ", mServiceSolicitationUuids=" + mServiceSolicitationUuids - + ", mManufacturerSpecificData=" + BluetoothLeUtils.toString( - mManufacturerSpecificData) - + ", mServiceData=" + BluetoothLeUtils.toString(mServiceData) - + ", mTxPowerLevel=" + mTxPowerLevel + ", mDeviceName=" + mDeviceName + "]"; - } - - // Parse service UUIDs. - private static int parseServiceUuid(byte[] scanRecord, int currentPos, int dataLength, - int uuidLength, List serviceUuids) { - while (dataLength > 0) { - byte[] uuidBytes = extractBytes(scanRecord, currentPos, - uuidLength); - serviceUuids.add(BluetoothUuid.parseUuidFrom(uuidBytes)); - dataLength -= uuidLength; - currentPos += uuidLength; - } - return currentPos; - } - - /** - * Parse service Solicitation UUIDs. - */ - private static int parseServiceSolicitationUuid(byte[] scanRecord, int currentPos, - int dataLength, int uuidLength, List serviceSolicitationUuids) { - while (dataLength > 0) { - byte[] uuidBytes = extractBytes(scanRecord, currentPos, uuidLength); - serviceSolicitationUuids.add(BluetoothUuid.parseUuidFrom(uuidBytes)); - dataLength -= uuidLength; - currentPos += uuidLength; - } - return currentPos; - } - - // Helper method to extract bytes from byte array. - private static byte[] extractBytes(byte[] scanRecord, int start, int length) { - byte[] bytes = new byte[length]; - System.arraycopy(scanRecord, start, bytes, 0, length); - return bytes; - } -} diff --git a/core/java/android/bluetooth/le/ScanResult.java b/core/java/android/bluetooth/le/ScanResult.java deleted file mode 100644 index f437d867ea3736b3b581bc3f276ad5fe57f682dd..0000000000000000000000000000000000000000 --- a/core/java/android/bluetooth/le/ScanResult.java +++ /dev/null @@ -1,361 +0,0 @@ -/* - * Copyright (C) 2014 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.bluetooth.le; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.bluetooth.Attributable; -import android.bluetooth.BluetoothDevice; -import android.content.AttributionSource; -import android.os.Parcel; -import android.os.Parcelable; - -import java.util.Objects; - -/** - * ScanResult for Bluetooth LE scan. - */ -public final class ScanResult implements Parcelable, Attributable { - - /** - * For chained advertisements, inidcates tha the data contained in this - * scan result is complete. - */ - public static final int DATA_COMPLETE = 0x00; - - /** - * For chained advertisements, indicates that the controller was - * unable to receive all chained packets and the scan result contains - * incomplete truncated data. - */ - public static final int DATA_TRUNCATED = 0x02; - - /** - * Indicates that the secondary physical layer was not used. - */ - public static final int PHY_UNUSED = 0x00; - - /** - * Advertising Set ID is not present in the packet. - */ - public static final int SID_NOT_PRESENT = 0xFF; - - /** - * TX power is not present in the packet. - */ - public static final int TX_POWER_NOT_PRESENT = 0x7F; - - /** - * Periodic advertising interval is not present in the packet. - */ - public static final int PERIODIC_INTERVAL_NOT_PRESENT = 0x00; - - /** - * Mask for checking whether event type represents legacy advertisement. - */ - private static final int ET_LEGACY_MASK = 0x10; - - /** - * Mask for checking whether event type represents connectable advertisement. - */ - private static final int ET_CONNECTABLE_MASK = 0x01; - - // Remote Bluetooth device. - private BluetoothDevice mDevice; - - // Scan record, including advertising data and scan response data. - @Nullable - private ScanRecord mScanRecord; - - // Received signal strength. - private int mRssi; - - // Device timestamp when the result was last seen. - private long mTimestampNanos; - - private int mEventType; - private int mPrimaryPhy; - private int mSecondaryPhy; - private int mAdvertisingSid; - private int mTxPower; - private int mPeriodicAdvertisingInterval; - - /** - * Constructs a new ScanResult. - * - * @param device Remote Bluetooth device found. - * @param scanRecord Scan record including both advertising data and scan response data. - * @param rssi Received signal strength. - * @param timestampNanos Timestamp at which the scan result was observed. - * @deprecated use {@link #ScanResult(BluetoothDevice, int, int, int, int, int, int, int, - * ScanRecord, long)} - */ - @Deprecated - public ScanResult(BluetoothDevice device, ScanRecord scanRecord, int rssi, - long timestampNanos) { - mDevice = device; - mScanRecord = scanRecord; - mRssi = rssi; - mTimestampNanos = timestampNanos; - mEventType = (DATA_COMPLETE << 5) | ET_LEGACY_MASK | ET_CONNECTABLE_MASK; - mPrimaryPhy = BluetoothDevice.PHY_LE_1M; - mSecondaryPhy = PHY_UNUSED; - mAdvertisingSid = SID_NOT_PRESENT; - mTxPower = 127; - mPeriodicAdvertisingInterval = 0; - } - - /** - * Constructs a new ScanResult. - * - * @param device Remote Bluetooth device found. - * @param eventType Event type. - * @param primaryPhy Primary advertising phy. - * @param secondaryPhy Secondary advertising phy. - * @param advertisingSid Advertising set ID. - * @param txPower Transmit power. - * @param rssi Received signal strength. - * @param periodicAdvertisingInterval Periodic advertising interval. - * @param scanRecord Scan record including both advertising data and scan response data. - * @param timestampNanos Timestamp at which the scan result was observed. - */ - public ScanResult(BluetoothDevice device, int eventType, int primaryPhy, int secondaryPhy, - int advertisingSid, int txPower, int rssi, int periodicAdvertisingInterval, - ScanRecord scanRecord, long timestampNanos) { - mDevice = device; - mEventType = eventType; - mPrimaryPhy = primaryPhy; - mSecondaryPhy = secondaryPhy; - mAdvertisingSid = advertisingSid; - mTxPower = txPower; - mRssi = rssi; - mPeriodicAdvertisingInterval = periodicAdvertisingInterval; - mScanRecord = scanRecord; - mTimestampNanos = timestampNanos; - } - - private ScanResult(Parcel in) { - readFromParcel(in); - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - if (mDevice != null) { - dest.writeInt(1); - mDevice.writeToParcel(dest, flags); - } else { - dest.writeInt(0); - } - if (mScanRecord != null) { - dest.writeInt(1); - dest.writeByteArray(mScanRecord.getBytes()); - } else { - dest.writeInt(0); - } - dest.writeInt(mRssi); - dest.writeLong(mTimestampNanos); - dest.writeInt(mEventType); - dest.writeInt(mPrimaryPhy); - dest.writeInt(mSecondaryPhy); - dest.writeInt(mAdvertisingSid); - dest.writeInt(mTxPower); - dest.writeInt(mPeriodicAdvertisingInterval); - } - - private void readFromParcel(Parcel in) { - if (in.readInt() == 1) { - mDevice = BluetoothDevice.CREATOR.createFromParcel(in); - } - if (in.readInt() == 1) { - mScanRecord = ScanRecord.parseFromBytes(in.createByteArray()); - } - mRssi = in.readInt(); - mTimestampNanos = in.readLong(); - mEventType = in.readInt(); - mPrimaryPhy = in.readInt(); - mSecondaryPhy = in.readInt(); - mAdvertisingSid = in.readInt(); - mTxPower = in.readInt(); - mPeriodicAdvertisingInterval = in.readInt(); - } - - @Override - public int describeContents() { - return 0; - } - - /** {@hide} */ - public void setAttributionSource(@NonNull AttributionSource attributionSource) { - Attributable.setAttributionSource(mDevice, attributionSource); - } - - /** - * Returns the remote Bluetooth device identified by the Bluetooth device address. - */ - public BluetoothDevice getDevice() { - return mDevice; - } - - /** - * Returns the scan record, which is a combination of advertisement and scan response. - */ - @Nullable - public ScanRecord getScanRecord() { - return mScanRecord; - } - - /** - * Returns the received signal strength in dBm. The valid range is [-127, 126]. - */ - public int getRssi() { - return mRssi; - } - - /** - * Returns timestamp since boot when the scan record was observed. - */ - public long getTimestampNanos() { - return mTimestampNanos; - } - - /** - * Returns true if this object represents legacy scan result. - * Legacy scan results do not contain advanced advertising information - * as specified in the Bluetooth Core Specification v5. - */ - public boolean isLegacy() { - return (mEventType & ET_LEGACY_MASK) != 0; - } - - /** - * Returns true if this object represents connectable scan result. - */ - public boolean isConnectable() { - return (mEventType & ET_CONNECTABLE_MASK) != 0; - } - - /** - * Returns the data status. - * Can be one of {@link ScanResult#DATA_COMPLETE} or - * {@link ScanResult#DATA_TRUNCATED}. - */ - public int getDataStatus() { - // return bit 5 and 6 - return (mEventType >> 5) & 0x03; - } - - /** - * Returns the primary Physical Layer - * on which this advertisment was received. - * Can be one of {@link BluetoothDevice#PHY_LE_1M} or - * {@link BluetoothDevice#PHY_LE_CODED}. - */ - public int getPrimaryPhy() { - return mPrimaryPhy; - } - - /** - * Returns the secondary Physical Layer - * on which this advertisment was received. - * Can be one of {@link BluetoothDevice#PHY_LE_1M}, - * {@link BluetoothDevice#PHY_LE_2M}, {@link BluetoothDevice#PHY_LE_CODED} - * or {@link ScanResult#PHY_UNUSED} - if the advertisement - * was not received on a secondary physical channel. - */ - public int getSecondaryPhy() { - return mSecondaryPhy; - } - - /** - * Returns the advertising set id. - * May return {@link ScanResult#SID_NOT_PRESENT} if - * no set id was is present. - */ - public int getAdvertisingSid() { - return mAdvertisingSid; - } - - /** - * Returns the transmit power in dBm. - * Valid range is [-127, 126]. A value of {@link ScanResult#TX_POWER_NOT_PRESENT} - * indicates that the TX power is not present. - */ - public int getTxPower() { - return mTxPower; - } - - /** - * Returns the periodic advertising interval in units of 1.25ms. - * Valid range is 6 (7.5ms) to 65536 (81918.75ms). A value of - * {@link ScanResult#PERIODIC_INTERVAL_NOT_PRESENT} means periodic - * advertising interval is not present. - */ - public int getPeriodicAdvertisingInterval() { - return mPeriodicAdvertisingInterval; - } - - @Override - public int hashCode() { - return Objects.hash(mDevice, mRssi, mScanRecord, mTimestampNanos, - mEventType, mPrimaryPhy, mSecondaryPhy, - mAdvertisingSid, mTxPower, - mPeriodicAdvertisingInterval); - } - - @Override - public boolean equals(@Nullable Object obj) { - if (this == obj) { - return true; - } - if (obj == null || getClass() != obj.getClass()) { - return false; - } - ScanResult other = (ScanResult) obj; - return Objects.equals(mDevice, other.mDevice) && (mRssi == other.mRssi) - && Objects.equals(mScanRecord, other.mScanRecord) - && (mTimestampNanos == other.mTimestampNanos) - && mEventType == other.mEventType - && mPrimaryPhy == other.mPrimaryPhy - && mSecondaryPhy == other.mSecondaryPhy - && mAdvertisingSid == other.mAdvertisingSid - && mTxPower == other.mTxPower - && mPeriodicAdvertisingInterval == other.mPeriodicAdvertisingInterval; - } - - @Override - public String toString() { - return "ScanResult{" + "device=" + mDevice + ", scanRecord=" - + Objects.toString(mScanRecord) + ", rssi=" + mRssi - + ", timestampNanos=" + mTimestampNanos + ", eventType=" + mEventType - + ", primaryPhy=" + mPrimaryPhy + ", secondaryPhy=" + mSecondaryPhy - + ", advertisingSid=" + mAdvertisingSid + ", txPower=" + mTxPower - + ", periodicAdvertisingInterval=" + mPeriodicAdvertisingInterval + '}'; - } - - public static final @android.annotation.NonNull Parcelable.Creator CREATOR = new Creator() { - @Override - public ScanResult createFromParcel(Parcel source) { - return new ScanResult(source); - } - - @Override - public ScanResult[] newArray(int size) { - return new ScanResult[size]; - } - }; - -} diff --git a/core/java/android/bluetooth/le/ScanSettings.java b/core/java/android/bluetooth/le/ScanSettings.java deleted file mode 100644 index 1aa7cb5111ce68d3dea499141c9c5934cf579829..0000000000000000000000000000000000000000 --- a/core/java/android/bluetooth/le/ScanSettings.java +++ /dev/null @@ -1,438 +0,0 @@ -/* - * Copyright (C) 2014 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.bluetooth.le; - -import android.annotation.SystemApi; -import android.bluetooth.BluetoothDevice; -import android.os.Parcel; -import android.os.Parcelable; - -/** - * Bluetooth LE scan settings are passed to {@link BluetoothLeScanner#startScan} to define the - * parameters for the scan. - */ -public final class ScanSettings implements Parcelable { - - /** - * A special Bluetooth LE scan mode. Applications using this scan mode will passively listen for - * other scan results without starting BLE scans themselves. - */ - public static final int SCAN_MODE_OPPORTUNISTIC = -1; - - /** - * Perform Bluetooth LE scan in low power mode. This is the default scan mode as it consumes the - * least power. This mode is enforced if the scanning application is not in foreground. - */ - public static final int SCAN_MODE_LOW_POWER = 0; - - /** - * Perform Bluetooth LE scan in balanced power mode. Scan results are returned at a rate that - * provides a good trade-off between scan frequency and power consumption. - */ - public static final int SCAN_MODE_BALANCED = 1; - - /** - * Scan using highest duty cycle. It's recommended to only use this mode when the application is - * running in the foreground. - */ - public static final int SCAN_MODE_LOW_LATENCY = 2; - - /** - * Perform Bluetooth LE scan in ambient discovery mode. This mode has lower duty cycle and more - * aggressive scan interval than balanced mode that provides a good trade-off between scan - * latency and power consumption. - * - * @hide - */ - @SystemApi - public static final int SCAN_MODE_AMBIENT_DISCOVERY = 3; - - /** - * Trigger a callback for every Bluetooth advertisement found that matches the filter criteria. - * If no filter is active, all advertisement packets are reported. - */ - public static final int CALLBACK_TYPE_ALL_MATCHES = 1; - - /** - * A result callback is only triggered for the first advertisement packet received that matches - * the filter criteria. - */ - public static final int CALLBACK_TYPE_FIRST_MATCH = 2; - - /** - * Receive a callback when advertisements are no longer received from a device that has been - * previously reported by a first match callback. - */ - public static final int CALLBACK_TYPE_MATCH_LOST = 4; - - - /** - * Determines how many advertisements to match per filter, as this is scarce hw resource - */ - /** - * Match one advertisement per filter - */ - public static final int MATCH_NUM_ONE_ADVERTISEMENT = 1; - - /** - * Match few advertisement per filter, depends on current capability and availibility of - * the resources in hw - */ - public static final int MATCH_NUM_FEW_ADVERTISEMENT = 2; - - /** - * Match as many advertisement per filter as hw could allow, depends on current - * capability and availibility of the resources in hw - */ - public static final int MATCH_NUM_MAX_ADVERTISEMENT = 3; - - - /** - * In Aggressive mode, hw will determine a match sooner even with feeble signal strength - * and few number of sightings/match in a duration. - */ - public static final int MATCH_MODE_AGGRESSIVE = 1; - - /** - * For sticky mode, higher threshold of signal strength and sightings is required - * before reporting by hw - */ - public static final int MATCH_MODE_STICKY = 2; - - /** - * Request full scan results which contain the device, rssi, advertising data, scan response - * as well as the scan timestamp. - * - * @hide - */ - @SystemApi - public static final int SCAN_RESULT_TYPE_FULL = 0; - - /** - * Request abbreviated scan results which contain the device, rssi and scan timestamp. - *

    - * Note: It is possible for an application to get more scan results than it asked for, if - * there are multiple apps using this type. - * - * @hide - */ - @SystemApi - public static final int SCAN_RESULT_TYPE_ABBREVIATED = 1; - - /** - * Use all supported PHYs for scanning. - * This will check the controller capabilities, and start - * the scan on 1Mbit and LE Coded PHYs if supported, or on - * the 1Mbit PHY only. - */ - public static final int PHY_LE_ALL_SUPPORTED = 255; - - // Bluetooth LE scan mode. - private int mScanMode; - - // Bluetooth LE scan callback type - private int mCallbackType; - - // Bluetooth LE scan result type - private int mScanResultType; - - // Time of delay for reporting the scan result - private long mReportDelayMillis; - - private int mMatchMode; - - private int mNumOfMatchesPerFilter; - - // Include only legacy advertising results - private boolean mLegacy; - - private int mPhy; - - public int getScanMode() { - return mScanMode; - } - - public int getCallbackType() { - return mCallbackType; - } - - public int getScanResultType() { - return mScanResultType; - } - - /** - * @hide - */ - public int getMatchMode() { - return mMatchMode; - } - - /** - * @hide - */ - public int getNumOfMatches() { - return mNumOfMatchesPerFilter; - } - - /** - * Returns whether only legacy advertisements will be returned. - * Legacy advertisements include advertisements as specified - * by the Bluetooth core specification 4.2 and below. - */ - public boolean getLegacy() { - return mLegacy; - } - - /** - * Returns the physical layer used during a scan. - */ - public int getPhy() { - return mPhy; - } - - /** - * Returns report delay timestamp based on the device clock. - */ - public long getReportDelayMillis() { - return mReportDelayMillis; - } - - private ScanSettings(int scanMode, int callbackType, int scanResultType, - long reportDelayMillis, int matchMode, - int numOfMatchesPerFilter, boolean legacy, int phy) { - mScanMode = scanMode; - mCallbackType = callbackType; - mScanResultType = scanResultType; - mReportDelayMillis = reportDelayMillis; - mNumOfMatchesPerFilter = numOfMatchesPerFilter; - mMatchMode = matchMode; - mLegacy = legacy; - mPhy = phy; - } - - private ScanSettings(Parcel in) { - mScanMode = in.readInt(); - mCallbackType = in.readInt(); - mScanResultType = in.readInt(); - mReportDelayMillis = in.readLong(); - mMatchMode = in.readInt(); - mNumOfMatchesPerFilter = in.readInt(); - mLegacy = in.readInt() != 0; - mPhy = in.readInt(); - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeInt(mScanMode); - dest.writeInt(mCallbackType); - dest.writeInt(mScanResultType); - dest.writeLong(mReportDelayMillis); - dest.writeInt(mMatchMode); - dest.writeInt(mNumOfMatchesPerFilter); - dest.writeInt(mLegacy ? 1 : 0); - dest.writeInt(mPhy); - } - - @Override - public int describeContents() { - return 0; - } - - public static final @android.annotation.NonNull Parcelable.Creator CREATOR = - new Creator() { - @Override - public ScanSettings[] newArray(int size) { - return new ScanSettings[size]; - } - - @Override - public ScanSettings createFromParcel(Parcel in) { - return new ScanSettings(in); - } - }; - - /** - * Builder for {@link ScanSettings}. - */ - public static final class Builder { - private int mScanMode = SCAN_MODE_LOW_POWER; - private int mCallbackType = CALLBACK_TYPE_ALL_MATCHES; - private int mScanResultType = SCAN_RESULT_TYPE_FULL; - private long mReportDelayMillis = 0; - private int mMatchMode = MATCH_MODE_AGGRESSIVE; - private int mNumOfMatchesPerFilter = MATCH_NUM_MAX_ADVERTISEMENT; - private boolean mLegacy = true; - private int mPhy = PHY_LE_ALL_SUPPORTED; - - /** - * Set scan mode for Bluetooth LE scan. - * - * @param scanMode The scan mode can be one of {@link ScanSettings#SCAN_MODE_LOW_POWER}, - * {@link ScanSettings#SCAN_MODE_BALANCED} or {@link ScanSettings#SCAN_MODE_LOW_LATENCY}. - * @throws IllegalArgumentException If the {@code scanMode} is invalid. - */ - public Builder setScanMode(int scanMode) { - switch (scanMode) { - case SCAN_MODE_OPPORTUNISTIC: - case SCAN_MODE_LOW_POWER: - case SCAN_MODE_BALANCED: - case SCAN_MODE_LOW_LATENCY: - case SCAN_MODE_AMBIENT_DISCOVERY: - mScanMode = scanMode; - break; - default: - throw new IllegalArgumentException("invalid scan mode " + scanMode); - } - return this; - } - - /** - * Set callback type for Bluetooth LE scan. - * - * @param callbackType The callback type flags for the scan. - * @throws IllegalArgumentException If the {@code callbackType} is invalid. - */ - public Builder setCallbackType(int callbackType) { - - if (!isValidCallbackType(callbackType)) { - throw new IllegalArgumentException("invalid callback type - " + callbackType); - } - mCallbackType = callbackType; - return this; - } - - // Returns true if the callbackType is valid. - private boolean isValidCallbackType(int callbackType) { - if (callbackType == CALLBACK_TYPE_ALL_MATCHES - || callbackType == CALLBACK_TYPE_FIRST_MATCH - || callbackType == CALLBACK_TYPE_MATCH_LOST) { - return true; - } - return callbackType == (CALLBACK_TYPE_FIRST_MATCH | CALLBACK_TYPE_MATCH_LOST); - } - - /** - * Set scan result type for Bluetooth LE scan. - * - * @param scanResultType Type for scan result, could be either {@link - * ScanSettings#SCAN_RESULT_TYPE_FULL} or {@link ScanSettings#SCAN_RESULT_TYPE_ABBREVIATED}. - * @throws IllegalArgumentException If the {@code scanResultType} is invalid. - * @hide - */ - @SystemApi - public Builder setScanResultType(int scanResultType) { - if (scanResultType < SCAN_RESULT_TYPE_FULL - || scanResultType > SCAN_RESULT_TYPE_ABBREVIATED) { - throw new IllegalArgumentException( - "invalid scanResultType - " + scanResultType); - } - mScanResultType = scanResultType; - return this; - } - - /** - * Set report delay timestamp for Bluetooth LE scan. If set to 0, you will be notified of - * scan results immediately. If > 0, scan results are queued up and delivered after the - * requested delay or 5000 milliseconds (whichever is higher). Note scan results may be - * delivered sooner if the internal buffers fill up. - * - * @param reportDelayMillis how frequently scan results should be delivered in - * milliseconds - * @throws IllegalArgumentException if {@code reportDelayMillis} < 0 - */ - public Builder setReportDelay(long reportDelayMillis) { - if (reportDelayMillis < 0) { - throw new IllegalArgumentException("reportDelay must be > 0"); - } - mReportDelayMillis = reportDelayMillis; - return this; - } - - /** - * Set the number of matches for Bluetooth LE scan filters hardware match - * - * @param numOfMatches The num of matches can be one of - * {@link ScanSettings#MATCH_NUM_ONE_ADVERTISEMENT} - * or {@link ScanSettings#MATCH_NUM_FEW_ADVERTISEMENT} or {@link - * ScanSettings#MATCH_NUM_MAX_ADVERTISEMENT} - * @throws IllegalArgumentException If the {@code matchMode} is invalid. - */ - public Builder setNumOfMatches(int numOfMatches) { - if (numOfMatches < MATCH_NUM_ONE_ADVERTISEMENT - || numOfMatches > MATCH_NUM_MAX_ADVERTISEMENT) { - throw new IllegalArgumentException("invalid numOfMatches " + numOfMatches); - } - mNumOfMatchesPerFilter = numOfMatches; - return this; - } - - /** - * Set match mode for Bluetooth LE scan filters hardware match - * - * @param matchMode The match mode can be one of {@link ScanSettings#MATCH_MODE_AGGRESSIVE} - * or {@link ScanSettings#MATCH_MODE_STICKY} - * @throws IllegalArgumentException If the {@code matchMode} is invalid. - */ - public Builder setMatchMode(int matchMode) { - if (matchMode < MATCH_MODE_AGGRESSIVE - || matchMode > MATCH_MODE_STICKY) { - throw new IllegalArgumentException("invalid matchMode " + matchMode); - } - mMatchMode = matchMode; - return this; - } - - /** - * Set whether only legacy advertisments should be returned in scan results. - * Legacy advertisements include advertisements as specified by the - * Bluetooth core specification 4.2 and below. This is true by default - * for compatibility with older apps. - * - * @param legacy true if only legacy advertisements will be returned - */ - public Builder setLegacy(boolean legacy) { - mLegacy = legacy; - return this; - } - - /** - * Set the Physical Layer to use during this scan. - * This is used only if {@link ScanSettings.Builder#setLegacy} - * is set to false. - * {@link android.bluetooth.BluetoothAdapter#isLeCodedPhySupported} - * may be used to check whether LE Coded phy is supported by calling - * {@link android.bluetooth.BluetoothAdapter#isLeCodedPhySupported}. - * Selecting an unsupported phy will result in failure to start scan. - * - * @param phy Can be one of {@link BluetoothDevice#PHY_LE_1M}, {@link - * BluetoothDevice#PHY_LE_CODED} or {@link ScanSettings#PHY_LE_ALL_SUPPORTED} - */ - public Builder setPhy(int phy) { - mPhy = phy; - return this; - } - - /** - * Build {@link ScanSettings}. - */ - public ScanSettings build() { - return new ScanSettings(mScanMode, mCallbackType, mScanResultType, - mReportDelayMillis, mMatchMode, - mNumOfMatchesPerFilter, mLegacy, mPhy); - } - } -} diff --git a/core/java/android/bluetooth/le/TransportBlock.java b/core/java/android/bluetooth/le/TransportBlock.java deleted file mode 100644 index 18bad9c3c259c90648b8e03477f08a660126fb05..0000000000000000000000000000000000000000 --- a/core/java/android/bluetooth/le/TransportBlock.java +++ /dev/null @@ -1,177 +0,0 @@ -/* - * Copyright (C) 2014 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.bluetooth.le; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.os.Parcel; -import android.os.Parcelable; -import android.util.Log; - -import java.nio.BufferOverflowException; -import java.nio.ByteBuffer; -import java.util.Arrays; - -/** - * Wrapper for Transport Discovery Data Transport Blocks. - * This class represents a Transport Block from a Transport Discovery Data. - * - * @see TransportDiscoveryData - * @see AdvertiseData - */ -public final class TransportBlock implements Parcelable { - private static final String TAG = "TransportBlock"; - private final int mOrgId; - private final int mTdsFlags; - private final int mTransportDataLength; - private final byte[] mTransportData; - - /** - * Creates an instance of TransportBlock from raw data. - * - * @param orgId the Organization ID - * @param tdsFlags the TDS flags - * @param transportDataLength the total length of the Transport Data - * @param transportData the Transport Data - */ - public TransportBlock(int orgId, int tdsFlags, int transportDataLength, - @Nullable byte[] transportData) { - mOrgId = orgId; - mTdsFlags = tdsFlags; - mTransportDataLength = transportDataLength; - mTransportData = transportData; - } - - private TransportBlock(Parcel in) { - mOrgId = in.readInt(); - mTdsFlags = in.readInt(); - mTransportDataLength = in.readInt(); - if (mTransportDataLength > 0) { - mTransportData = new byte[mTransportDataLength]; - in.readByteArray(mTransportData); - } else { - mTransportData = null; - } - } - - @Override - public void writeToParcel(@NonNull Parcel dest, int flags) { - dest.writeInt(mOrgId); - dest.writeInt(mTdsFlags); - dest.writeInt(mTransportDataLength); - if (mTransportData != null) { - dest.writeByteArray(mTransportData); - } - } - - /** - * @hide - */ - @Override - public int describeContents() { - return 0; - } - - /** - * @hide - */ - @Override - public boolean equals(@Nullable Object obj) { - if (this == obj) { - return true; - } - if (obj == null || getClass() != obj.getClass()) { - return false; - } - TransportBlock other = (TransportBlock) obj; - return Arrays.equals(toByteArray(), other.toByteArray()); - } - - public static final @NonNull Creator CREATOR = new Creator() { - @Override - public TransportBlock createFromParcel(Parcel in) { - return new TransportBlock(in); - } - - @Override - public TransportBlock[] newArray(int size) { - return new TransportBlock[size]; - } - }; - - /** - * Gets the Organization ID of the Transport Block which corresponds to one of the - * the Bluetooth SIG Assigned Numbers. - */ - public int getOrgId() { - return mOrgId; - } - - /** - * Gets the TDS flags of the Transport Block which represents the role of the device and - * information about its state and supported features. - */ - public int getTdsFlags() { - return mTdsFlags; - } - - /** - * Gets the total number of octets in the Transport Data field in this Transport Block. - */ - public int getTransportDataLength() { - return mTransportDataLength; - } - - /** - * Gets the Transport Data of the Transport Block which contains organization-specific data. - */ - @Nullable - public byte[] getTransportData() { - return mTransportData; - } - - /** - * Converts this TransportBlock to byte array - * - * @return byte array representation of this Transport Block or null if the conversion failed - */ - @Nullable - public byte[] toByteArray() { - try { - ByteBuffer buffer = ByteBuffer.allocate(totalBytes()); - buffer.put((byte) mOrgId); - buffer.put((byte) mTdsFlags); - buffer.put((byte) mTransportDataLength); - if (mTransportData != null) { - buffer.put(mTransportData); - } - return buffer.array(); - } catch (BufferOverflowException e) { - Log.e(TAG, "Error converting to byte array: " + e.toString()); - return null; - } - } - - /** - * @return total byte count of this TransportBlock - */ - public int totalBytes() { - // 3 uint8 + byte[] length - int size = 3 + mTransportDataLength; - return size; - } -} diff --git a/core/java/android/bluetooth/le/TransportDiscoveryData.java b/core/java/android/bluetooth/le/TransportDiscoveryData.java deleted file mode 100644 index 2b52f19798ad5dac728f48d67152d8ebcdf20677..0000000000000000000000000000000000000000 --- a/core/java/android/bluetooth/le/TransportDiscoveryData.java +++ /dev/null @@ -1,184 +0,0 @@ -/* - * Copyright (C) 2014 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.bluetooth.le; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.os.Parcel; -import android.os.Parcelable; -import android.util.Log; - -import java.nio.BufferOverflowException; -import java.nio.BufferUnderflowException; -import java.nio.ByteBuffer; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; - -/** - * Wrapper for Transport Discovery Data AD Type. - * This class contains the Transport Discovery Data AD Type Code as well as - * a list of potential Transport Blocks. - * - * @see AdvertiseData - */ -public final class TransportDiscoveryData implements Parcelable { - private static final String TAG = "TransportDiscoveryData"; - private final int mTransportDataType; - private final List mTransportBlocks; - - /** - * Creates a TransportDiscoveryData instance. - * - * @param transportDataType the Transport Discovery Data AD Type - * @param transportBlocks the list of Transport Blocks - */ - public TransportDiscoveryData(int transportDataType, - @NonNull List transportBlocks) { - mTransportDataType = transportDataType; - mTransportBlocks = transportBlocks; - } - - /** - * Creates a TransportDiscoveryData instance from byte arrays. - * - * Uses the transport discovery data bytes and parses them into an usable class. - * - * @param transportDiscoveryData the raw discovery data - */ - public TransportDiscoveryData(@NonNull byte[] transportDiscoveryData) { - ByteBuffer byteBuffer = ByteBuffer.wrap(transportDiscoveryData); - mTransportBlocks = new ArrayList(); - if (byteBuffer.remaining() > 0) { - mTransportDataType = byteBuffer.get(); - } else { - mTransportDataType = -1; - } - try { - while (byteBuffer.remaining() > 0) { - int orgId = byteBuffer.get(); - int tdsFlags = byteBuffer.get(); - int transportDataLength = byteBuffer.get(); - byte[] transportData = new byte[transportDataLength]; - byteBuffer.get(transportData, 0, transportDataLength); - mTransportBlocks.add(new TransportBlock(orgId, tdsFlags, - transportDataLength, transportData)); - } - } catch (BufferUnderflowException e) { - Log.e(TAG, "Error while parsing data: " + e.toString()); - } - } - - private TransportDiscoveryData(Parcel in) { - mTransportDataType = in.readInt(); - mTransportBlocks = in.createTypedArrayList(TransportBlock.CREATOR); - } - - /** - * @hide - */ - @Override - public int describeContents() { - return 0; - } - - /** - * @hide - */ - @Override - public boolean equals(@Nullable Object obj) { - if (this == obj) { - return true; - } - if (obj == null || getClass() != obj.getClass()) { - return false; - } - TransportDiscoveryData other = (TransportDiscoveryData) obj; - return Arrays.equals(toByteArray(), other.toByteArray()); - } - - @Override - public void writeToParcel(@NonNull Parcel dest, int flags) { - dest.writeInt(mTransportDataType); - dest.writeTypedList(mTransportBlocks); - } - - public static final @NonNull Creator CREATOR = - new Creator() { - @Override - public TransportDiscoveryData createFromParcel(Parcel in) { - return new TransportDiscoveryData(in); - } - - @Override - public TransportDiscoveryData[] newArray(int size) { - return new TransportDiscoveryData[size]; - } - }; - - /** - * Gets the transport data type. - */ - public int getTransportDataType() { - return mTransportDataType; - } - - /** - * @return the list of {@link TransportBlock} in this TransportDiscoveryData - * or an empty list if there are no Transport Blocks - */ - @NonNull - public List getTransportBlocks() { - if (mTransportBlocks == null) { - return Collections.emptyList(); - } - return mTransportBlocks; - } - - /** - * Converts this TransportDiscoveryData to byte array - * - * @return byte array representation of this Transport Discovery Data or null if the - * conversion failed - */ - @Nullable - public byte[] toByteArray() { - try { - ByteBuffer buffer = ByteBuffer.allocate(totalBytes()); - buffer.put((byte) mTransportDataType); - for (TransportBlock transportBlock : getTransportBlocks()) { - buffer.put(transportBlock.toByteArray()); - } - return buffer.array(); - } catch (BufferOverflowException e) { - Log.e(TAG, "Error converting to byte array: " + e.toString()); - return null; - } - } - - /** - * @return total byte count of this TransportDataDiscovery - */ - public int totalBytes() { - int size = 1; // Counting Transport Data Type here. - for (TransportBlock transportBlock : getTransportBlocks()) { - size += transportBlock.totalBytes(); - } - return size; - } -} diff --git a/core/java/android/bluetooth/le/TruncatedFilter.java b/core/java/android/bluetooth/le/TruncatedFilter.java deleted file mode 100644 index 25925888a0d237a408502159b3942f808089cf7e..0000000000000000000000000000000000000000 --- a/core/java/android/bluetooth/le/TruncatedFilter.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (C) 2014 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.bluetooth.le; - -import android.annotation.SuppressLint; -import android.annotation.SystemApi; - -import java.util.List; - -/** - * A special scan filter that lets the client decide how the scan record should be stored. - * - * @deprecated this is not used anywhere - * - * @hide - */ -@Deprecated -@SystemApi -@SuppressLint("AndroidFrameworkBluetoothPermission") -public final class TruncatedFilter { - private final ScanFilter mFilter; - private final List mStorageDescriptors; - - /** - * Constructor for {@link TruncatedFilter}. - * - * @param filter Scan filter of the truncated filter. - * @param storageDescriptors Describes how the scan should be stored. - */ - public TruncatedFilter(ScanFilter filter, List storageDescriptors) { - mFilter = filter; - mStorageDescriptors = storageDescriptors; - } - - /** - * Returns the scan filter. - */ - public ScanFilter getFilter() { - return mFilter; - } - - /** - * Returns a list of descriptor for scan result storage. - */ - public List getStorageDescriptors() { - return mStorageDescriptors; - } - - -} diff --git a/core/java/android/bluetooth/package.html b/core/java/android/bluetooth/package.html deleted file mode 100644 index d9ca4f13101f8189277b1733ac215213da4c106b..0000000000000000000000000000000000000000 --- a/core/java/android/bluetooth/package.html +++ /dev/null @@ -1,38 +0,0 @@ - - -

    Provides classes that manage Bluetooth functionality, such as scanning for -devices, connecting with devices, and managing data transfer between devices. -The Bluetooth API supports both "Classic Bluetooth" and Bluetooth Low Energy.

    - -

    For more information about Classic Bluetooth, see the -Bluetooth guide. -For more information about Bluetooth Low Energy, see the - -Bluetooth Low Energy (BLE) guide.

    -{@more} - -

    The Bluetooth APIs let applications:

    -
      -
    • Scan for other Bluetooth devices (including BLE devices).
    • -
    • Query the local Bluetooth adapter for paired Bluetooth devices.
    • -
    • Establish RFCOMM channels/sockets.
    • -
    • Connect to specified sockets on other devices.
    • -
    • Transfer data to and from other devices.
    • -
    • Communicate with BLE devices, such as proximity sensors, heart rate - monitors, fitness devices, and so on.
    • -
    • Act as a GATT client or a GATT server (BLE).
    • -
    - -

    -To perform Bluetooth communication using these APIs, an application must -declare the {@link android.Manifest.permission#BLUETOOTH} permission. Some -additional functionality, such as requesting device discovery, -also requires the {@link android.Manifest.permission#BLUETOOTH_ADMIN} -permission. -

    - -

    Note: -Not all Android-powered devices provide Bluetooth functionality.

    - - - diff --git a/core/tests/bluetoothtests/Android.bp b/core/tests/bluetoothtests/Android.bp deleted file mode 100644 index 68416dd6546689c235c7c28d30cddb94f4eb16cb..0000000000000000000000000000000000000000 --- a/core/tests/bluetoothtests/Android.bp +++ /dev/null @@ -1,24 +0,0 @@ -package { - // See: http://go/android-license-faq - // A large-scale-change added 'default_applicable_licenses' to import - // all of the 'license_kinds' from "frameworks_base_license" - // to get the below license kinds: - // SPDX-license-identifier-Apache-2.0 - default_applicable_licenses: ["frameworks_base_license"], -} - -android_test { - name: "BluetoothTests", - // Include all test java files. - srcs: ["src/**/*.java"], - libs: [ - "android.test.runner", - "android.test.base", - ], - static_libs: [ - "junit", - "modules-utils-bytesmatcher", - ], - platform_apis: true, - certificate: "platform", -} diff --git a/core/tests/bluetoothtests/AndroidManifest.xml b/core/tests/bluetoothtests/AndroidManifest.xml deleted file mode 100644 index 75583d5298cbe465bc66cae0a7416f38b56a73b8..0000000000000000000000000000000000000000 --- a/core/tests/bluetoothtests/AndroidManifest.xml +++ /dev/null @@ -1,47 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/core/tests/bluetoothtests/AndroidTest.xml b/core/tests/bluetoothtests/AndroidTest.xml deleted file mode 100644 index f93c4ebf5bf69eaf2e69a8bbcff677f33b166efb..0000000000000000000000000000000000000000 --- a/core/tests/bluetoothtests/AndroidTest.xml +++ /dev/null @@ -1,32 +0,0 @@ - - - - diff --git a/core/tests/bluetoothtests/OWNERS b/core/tests/bluetoothtests/OWNERS deleted file mode 100644 index 98bb87716207dcf564bf6ffecf24e2f5fe6ef680..0000000000000000000000000000000000000000 --- a/core/tests/bluetoothtests/OWNERS +++ /dev/null @@ -1 +0,0 @@ -include /core/java/android/bluetooth/OWNERS diff --git a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothCodecConfigTest.java b/core/tests/bluetoothtests/src/android/bluetooth/BluetoothCodecConfigTest.java deleted file mode 100644 index bd55426601fc5842486dcbb21e1fe05e80b7992e..0000000000000000000000000000000000000000 --- a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothCodecConfigTest.java +++ /dev/null @@ -1,329 +0,0 @@ -/* - * Copyright 2018 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.bluetooth; - -import android.test.suitebuilder.annotation.SmallTest; - -import junit.framework.TestCase; - -/** - * Unit test cases for {@link BluetoothCodecConfig}. - *

    - * To run this test, use: - * runtest --path core/tests/bluetoothtests/src/android/bluetooth/BluetoothCodecConfigTest.java - */ -public class BluetoothCodecConfigTest extends TestCase { - private static final int[] kCodecTypeArray = new int[] { - BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC, - BluetoothCodecConfig.SOURCE_CODEC_TYPE_AAC, - BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX, - BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX_HD, - BluetoothCodecConfig.SOURCE_CODEC_TYPE_LDAC, - BluetoothCodecConfig.SOURCE_CODEC_TYPE_INVALID, - }; - private static final int[] kCodecPriorityArray = new int[] { - BluetoothCodecConfig.CODEC_PRIORITY_DISABLED, - BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, - BluetoothCodecConfig.CODEC_PRIORITY_HIGHEST, - }; - private static final int[] kSampleRateArray = new int[] { - BluetoothCodecConfig.SAMPLE_RATE_NONE, - BluetoothCodecConfig.SAMPLE_RATE_44100, - BluetoothCodecConfig.SAMPLE_RATE_48000, - BluetoothCodecConfig.SAMPLE_RATE_88200, - BluetoothCodecConfig.SAMPLE_RATE_96000, - BluetoothCodecConfig.SAMPLE_RATE_176400, - BluetoothCodecConfig.SAMPLE_RATE_192000, - }; - private static final int[] kBitsPerSampleArray = new int[] { - BluetoothCodecConfig.BITS_PER_SAMPLE_NONE, - BluetoothCodecConfig.BITS_PER_SAMPLE_16, - BluetoothCodecConfig.BITS_PER_SAMPLE_24, - BluetoothCodecConfig.BITS_PER_SAMPLE_32, - }; - private static final int[] kChannelModeArray = new int[] { - BluetoothCodecConfig.CHANNEL_MODE_NONE, - BluetoothCodecConfig.CHANNEL_MODE_MONO, - BluetoothCodecConfig.CHANNEL_MODE_STEREO, - }; - private static final long[] kCodecSpecific1Array = new long[] { 1000, 1001, 1002, 1003, }; - private static final long[] kCodecSpecific2Array = new long[] { 2000, 2001, 2002, 2003, }; - private static final long[] kCodecSpecific3Array = new long[] { 3000, 3001, 3002, 3003, }; - private static final long[] kCodecSpecific4Array = new long[] { 4000, 4001, 4002, 4003, }; - - private static final int kTotalConfigs = kCodecTypeArray.length * kCodecPriorityArray.length * - kSampleRateArray.length * kBitsPerSampleArray.length * kChannelModeArray.length * - kCodecSpecific1Array.length * kCodecSpecific2Array.length * kCodecSpecific3Array.length * - kCodecSpecific4Array.length; - - private int selectCodecType(int configId) { - int left = kCodecTypeArray.length; - int right = kTotalConfigs / left; - int index = configId / right; - index = index % kCodecTypeArray.length; - return kCodecTypeArray[index]; - } - - private int selectCodecPriority(int configId) { - int left = kCodecTypeArray.length * kCodecPriorityArray.length; - int right = kTotalConfigs / left; - int index = configId / right; - index = index % kCodecPriorityArray.length; - return kCodecPriorityArray[index]; - } - - private int selectSampleRate(int configId) { - int left = kCodecTypeArray.length * kCodecPriorityArray.length * kSampleRateArray.length; - int right = kTotalConfigs / left; - int index = configId / right; - index = index % kSampleRateArray.length; - return kSampleRateArray[index]; - } - - private int selectBitsPerSample(int configId) { - int left = kCodecTypeArray.length * kCodecPriorityArray.length * kSampleRateArray.length * - kBitsPerSampleArray.length; - int right = kTotalConfigs / left; - int index = configId / right; - index = index % kBitsPerSampleArray.length; - return kBitsPerSampleArray[index]; - } - - private int selectChannelMode(int configId) { - int left = kCodecTypeArray.length * kCodecPriorityArray.length * kSampleRateArray.length * - kBitsPerSampleArray.length * kChannelModeArray.length; - int right = kTotalConfigs / left; - int index = configId / right; - index = index % kChannelModeArray.length; - return kChannelModeArray[index]; - } - - private long selectCodecSpecific1(int configId) { - int left = kCodecTypeArray.length * kCodecPriorityArray.length * kSampleRateArray.length * - kBitsPerSampleArray.length * kChannelModeArray.length * kCodecSpecific1Array.length; - int right = kTotalConfigs / left; - int index = configId / right; - index = index % kCodecSpecific1Array.length; - return kCodecSpecific1Array[index]; - } - - private long selectCodecSpecific2(int configId) { - int left = kCodecTypeArray.length * kCodecPriorityArray.length * kSampleRateArray.length * - kBitsPerSampleArray.length * kChannelModeArray.length * kCodecSpecific1Array.length * - kCodecSpecific2Array.length; - int right = kTotalConfigs / left; - int index = configId / right; - index = index % kCodecSpecific2Array.length; - return kCodecSpecific2Array[index]; - } - - private long selectCodecSpecific3(int configId) { - int left = kCodecTypeArray.length * kCodecPriorityArray.length * kSampleRateArray.length * - kBitsPerSampleArray.length * kChannelModeArray.length * kCodecSpecific1Array.length * - kCodecSpecific2Array.length * kCodecSpecific3Array.length; - int right = kTotalConfigs / left; - int index = configId / right; - index = index % kCodecSpecific3Array.length; - return kCodecSpecific3Array[index]; - } - - private long selectCodecSpecific4(int configId) { - int left = kCodecTypeArray.length * kCodecPriorityArray.length * kSampleRateArray.length * - kBitsPerSampleArray.length * kChannelModeArray.length * kCodecSpecific1Array.length * - kCodecSpecific2Array.length * kCodecSpecific3Array.length * - kCodecSpecific4Array.length; - int right = kTotalConfigs / left; - int index = configId / right; - index = index % kCodecSpecific4Array.length; - return kCodecSpecific4Array[index]; - } - - @SmallTest - public void testBluetoothCodecConfig_valid_get_methods() { - - for (int config_id = 0; config_id < kTotalConfigs; config_id++) { - int codec_type = selectCodecType(config_id); - int codec_priority = selectCodecPriority(config_id); - int sample_rate = selectSampleRate(config_id); - int bits_per_sample = selectBitsPerSample(config_id); - int channel_mode = selectChannelMode(config_id); - long codec_specific1 = selectCodecSpecific1(config_id); - long codec_specific2 = selectCodecSpecific2(config_id); - long codec_specific3 = selectCodecSpecific3(config_id); - long codec_specific4 = selectCodecSpecific4(config_id); - - BluetoothCodecConfig bcc = buildBluetoothCodecConfig(codec_type, codec_priority, - sample_rate, bits_per_sample, - channel_mode, codec_specific1, - codec_specific2, codec_specific3, - codec_specific4); - - if (codec_type == BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC) { - assertTrue(bcc.isMandatoryCodec()); - } else { - assertFalse(bcc.isMandatoryCodec()); - } - - if (codec_type == BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC) { - assertEquals("SBC", bcc.getCodecName()); - } - if (codec_type == BluetoothCodecConfig.SOURCE_CODEC_TYPE_AAC) { - assertEquals("AAC", bcc.getCodecName()); - } - if (codec_type == BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX) { - assertEquals("aptX", bcc.getCodecName()); - } - if (codec_type == BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX_HD) { - assertEquals("aptX HD", bcc.getCodecName()); - } - if (codec_type == BluetoothCodecConfig.SOURCE_CODEC_TYPE_LDAC) { - assertEquals("LDAC", bcc.getCodecName()); - } - if (codec_type == BluetoothCodecConfig.SOURCE_CODEC_TYPE_INVALID) { - assertEquals("INVALID CODEC", bcc.getCodecName()); - } - - assertEquals(codec_type, bcc.getCodecType()); - assertEquals(codec_priority, bcc.getCodecPriority()); - assertEquals(sample_rate, bcc.getSampleRate()); - assertEquals(bits_per_sample, bcc.getBitsPerSample()); - assertEquals(channel_mode, bcc.getChannelMode()); - assertEquals(codec_specific1, bcc.getCodecSpecific1()); - assertEquals(codec_specific2, bcc.getCodecSpecific2()); - assertEquals(codec_specific3, bcc.getCodecSpecific3()); - assertEquals(codec_specific4, bcc.getCodecSpecific4()); - } - } - - @SmallTest - public void testBluetoothCodecConfig_equals() { - BluetoothCodecConfig bcc1 = - buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC, - BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, - BluetoothCodecConfig.SAMPLE_RATE_44100, - BluetoothCodecConfig.BITS_PER_SAMPLE_16, - BluetoothCodecConfig.CHANNEL_MODE_STEREO, - 1000, 2000, 3000, 4000); - - BluetoothCodecConfig bcc2_same = - buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC, - BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, - BluetoothCodecConfig.SAMPLE_RATE_44100, - BluetoothCodecConfig.BITS_PER_SAMPLE_16, - BluetoothCodecConfig.CHANNEL_MODE_STEREO, - 1000, 2000, 3000, 4000); - assertTrue(bcc1.equals(bcc2_same)); - - BluetoothCodecConfig bcc3_codec_type = - buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_AAC, - BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, - BluetoothCodecConfig.SAMPLE_RATE_44100, - BluetoothCodecConfig.BITS_PER_SAMPLE_16, - BluetoothCodecConfig.CHANNEL_MODE_STEREO, - 1000, 2000, 3000, 4000); - assertFalse(bcc1.equals(bcc3_codec_type)); - - BluetoothCodecConfig bcc4_codec_priority = - buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC, - BluetoothCodecConfig.CODEC_PRIORITY_HIGHEST, - BluetoothCodecConfig.SAMPLE_RATE_44100, - BluetoothCodecConfig.BITS_PER_SAMPLE_16, - BluetoothCodecConfig.CHANNEL_MODE_STEREO, - 1000, 2000, 3000, 4000); - assertFalse(bcc1.equals(bcc4_codec_priority)); - - BluetoothCodecConfig bcc5_sample_rate = - buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC, - BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, - BluetoothCodecConfig.SAMPLE_RATE_48000, - BluetoothCodecConfig.BITS_PER_SAMPLE_16, - BluetoothCodecConfig.CHANNEL_MODE_STEREO, - 1000, 2000, 3000, 4000); - assertFalse(bcc1.equals(bcc5_sample_rate)); - - BluetoothCodecConfig bcc6_bits_per_sample = - buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC, - BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, - BluetoothCodecConfig.SAMPLE_RATE_44100, - BluetoothCodecConfig.BITS_PER_SAMPLE_24, - BluetoothCodecConfig.CHANNEL_MODE_STEREO, - 1000, 2000, 3000, 4000); - assertFalse(bcc1.equals(bcc6_bits_per_sample)); - - BluetoothCodecConfig bcc7_channel_mode = - buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC, - BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, - BluetoothCodecConfig.SAMPLE_RATE_44100, - BluetoothCodecConfig.BITS_PER_SAMPLE_16, - BluetoothCodecConfig.CHANNEL_MODE_MONO, - 1000, 2000, 3000, 4000); - assertFalse(bcc1.equals(bcc7_channel_mode)); - - BluetoothCodecConfig bcc8_codec_specific1 = - buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC, - BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, - BluetoothCodecConfig.SAMPLE_RATE_44100, - BluetoothCodecConfig.BITS_PER_SAMPLE_16, - BluetoothCodecConfig.CHANNEL_MODE_STEREO, - 1001, 2000, 3000, 4000); - assertFalse(bcc1.equals(bcc8_codec_specific1)); - - BluetoothCodecConfig bcc9_codec_specific2 = - buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC, - BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, - BluetoothCodecConfig.SAMPLE_RATE_44100, - BluetoothCodecConfig.BITS_PER_SAMPLE_16, - BluetoothCodecConfig.CHANNEL_MODE_STEREO, - 1000, 2002, 3000, 4000); - assertFalse(bcc1.equals(bcc9_codec_specific2)); - - BluetoothCodecConfig bcc10_codec_specific3 = - buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC, - BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, - BluetoothCodecConfig.SAMPLE_RATE_44100, - BluetoothCodecConfig.BITS_PER_SAMPLE_16, - BluetoothCodecConfig.CHANNEL_MODE_STEREO, - 1000, 2000, 3003, 4000); - assertFalse(bcc1.equals(bcc10_codec_specific3)); - - BluetoothCodecConfig bcc11_codec_specific4 = - buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC, - BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, - BluetoothCodecConfig.SAMPLE_RATE_44100, - BluetoothCodecConfig.BITS_PER_SAMPLE_16, - BluetoothCodecConfig.CHANNEL_MODE_STEREO, - 1000, 2000, 3000, 4004); - assertFalse(bcc1.equals(bcc11_codec_specific4)); - } - - private BluetoothCodecConfig buildBluetoothCodecConfig(int sourceCodecType, - int codecPriority, int sampleRate, int bitsPerSample, int channelMode, - long codecSpecific1, long codecSpecific2, long codecSpecific3, long codecSpecific4) { - return new BluetoothCodecConfig.Builder() - .setCodecType(sourceCodecType) - .setCodecPriority(codecPriority) - .setSampleRate(sampleRate) - .setBitsPerSample(bitsPerSample) - .setChannelMode(channelMode) - .setCodecSpecific1(codecSpecific1) - .setCodecSpecific2(codecSpecific2) - .setCodecSpecific3(codecSpecific3) - .setCodecSpecific4(codecSpecific4) - .build(); - - } -} diff --git a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothCodecStatusTest.java b/core/tests/bluetoothtests/src/android/bluetooth/BluetoothCodecStatusTest.java deleted file mode 100644 index 1cb2dcae865ca2ed3a2b6dab5c4d5b376c0c25e6..0000000000000000000000000000000000000000 --- a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothCodecStatusTest.java +++ /dev/null @@ -1,493 +0,0 @@ -/* - * Copyright 2018 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.bluetooth; - -import android.test.suitebuilder.annotation.SmallTest; - -import junit.framework.TestCase; - -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; - -/** - * Unit test cases for {@link BluetoothCodecStatus}. - *

    - * To run this test, use: - * runtest --path core/tests/bluetoothtests/src/android/bluetooth/BluetoothCodecStatusTest.java - */ -public class BluetoothCodecStatusTest extends TestCase { - - // Codec configs: A and B are same; C is different - private static final BluetoothCodecConfig config_A = - buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC, - BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, - BluetoothCodecConfig.SAMPLE_RATE_44100, - BluetoothCodecConfig.BITS_PER_SAMPLE_16, - BluetoothCodecConfig.CHANNEL_MODE_STEREO, - 1000, 2000, 3000, 4000); - - private static final BluetoothCodecConfig config_B = - buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC, - BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, - BluetoothCodecConfig.SAMPLE_RATE_44100, - BluetoothCodecConfig.BITS_PER_SAMPLE_16, - BluetoothCodecConfig.CHANNEL_MODE_STEREO, - 1000, 2000, 3000, 4000); - - private static final BluetoothCodecConfig config_C = - buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_AAC, - BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, - BluetoothCodecConfig.SAMPLE_RATE_44100, - BluetoothCodecConfig.BITS_PER_SAMPLE_16, - BluetoothCodecConfig.CHANNEL_MODE_STEREO, - 1000, 2000, 3000, 4000); - - // Local capabilities: A and B are same; C is different - private static final BluetoothCodecConfig local_capability1_A = - buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC, - BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, - BluetoothCodecConfig.SAMPLE_RATE_44100 | - BluetoothCodecConfig.SAMPLE_RATE_48000, - BluetoothCodecConfig.BITS_PER_SAMPLE_16, - BluetoothCodecConfig.CHANNEL_MODE_STEREO | - BluetoothCodecConfig.CHANNEL_MODE_MONO, - 1000, 2000, 3000, 4000); - - private static final BluetoothCodecConfig local_capability1_B = - buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC, - BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, - BluetoothCodecConfig.SAMPLE_RATE_44100 | - BluetoothCodecConfig.SAMPLE_RATE_48000, - BluetoothCodecConfig.BITS_PER_SAMPLE_16, - BluetoothCodecConfig.CHANNEL_MODE_STEREO | - BluetoothCodecConfig.CHANNEL_MODE_MONO, - 1000, 2000, 3000, 4000); - - private static final BluetoothCodecConfig local_capability1_C = - buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC, - BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, - BluetoothCodecConfig.SAMPLE_RATE_44100 | - BluetoothCodecConfig.SAMPLE_RATE_48000, - BluetoothCodecConfig.BITS_PER_SAMPLE_16, - BluetoothCodecConfig.CHANNEL_MODE_STEREO, - 1000, 2000, 3000, 4000); - - - private static final BluetoothCodecConfig local_capability2_A = - buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_AAC, - BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, - BluetoothCodecConfig.SAMPLE_RATE_44100 | - BluetoothCodecConfig.SAMPLE_RATE_48000, - BluetoothCodecConfig.BITS_PER_SAMPLE_16, - BluetoothCodecConfig.CHANNEL_MODE_STEREO | - BluetoothCodecConfig.CHANNEL_MODE_MONO, - 1000, 2000, 3000, 4000); - - private static final BluetoothCodecConfig local_capability2_B = - buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_AAC, - BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, - BluetoothCodecConfig.SAMPLE_RATE_44100 | - BluetoothCodecConfig.SAMPLE_RATE_48000, - BluetoothCodecConfig.BITS_PER_SAMPLE_16, - BluetoothCodecConfig.CHANNEL_MODE_STEREO | - BluetoothCodecConfig.CHANNEL_MODE_MONO, - 1000, 2000, 3000, 4000); - - private static final BluetoothCodecConfig local_capability2_C = - buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_AAC, - BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, - BluetoothCodecConfig.SAMPLE_RATE_44100 | - BluetoothCodecConfig.SAMPLE_RATE_48000, - BluetoothCodecConfig.BITS_PER_SAMPLE_16, - BluetoothCodecConfig.CHANNEL_MODE_STEREO, - 1000, 2000, 3000, 4000); - - private static final BluetoothCodecConfig local_capability3_A = - buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX, - BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, - BluetoothCodecConfig.SAMPLE_RATE_44100 | - BluetoothCodecConfig.SAMPLE_RATE_48000, - BluetoothCodecConfig.BITS_PER_SAMPLE_16, - BluetoothCodecConfig.CHANNEL_MODE_STEREO | - BluetoothCodecConfig.CHANNEL_MODE_MONO, - 1000, 2000, 3000, 4000); - - private static final BluetoothCodecConfig local_capability3_B = - buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX, - BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, - BluetoothCodecConfig.SAMPLE_RATE_44100 | - BluetoothCodecConfig.SAMPLE_RATE_48000, - BluetoothCodecConfig.BITS_PER_SAMPLE_16, - BluetoothCodecConfig.CHANNEL_MODE_STEREO | - BluetoothCodecConfig.CHANNEL_MODE_MONO, - 1000, 2000, 3000, 4000); - - private static final BluetoothCodecConfig local_capability3_C = - buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX, - BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, - BluetoothCodecConfig.SAMPLE_RATE_44100 | - BluetoothCodecConfig.SAMPLE_RATE_48000, - BluetoothCodecConfig.BITS_PER_SAMPLE_16, - BluetoothCodecConfig.CHANNEL_MODE_STEREO, - 1000, 2000, 3000, 4000); - - private static final BluetoothCodecConfig local_capability4_A = - buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX_HD, - BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, - BluetoothCodecConfig.SAMPLE_RATE_44100 | - BluetoothCodecConfig.SAMPLE_RATE_48000, - BluetoothCodecConfig.BITS_PER_SAMPLE_24, - BluetoothCodecConfig.CHANNEL_MODE_STEREO | - BluetoothCodecConfig.CHANNEL_MODE_MONO, - 1000, 2000, 3000, 4000); - - private static final BluetoothCodecConfig local_capability4_B = - buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX_HD, - BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, - BluetoothCodecConfig.SAMPLE_RATE_44100 | - BluetoothCodecConfig.SAMPLE_RATE_48000, - BluetoothCodecConfig.BITS_PER_SAMPLE_24, - BluetoothCodecConfig.CHANNEL_MODE_STEREO | - BluetoothCodecConfig.CHANNEL_MODE_MONO, - 1000, 2000, 3000, 4000); - - private static final BluetoothCodecConfig local_capability4_C = - buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX_HD, - BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, - BluetoothCodecConfig.SAMPLE_RATE_44100 | - BluetoothCodecConfig.SAMPLE_RATE_48000, - BluetoothCodecConfig.BITS_PER_SAMPLE_24, - BluetoothCodecConfig.CHANNEL_MODE_STEREO, - 1000, 2000, 3000, 4000); - - private static final BluetoothCodecConfig local_capability5_A = - buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_LDAC, - BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, - BluetoothCodecConfig.SAMPLE_RATE_44100 | - BluetoothCodecConfig.SAMPLE_RATE_48000 | - BluetoothCodecConfig.SAMPLE_RATE_88200 | - BluetoothCodecConfig.SAMPLE_RATE_96000, - BluetoothCodecConfig.BITS_PER_SAMPLE_16 | - BluetoothCodecConfig.BITS_PER_SAMPLE_24 | - BluetoothCodecConfig.BITS_PER_SAMPLE_32, - BluetoothCodecConfig.CHANNEL_MODE_STEREO | - BluetoothCodecConfig.CHANNEL_MODE_MONO, - 1000, 2000, 3000, 4000); - - private static final BluetoothCodecConfig local_capability5_B = - buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_LDAC, - BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, - BluetoothCodecConfig.SAMPLE_RATE_44100 | - BluetoothCodecConfig.SAMPLE_RATE_48000 | - BluetoothCodecConfig.SAMPLE_RATE_88200 | - BluetoothCodecConfig.SAMPLE_RATE_96000, - BluetoothCodecConfig.BITS_PER_SAMPLE_16 | - BluetoothCodecConfig.BITS_PER_SAMPLE_24 | - BluetoothCodecConfig.BITS_PER_SAMPLE_32, - BluetoothCodecConfig.CHANNEL_MODE_STEREO | - BluetoothCodecConfig.CHANNEL_MODE_MONO, - 1000, 2000, 3000, 4000); - - private static final BluetoothCodecConfig local_capability5_C = - buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_LDAC, - BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, - BluetoothCodecConfig.SAMPLE_RATE_44100 | - BluetoothCodecConfig.SAMPLE_RATE_48000 | - BluetoothCodecConfig.SAMPLE_RATE_88200 | - BluetoothCodecConfig.SAMPLE_RATE_96000, - BluetoothCodecConfig.BITS_PER_SAMPLE_16 | - BluetoothCodecConfig.BITS_PER_SAMPLE_24 | - BluetoothCodecConfig.BITS_PER_SAMPLE_32, - BluetoothCodecConfig.CHANNEL_MODE_STEREO, - 1000, 2000, 3000, 4000); - - - // Selectable capabilities: A and B are same; C is different - private static final BluetoothCodecConfig selectable_capability1_A = - buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC, - BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, - BluetoothCodecConfig.SAMPLE_RATE_44100, - BluetoothCodecConfig.BITS_PER_SAMPLE_16, - BluetoothCodecConfig.CHANNEL_MODE_STEREO | - BluetoothCodecConfig.CHANNEL_MODE_MONO, - 1000, 2000, 3000, 4000); - - private static final BluetoothCodecConfig selectable_capability1_B = - buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC, - BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, - BluetoothCodecConfig.SAMPLE_RATE_44100, - BluetoothCodecConfig.BITS_PER_SAMPLE_16, - BluetoothCodecConfig.CHANNEL_MODE_STEREO | - BluetoothCodecConfig.CHANNEL_MODE_MONO, - 1000, 2000, 3000, 4000); - - private static final BluetoothCodecConfig selectable_capability1_C = - buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC, - BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, - BluetoothCodecConfig.SAMPLE_RATE_44100, - BluetoothCodecConfig.BITS_PER_SAMPLE_16, - BluetoothCodecConfig.CHANNEL_MODE_STEREO, - 1000, 2000, 3000, 4000); - - private static final BluetoothCodecConfig selectable_capability2_A = - buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_AAC, - BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, - BluetoothCodecConfig.SAMPLE_RATE_44100, - BluetoothCodecConfig.BITS_PER_SAMPLE_16, - BluetoothCodecConfig.CHANNEL_MODE_STEREO | - BluetoothCodecConfig.CHANNEL_MODE_MONO, - 1000, 2000, 3000, 4000); - - private static final BluetoothCodecConfig selectable_capability2_B = - buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_AAC, - BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, - BluetoothCodecConfig.SAMPLE_RATE_44100, - BluetoothCodecConfig.BITS_PER_SAMPLE_16, - BluetoothCodecConfig.CHANNEL_MODE_STEREO | - BluetoothCodecConfig.CHANNEL_MODE_MONO, - 1000, 2000, 3000, 4000); - - private static final BluetoothCodecConfig selectable_capability2_C = - buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_AAC, - BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, - BluetoothCodecConfig.SAMPLE_RATE_44100, - BluetoothCodecConfig.BITS_PER_SAMPLE_16, - BluetoothCodecConfig.CHANNEL_MODE_STEREO, - 1000, 2000, 3000, 4000); - - private static final BluetoothCodecConfig selectable_capability3_A = - buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX, - BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, - BluetoothCodecConfig.SAMPLE_RATE_44100, - BluetoothCodecConfig.BITS_PER_SAMPLE_16, - BluetoothCodecConfig.CHANNEL_MODE_STEREO | - BluetoothCodecConfig.CHANNEL_MODE_MONO, - 1000, 2000, 3000, 4000); - - private static final BluetoothCodecConfig selectable_capability3_B = - buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX, - BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, - BluetoothCodecConfig.SAMPLE_RATE_44100, - BluetoothCodecConfig.BITS_PER_SAMPLE_16, - BluetoothCodecConfig.CHANNEL_MODE_STEREO | - BluetoothCodecConfig.CHANNEL_MODE_MONO, - 1000, 2000, 3000, 4000); - - private static final BluetoothCodecConfig selectable_capability3_C = - buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX, - BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, - BluetoothCodecConfig.SAMPLE_RATE_44100, - BluetoothCodecConfig.BITS_PER_SAMPLE_16, - BluetoothCodecConfig.CHANNEL_MODE_STEREO, - 1000, 2000, 3000, 4000); - - private static final BluetoothCodecConfig selectable_capability4_A = - buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX_HD, - BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, - BluetoothCodecConfig.SAMPLE_RATE_44100, - BluetoothCodecConfig.BITS_PER_SAMPLE_24, - BluetoothCodecConfig.CHANNEL_MODE_STEREO | - BluetoothCodecConfig.CHANNEL_MODE_MONO, - 1000, 2000, 3000, 4000); - - private static final BluetoothCodecConfig selectable_capability4_B = - buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX_HD, - BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, - BluetoothCodecConfig.SAMPLE_RATE_44100, - BluetoothCodecConfig.BITS_PER_SAMPLE_24, - BluetoothCodecConfig.CHANNEL_MODE_STEREO | - BluetoothCodecConfig.CHANNEL_MODE_MONO, - 1000, 2000, 3000, 4000); - - private static final BluetoothCodecConfig selectable_capability4_C = - buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX_HD, - BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, - BluetoothCodecConfig.SAMPLE_RATE_44100, - BluetoothCodecConfig.BITS_PER_SAMPLE_24, - BluetoothCodecConfig.CHANNEL_MODE_STEREO, - 1000, 2000, 3000, 4000); - - private static final BluetoothCodecConfig selectable_capability5_A = - buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_LDAC, - BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, - BluetoothCodecConfig.SAMPLE_RATE_44100 | - BluetoothCodecConfig.SAMPLE_RATE_48000 | - BluetoothCodecConfig.SAMPLE_RATE_88200 | - BluetoothCodecConfig.SAMPLE_RATE_96000, - BluetoothCodecConfig.BITS_PER_SAMPLE_16 | - BluetoothCodecConfig.BITS_PER_SAMPLE_24 | - BluetoothCodecConfig.BITS_PER_SAMPLE_32, - BluetoothCodecConfig.CHANNEL_MODE_STEREO | - BluetoothCodecConfig.CHANNEL_MODE_MONO, - 1000, 2000, 3000, 4000); - - private static final BluetoothCodecConfig selectable_capability5_B = - buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_LDAC, - BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, - BluetoothCodecConfig.SAMPLE_RATE_44100 | - BluetoothCodecConfig.SAMPLE_RATE_48000 | - BluetoothCodecConfig.SAMPLE_RATE_88200 | - BluetoothCodecConfig.SAMPLE_RATE_96000, - BluetoothCodecConfig.BITS_PER_SAMPLE_16 | - BluetoothCodecConfig.BITS_PER_SAMPLE_24 | - BluetoothCodecConfig.BITS_PER_SAMPLE_32, - BluetoothCodecConfig.CHANNEL_MODE_STEREO | - BluetoothCodecConfig.CHANNEL_MODE_MONO, - 1000, 2000, 3000, 4000); - - private static final BluetoothCodecConfig selectable_capability5_C = - buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_LDAC, - BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, - BluetoothCodecConfig.SAMPLE_RATE_44100 | - BluetoothCodecConfig.SAMPLE_RATE_48000 | - BluetoothCodecConfig.SAMPLE_RATE_88200 | - BluetoothCodecConfig.SAMPLE_RATE_96000, - BluetoothCodecConfig.BITS_PER_SAMPLE_16 | - BluetoothCodecConfig.BITS_PER_SAMPLE_24 | - BluetoothCodecConfig.BITS_PER_SAMPLE_32, - BluetoothCodecConfig.CHANNEL_MODE_STEREO, - 1000, 2000, 3000, 4000); - - private static final List LOCAL_CAPABILITY_A = - new ArrayList() {{ - add(local_capability1_A); - add(local_capability2_A); - add(local_capability3_A); - add(local_capability4_A); - add(local_capability5_A); - }}; - - private static final List LOCAL_CAPABILITY_B = - new ArrayList() {{ - add(local_capability1_B); - add(local_capability2_B); - add(local_capability3_B); - add(local_capability4_B); - add(local_capability5_B); - }}; - - private static final List LOCAL_CAPABILITY_B_REORDERED = - new ArrayList() {{ - add(local_capability5_B); - add(local_capability4_B); - add(local_capability2_B); - add(local_capability3_B); - add(local_capability1_B); - }}; - - private static final List LOCAL_CAPABILITY_C = - new ArrayList() {{ - add(local_capability1_C); - add(local_capability2_C); - add(local_capability3_C); - add(local_capability4_C); - add(local_capability5_C); - }}; - - private static final List SELECTABLE_CAPABILITY_A = - new ArrayList() {{ - add(selectable_capability1_A); - add(selectable_capability2_A); - add(selectable_capability3_A); - add(selectable_capability4_A); - add(selectable_capability5_A); - }}; - - private static final List SELECTABLE_CAPABILITY_B = - new ArrayList() {{ - add(selectable_capability1_B); - add(selectable_capability2_B); - add(selectable_capability3_B); - add(selectable_capability4_B); - add(selectable_capability5_B); - }}; - - private static final List SELECTABLE_CAPABILITY_B_REORDERED = - new ArrayList() {{ - add(selectable_capability5_B); - add(selectable_capability4_B); - add(selectable_capability2_B); - add(selectable_capability3_B); - add(selectable_capability1_B); - }}; - - private static final List SELECTABLE_CAPABILITY_C = - new ArrayList() {{ - add(selectable_capability1_C); - add(selectable_capability2_C); - add(selectable_capability3_C); - add(selectable_capability4_C); - add(selectable_capability5_C); - }}; - - private static final BluetoothCodecStatus bcs_A = - new BluetoothCodecStatus(config_A, LOCAL_CAPABILITY_A, SELECTABLE_CAPABILITY_A); - private static final BluetoothCodecStatus bcs_B = - new BluetoothCodecStatus(config_B, LOCAL_CAPABILITY_B, SELECTABLE_CAPABILITY_B); - private static final BluetoothCodecStatus bcs_B_reordered = - new BluetoothCodecStatus(config_B, LOCAL_CAPABILITY_B_REORDERED, - SELECTABLE_CAPABILITY_B_REORDERED); - private static final BluetoothCodecStatus bcs_C = - new BluetoothCodecStatus(config_C, LOCAL_CAPABILITY_C, SELECTABLE_CAPABILITY_C); - - @SmallTest - public void testBluetoothCodecStatus_get_methods() { - - assertTrue(Objects.equals(bcs_A.getCodecConfig(), config_A)); - assertTrue(Objects.equals(bcs_A.getCodecConfig(), config_B)); - assertFalse(Objects.equals(bcs_A.getCodecConfig(), config_C)); - - assertTrue(bcs_A.getCodecsLocalCapabilities().equals(LOCAL_CAPABILITY_A)); - assertTrue(bcs_A.getCodecsLocalCapabilities().equals(LOCAL_CAPABILITY_B)); - assertFalse(bcs_A.getCodecsLocalCapabilities().equals(LOCAL_CAPABILITY_C)); - - assertTrue(bcs_A.getCodecsSelectableCapabilities() - .equals(SELECTABLE_CAPABILITY_A)); - assertTrue(bcs_A.getCodecsSelectableCapabilities() - .equals(SELECTABLE_CAPABILITY_B)); - assertFalse(bcs_A.getCodecsSelectableCapabilities() - .equals(SELECTABLE_CAPABILITY_C)); - } - - @SmallTest - public void testBluetoothCodecStatus_equals() { - assertTrue(bcs_A.equals(bcs_B)); - assertTrue(bcs_B.equals(bcs_A)); - assertTrue(bcs_A.equals(bcs_B_reordered)); - assertTrue(bcs_B_reordered.equals(bcs_A)); - assertFalse(bcs_A.equals(bcs_C)); - assertFalse(bcs_C.equals(bcs_A)); - } - - private static BluetoothCodecConfig buildBluetoothCodecConfig(int sourceCodecType, - int codecPriority, int sampleRate, int bitsPerSample, int channelMode, - long codecSpecific1, long codecSpecific2, long codecSpecific3, long codecSpecific4) { - return new BluetoothCodecConfig.Builder() - .setCodecType(sourceCodecType) - .setCodecPriority(codecPriority) - .setSampleRate(sampleRate) - .setBitsPerSample(bitsPerSample) - .setChannelMode(channelMode) - .setCodecSpecific1(codecSpecific1) - .setCodecSpecific2(codecSpecific2) - .setCodecSpecific3(codecSpecific3) - .setCodecSpecific4(codecSpecific4) - .build(); - - } -} diff --git a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothInstrumentation.java b/core/tests/bluetoothtests/src/android/bluetooth/BluetoothInstrumentation.java deleted file mode 100644 index 37b2a50ed670a9d8934e7f4ef23b52d55a2ff127..0000000000000000000000000000000000000000 --- a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothInstrumentation.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright (C) 2014 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.bluetooth; - -import android.app.Activity; -import android.app.Instrumentation; -import android.content.Context; -import android.os.Bundle; - -import junit.framework.Assert; - -import java.util.Set; - -public class BluetoothInstrumentation extends Instrumentation { - - private BluetoothTestUtils mUtils = null; - private BluetoothAdapter mAdapter = null; - private Bundle mArgs = null; - private Bundle mSuccessResult = null; - - private BluetoothTestUtils getBluetoothTestUtils() { - if (mUtils == null) { - mUtils = new BluetoothTestUtils(getContext(), - BluetoothInstrumentation.class.getSimpleName()); - } - return mUtils; - } - - private BluetoothAdapter getBluetoothAdapter() { - if (mAdapter == null) { - mAdapter = ((BluetoothManager)getContext().getSystemService( - Context.BLUETOOTH_SERVICE)).getAdapter(); - } - return mAdapter; - } - - @Override - public void onCreate(Bundle arguments) { - super.onCreate(arguments); - mArgs = arguments; - // create the default result response, but only use it in success code path - mSuccessResult = new Bundle(); - mSuccessResult.putString("result", "SUCCESS"); - start(); - } - - @Override - public void onStart() { - String command = mArgs.getString("command"); - if ("enable".equals(command)) { - enable(); - } else if ("disable".equals(command)) { - disable(); - } else if ("unpairAll".equals(command)) { - unpairAll(); - } else if ("getName".equals(command)) { - getName(); - } else if ("getAddress".equals(command)) { - getAddress(); - } else if ("getBondedDevices".equals(command)) { - getBondedDevices(); - } else { - finish(null); - } - } - - public void enable() { - getBluetoothTestUtils().enable(getBluetoothAdapter()); - finish(mSuccessResult); - } - - public void disable() { - getBluetoothTestUtils().disable(getBluetoothAdapter()); - finish(mSuccessResult); - } - - public void unpairAll() { - getBluetoothTestUtils().unpairAll(getBluetoothAdapter()); - finish(mSuccessResult); - } - - public void getName() { - String name = getBluetoothAdapter().getName(); - mSuccessResult.putString("name", name); - finish(mSuccessResult); - } - - public void getAddress() { - String name = getBluetoothAdapter().getAddress(); - mSuccessResult.putString("address", name); - finish(mSuccessResult); - } - - public void getBondedDevices() { - Set devices = getBluetoothAdapter().getBondedDevices(); - int i = 0; - for (BluetoothDevice device : devices) { - mSuccessResult.putString(String.format("device-%02d", i), device.getAddress()); - i++; - } - finish(mSuccessResult); - } - - public void finish(Bundle result) { - if (result == null) { - result = new Bundle(); - } - finish(Activity.RESULT_OK, result); - } -} diff --git a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothLeAudioCodecConfigTest.java b/core/tests/bluetoothtests/src/android/bluetooth/BluetoothLeAudioCodecConfigTest.java deleted file mode 100644 index c3d707cd759696a112bdb86ebca8c9ab7b738afa..0000000000000000000000000000000000000000 --- a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothLeAudioCodecConfigTest.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * 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.bluetooth; - -import android.test.suitebuilder.annotation.SmallTest; - -import junit.framework.TestCase; - -/** - * Unit test cases for {@link BluetoothLeAudioCodecConfig}. - */ -public class BluetoothLeAudioCodecConfigTest extends TestCase { - private int[] mCodecTypeArray = new int[] { - BluetoothLeAudioCodecConfig.SOURCE_CODEC_TYPE_LC3, - BluetoothLeAudioCodecConfig.SOURCE_CODEC_TYPE_INVALID, - }; - - @SmallTest - public void testBluetoothLeAudioCodecConfig_valid_get_methods() { - - for (int codecIdx = 0; codecIdx < mCodecTypeArray.length; codecIdx++) { - int codecType = mCodecTypeArray[codecIdx]; - - BluetoothLeAudioCodecConfig leAudioCodecConfig = - buildBluetoothLeAudioCodecConfig(codecType); - - if (codecType == BluetoothLeAudioCodecConfig.SOURCE_CODEC_TYPE_LC3) { - assertEquals("LC3", leAudioCodecConfig.getCodecName()); - } - if (codecType == BluetoothLeAudioCodecConfig.SOURCE_CODEC_TYPE_INVALID) { - assertEquals("INVALID CODEC", leAudioCodecConfig.getCodecName()); - } - - assertEquals(codecType, leAudioCodecConfig.getCodecType()); - } - } - - private BluetoothLeAudioCodecConfig buildBluetoothLeAudioCodecConfig(int sourceCodecType) { - return new BluetoothLeAudioCodecConfig.Builder() - .setCodecType(sourceCodecType) - .build(); - - } -} diff --git a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothRebootStressTest.java b/core/tests/bluetoothtests/src/android/bluetooth/BluetoothRebootStressTest.java deleted file mode 100644 index 33e9dd7fabc6c8460655c168bdcca027323a8b85..0000000000000000000000000000000000000000 --- a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothRebootStressTest.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright (C) 2010 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.bluetooth; - -import android.content.Context; -import android.test.InstrumentationTestCase; - -/** - * Instrumentation test case for stress test involving rebooting the device. - *

    - * This test case tests that bluetooth is enabled after a device reboot. Because - * the device will reboot, the instrumentation must be driven by a script on the - * host side. - */ -public class BluetoothRebootStressTest extends InstrumentationTestCase { - private static final String TAG = "BluetoothRebootStressTest"; - private static final String OUTPUT_FILE = "BluetoothRebootStressTestOutput.txt"; - - private BluetoothTestUtils mTestUtils; - - @Override - protected void setUp() throws Exception { - super.setUp(); - - Context context = getInstrumentation().getTargetContext(); - mTestUtils = new BluetoothTestUtils(context, TAG, OUTPUT_FILE); - } - - @Override - protected void tearDown() throws Exception { - super.tearDown(); - - mTestUtils.close(); - } - - /** - * Test method used to start the test by turning bluetooth on. - */ - public void testStart() { - BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); - mTestUtils.enable(adapter); - } - - /** - * Test method used in the middle iterations of the test to check if - * bluetooth is on. Does not toggle bluetooth after the check. Assumes that - * bluetooth has been turned on by {@code #testStart()} - */ - public void testMiddleNoToggle() { - BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); - - assertTrue(adapter.isEnabled()); - } - - /** - * Test method used in the middle iterations of the test to check if - * bluetooth is on. Toggles bluetooth after the check. Assumes that - * bluetooth has been turned on by {@code #testStart()} - */ - public void testMiddleToggle() { - BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); - - assertTrue(adapter.isEnabled()); - - mTestUtils.disable(adapter); - mTestUtils.enable(adapter); - } - - /** - * Test method used in the stop the test by turning bluetooth off. Assumes - * that bluetooth has been turned on by {@code #testStart()} - */ - public void testStop() { - BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); - - assertTrue(adapter.isEnabled()); - - mTestUtils.disable(adapter); - } -} diff --git a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothStressTest.java b/core/tests/bluetoothtests/src/android/bluetooth/BluetoothStressTest.java deleted file mode 100644 index 89dbe3f75b56f9d9deab04e2f1c0ab6ff3666c20..0000000000000000000000000000000000000000 --- a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothStressTest.java +++ /dev/null @@ -1,393 +0,0 @@ -/* - * Copyright (C) 2010 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.bluetooth; - -import android.content.Context; -import android.test.InstrumentationTestCase; - -/** - * Stress test suite for Bluetooth related functions. - * - * Includes tests for enabling/disabling bluetooth, enabling/disabling discoverable mode, - * starting/stopping scans, connecting/disconnecting to HFP, A2DP, HID, PAN profiles, and verifying - * that remote connections/disconnections occur for the PAN profile. - *

    - * This test suite uses {@link android.bluetooth.BluetoothTestRunner} to for parameters such as the - * number of iterations and the addresses of remote Bluetooth devices. - */ -public class BluetoothStressTest extends InstrumentationTestCase { - private static final String TAG = "BluetoothStressTest"; - private static final String OUTPUT_FILE = "BluetoothStressTestOutput.txt"; - /** The amount of time to sleep between issuing start/stop SCO in ms. */ - private static final long SCO_SLEEP_TIME = 2 * 1000; - - private BluetoothAdapter mAdapter; - private BluetoothTestUtils mTestUtils; - - @Override - protected void setUp() throws Exception { - super.setUp(); - - Context context = getInstrumentation().getTargetContext(); - mAdapter = BluetoothAdapter.getDefaultAdapter(); - mTestUtils = new BluetoothTestUtils(context, TAG, OUTPUT_FILE); - - // Start all tests in a disabled state. - if (mAdapter.isEnabled()) { - mTestUtils.disable(mAdapter); - } - } - - @Override - protected void tearDown() throws Exception { - super.tearDown(); - mTestUtils.close(); - } - - /** - * Stress test for enabling and disabling Bluetooth. - */ - public void testEnable() { - int iterations = BluetoothTestRunner.sEnableIterations; - if (iterations == 0) { - return; - } - - for (int i = 0; i < iterations; i++) { - mTestUtils.writeOutput("enable iteration " + (i + 1) + " of " + iterations); - mTestUtils.enable(mAdapter); - mTestUtils.disable(mAdapter); - } - } - - /** - * Stress test for putting the device in and taking the device out of discoverable mode. - */ - public void testDiscoverable() { - int iterations = BluetoothTestRunner.sDiscoverableIterations; - if (iterations == 0) { - return; - } - - mTestUtils.enable(mAdapter); - mTestUtils.undiscoverable(mAdapter); - - for (int i = 0; i < iterations; i++) { - mTestUtils.writeOutput("discoverable iteration " + (i + 1) + " of " + iterations); - mTestUtils.discoverable(mAdapter); - mTestUtils.undiscoverable(mAdapter); - } - } - - /** - * Stress test for starting and stopping Bluetooth scans. - */ - public void testScan() { - int iterations = BluetoothTestRunner.sScanIterations; - if (iterations == 0) { - return; - } - - mTestUtils.enable(mAdapter); - mTestUtils.stopScan(mAdapter); - - for (int i = 0; i < iterations; i++) { - mTestUtils.writeOutput("scan iteration " + (i + 1) + " of " + iterations); - mTestUtils.startScan(mAdapter); - mTestUtils.stopScan(mAdapter); - } - } - - /** - * Stress test for enabling and disabling the PAN NAP profile. - */ - public void testEnablePan() { - int iterations = BluetoothTestRunner.sEnablePanIterations; - if (iterations == 0) { - return; - } - - mTestUtils.enable(mAdapter); - mTestUtils.disablePan(mAdapter); - - for (int i = 0; i < iterations; i++) { - mTestUtils.writeOutput("testEnablePan iteration " + (i + 1) + " of " - + iterations); - mTestUtils.enablePan(mAdapter); - mTestUtils.disablePan(mAdapter); - } - } - - /** - * Stress test for pairing and unpairing with a remote device. - *

    - * In this test, the local device initiates pairing with a remote device, and then unpairs with - * the device after the pairing has successfully completed. - */ - public void testPair() { - int iterations = BluetoothTestRunner.sPairIterations; - if (iterations == 0) { - return; - } - - BluetoothDevice device = mAdapter.getRemoteDevice(BluetoothTestRunner.sDeviceAddress); - mTestUtils.enable(mAdapter); - mTestUtils.unpair(mAdapter, device); - - for (int i = 0; i < iterations; i++) { - mTestUtils.writeOutput("pair iteration " + (i + 1) + " of " + iterations); - mTestUtils.pair(mAdapter, device, BluetoothTestRunner.sDevicePairPasskey, - BluetoothTestRunner.sDevicePairPin); - mTestUtils.unpair(mAdapter, device); - } - } - - /** - * Stress test for accepting a pairing request and unpairing with a remote device. - *

    - * In this test, the local device waits for a pairing request from a remote device. It accepts - * the request and then unpairs after the paring has successfully completed. - */ - public void testAcceptPair() { - int iterations = BluetoothTestRunner.sPairIterations; - if (iterations == 0) { - return; - } - BluetoothDevice device = mAdapter.getRemoteDevice(BluetoothTestRunner.sDeviceAddress); - mTestUtils.enable(mAdapter); - mTestUtils.unpair(mAdapter, device); - - for (int i = 0; i < iterations; i++) { - mTestUtils.writeOutput("acceptPair iteration " + (i + 1) + " of " + iterations); - mTestUtils.acceptPair(mAdapter, device, BluetoothTestRunner.sDevicePairPasskey, - BluetoothTestRunner.sDevicePairPin); - mTestUtils.unpair(mAdapter, device); - } - } - - /** - * Stress test for connecting and disconnecting with an A2DP source. - *

    - * In this test, the local device plays the role of an A2DP sink, and initiates connections and - * disconnections with an A2DP source. - */ - public void testConnectA2dp() { - int iterations = BluetoothTestRunner.sConnectA2dpIterations; - if (iterations == 0) { - return; - } - - BluetoothDevice device = mAdapter.getRemoteDevice(BluetoothTestRunner.sDeviceAddress); - mTestUtils.enable(mAdapter); - mTestUtils.unpair(mAdapter, device); - mTestUtils.pair(mAdapter, device, BluetoothTestRunner.sDevicePairPasskey, - BluetoothTestRunner.sDevicePairPin); - mTestUtils.disconnectProfile(mAdapter, device, BluetoothProfile.A2DP, null); - - for (int i = 0; i < iterations; i++) { - mTestUtils.writeOutput("connectA2dp iteration " + (i + 1) + " of " + iterations); - mTestUtils.connectProfile(mAdapter, device, BluetoothProfile.A2DP, - String.format("connectA2dp(device=%s)", device)); - mTestUtils.disconnectProfile(mAdapter, device, BluetoothProfile.A2DP, - String.format("disconnectA2dp(device=%s)", device)); - } - - mTestUtils.unpair(mAdapter, device); - } - - /** - * Stress test for connecting and disconnecting the HFP with a hands free device. - *

    - * In this test, the local device plays the role of an HFP audio gateway, and initiates - * connections and disconnections with a hands free device. - */ - public void testConnectHeadset() { - int iterations = BluetoothTestRunner.sConnectHeadsetIterations; - if (iterations == 0) { - return; - } - - BluetoothDevice device = mAdapter.getRemoteDevice(BluetoothTestRunner.sDeviceAddress); - mTestUtils.enable(mAdapter); - mTestUtils.unpair(mAdapter, device); - mTestUtils.pair(mAdapter, device, BluetoothTestRunner.sDevicePairPasskey, - BluetoothTestRunner.sDevicePairPin); - mTestUtils.disconnectProfile(mAdapter, device, BluetoothProfile.HEADSET, null); - - for (int i = 0; i < iterations; i++) { - mTestUtils.writeOutput("connectHeadset iteration " + (i + 1) + " of " + iterations); - mTestUtils.connectProfile(mAdapter, device, BluetoothProfile.HEADSET, - String.format("connectHeadset(device=%s)", device)); - mTestUtils.disconnectProfile(mAdapter, device, BluetoothProfile.HEADSET, - String.format("disconnectHeadset(device=%s)", device)); - } - - mTestUtils.unpair(mAdapter, device); - } - - /** - * Stress test for connecting and disconnecting with a HID device. - *

    - * In this test, the local device plays the role of a HID host, and initiates connections and - * disconnections with a HID device. - */ - public void testConnectInput() { - int iterations = BluetoothTestRunner.sConnectInputIterations; - if (iterations == 0) { - return; - } - - BluetoothDevice device = mAdapter.getRemoteDevice(BluetoothTestRunner.sDeviceAddress); - mTestUtils.enable(mAdapter); - mTestUtils.unpair(mAdapter, device); - mTestUtils.pair(mAdapter, device, BluetoothTestRunner.sDevicePairPasskey, - BluetoothTestRunner.sDevicePairPin); - mTestUtils.disconnectProfile(mAdapter, device, BluetoothProfile.HID_HOST, null); - - for (int i = 0; i < iterations; i++) { - mTestUtils.writeOutput("connectInput iteration " + (i + 1) + " of " + iterations); - mTestUtils.connectProfile(mAdapter, device, BluetoothProfile.HID_HOST, - String.format("connectInput(device=%s)", device)); - mTestUtils.disconnectProfile(mAdapter, device, BluetoothProfile.HID_HOST, - String.format("disconnectInput(device=%s)", device)); - } - - mTestUtils.unpair(mAdapter, device); - } - - /** - * Stress test for connecting and disconnecting with a PAN NAP. - *

    - * In this test, the local device plays the role of a PANU, and initiates connections and - * disconnections with a NAP. - */ - public void testConnectPan() { - int iterations = BluetoothTestRunner.sConnectPanIterations; - if (iterations == 0) { - return; - } - - BluetoothDevice device = mAdapter.getRemoteDevice(BluetoothTestRunner.sDeviceAddress); - mTestUtils.enable(mAdapter); - mTestUtils.unpair(mAdapter, device); - mTestUtils.pair(mAdapter, device, BluetoothTestRunner.sDevicePairPasskey, - BluetoothTestRunner.sDevicePairPin); - - for (int i = 0; i < iterations; i++) { - mTestUtils.writeOutput("connectPan iteration " + (i + 1) + " of " + iterations); - mTestUtils.connectPan(mAdapter, device); - mTestUtils.disconnectPan(mAdapter, device); - } - - mTestUtils.unpair(mAdapter, device); - } - - /** - * Stress test for verifying a PANU connecting and disconnecting with the device. - *

    - * In this test, the local device plays the role of a NAP which a remote PANU connects and - * disconnects from. - */ - public void testIncomingPanConnection() { - int iterations = BluetoothTestRunner.sConnectPanIterations; - if (iterations == 0) { - return; - } - - BluetoothDevice device = mAdapter.getRemoteDevice(BluetoothTestRunner.sDeviceAddress); - mTestUtils.enable(mAdapter); - mTestUtils.disablePan(mAdapter); - mTestUtils.enablePan(mAdapter); - mTestUtils.unpair(mAdapter, device); - mTestUtils.acceptPair(mAdapter, device, BluetoothTestRunner.sDevicePairPasskey, - BluetoothTestRunner.sDevicePairPin); - - for (int i = 0; i < iterations; i++) { - mTestUtils.writeOutput("incomingPanConnection iteration " + (i + 1) + " of " - + iterations); - mTestUtils.incomingPanConnection(mAdapter, device); - mTestUtils.incomingPanDisconnection(mAdapter, device); - } - - mTestUtils.unpair(mAdapter, device); - mTestUtils.disablePan(mAdapter); - } - - /** - * Stress test for verifying that AudioManager can open and close SCO connections. - *

    - * In this test, a HSP connection is opened with an external headset and the SCO connection is - * repeatibly opened and closed. - */ - public void testStartStopSco() { - int iterations = BluetoothTestRunner.sStartStopScoIterations; - if (iterations == 0) { - return; - } - - BluetoothDevice device = mAdapter.getRemoteDevice(BluetoothTestRunner.sDeviceAddress); - mTestUtils.enable(mAdapter); - mTestUtils.unpair(mAdapter, device); - mTestUtils.pair(mAdapter, device, BluetoothTestRunner.sDevicePairPasskey, - BluetoothTestRunner.sDevicePairPin); - mTestUtils.disconnectProfile(mAdapter, device, BluetoothProfile.HEADSET, null); - mTestUtils.connectProfile(mAdapter, device, BluetoothProfile.HEADSET, null); - mTestUtils.stopSco(mAdapter, device); - - for (int i = 0; i < iterations; i++) { - mTestUtils.writeOutput("startStopSco iteration " + (i + 1) + " of " + iterations); - mTestUtils.startSco(mAdapter, device); - sleep(SCO_SLEEP_TIME); - mTestUtils.stopSco(mAdapter, device); - sleep(SCO_SLEEP_TIME); - } - - mTestUtils.disconnectProfile(mAdapter, device, BluetoothProfile.HEADSET, null); - mTestUtils.unpair(mAdapter, device); - } - - /* Make sure there is at least 1 unread message in the last week on remote device */ - public void testMceSetMessageStatus() { - int iterations = BluetoothTestRunner.sMceSetMessageStatusIterations; - if (iterations == 0) { - return; - } - - BluetoothDevice device = mAdapter.getRemoteDevice(BluetoothTestRunner.sDeviceAddress); - mTestUtils.enable(mAdapter); - mTestUtils.connectProfile(mAdapter, device, BluetoothProfile.MAP_CLIENT, null); - mTestUtils.mceGetUnreadMessage(mAdapter, device); - - for (int i = 0; i < iterations; i++) { - mTestUtils.mceSetMessageStatus(mAdapter, device, BluetoothMapClient.READ); - mTestUtils.mceSetMessageStatus(mAdapter, device, BluetoothMapClient.UNREAD); - } - - /** - * It is hard to find device to support set undeleted status, so just - * set deleted in 1 iteration - **/ - mTestUtils.mceSetMessageStatus(mAdapter, device, BluetoothMapClient.DELETED); - } - - private void sleep(long time) { - try { - Thread.sleep(time); - } catch (InterruptedException e) { - } - } -} diff --git a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothTestRunner.java b/core/tests/bluetoothtests/src/android/bluetooth/BluetoothTestRunner.java deleted file mode 100644 index d19c2c3e7e24d50337207b88e8c9bd42a69defb5..0000000000000000000000000000000000000000 --- a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothTestRunner.java +++ /dev/null @@ -1,225 +0,0 @@ -/* - * Copyright (C) 2010 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.bluetooth; - -import junit.framework.TestSuite; - -import android.os.Bundle; -import android.test.InstrumentationTestRunner; -import android.test.InstrumentationTestSuite; -import android.util.Log; - -/** - * Instrumentation test runner for Bluetooth tests. - *

    - * To run: - *

    - * {@code
    - * adb shell am instrument \
    - *     [-e enable_iterations ] \
    - *     [-e discoverable_iterations ] \
    - *     [-e scan_iterations ] \
    - *     [-e enable_pan_iterations ] \
    - *     [-e pair_iterations ] \
    - *     [-e connect_a2dp_iterations ] \
    - *     [-e connect_headset_iterations ] \
    - *     [-e connect_input_iterations ] \
    - *     [-e connect_pan_iterations ] \
    - *     [-e start_stop_sco_iterations ] \
    - *     [-e mce_set_message_status_iterations ] \
    - *     [-e pair_address 
    ] \ - * [-e headset_address
    ] \ - * [-e a2dp_address
    ] \ - * [-e input_address
    ] \ - * [-e pan_address
    ] \ - * [-e pair_pin ] \ - * [-e pair_passkey ] \ - * -w com.android.bluetooth.tests/android.bluetooth.BluetoothTestRunner - * } - *
    - */ -public class BluetoothTestRunner extends InstrumentationTestRunner { - private static final String TAG = "BluetoothTestRunner"; - - public static int sEnableIterations = 100; - public static int sDiscoverableIterations = 1000; - public static int sScanIterations = 1000; - public static int sEnablePanIterations = 1000; - public static int sPairIterations = 100; - public static int sConnectHeadsetIterations = 100; - public static int sConnectA2dpIterations = 100; - public static int sConnectInputIterations = 100; - public static int sConnectPanIterations = 100; - public static int sStartStopScoIterations = 100; - public static int sMceSetMessageStatusIterations = 100; - - public static String sDeviceAddress = ""; - public static byte[] sDevicePairPin = {'1', '2', '3', '4'}; - public static int sDevicePairPasskey = 123456; - - @Override - public TestSuite getAllTests() { - TestSuite suite = new InstrumentationTestSuite(this); - suite.addTestSuite(BluetoothStressTest.class); - return suite; - } - - @Override - public ClassLoader getLoader() { - return BluetoothTestRunner.class.getClassLoader(); - } - - @Override - public void onCreate(Bundle arguments) { - String val = arguments.getString("enable_iterations"); - if (val != null) { - try { - sEnableIterations = Integer.parseInt(val); - } catch (NumberFormatException e) { - // Invalid argument, fall back to default value - } - } - - val = arguments.getString("discoverable_iterations"); - if (val != null) { - try { - sDiscoverableIterations = Integer.parseInt(val); - } catch (NumberFormatException e) { - // Invalid argument, fall back to default value - } - } - - val = arguments.getString("scan_iterations"); - if (val != null) { - try { - sScanIterations = Integer.parseInt(val); - } catch (NumberFormatException e) { - // Invalid argument, fall back to default value - } - } - - val = arguments.getString("enable_pan_iterations"); - if (val != null) { - try { - sEnablePanIterations = Integer.parseInt(val); - } catch (NumberFormatException e) { - // Invalid argument, fall back to default value - } - } - - val = arguments.getString("pair_iterations"); - if (val != null) { - try { - sPairIterations = Integer.parseInt(val); - } catch (NumberFormatException e) { - // Invalid argument, fall back to default value - } - } - - val = arguments.getString("connect_a2dp_iterations"); - if (val != null) { - try { - sConnectA2dpIterations = Integer.parseInt(val); - } catch (NumberFormatException e) { - // Invalid argument, fall back to default value - } - } - - val = arguments.getString("connect_headset_iterations"); - if (val != null) { - try { - sConnectHeadsetIterations = Integer.parseInt(val); - } catch (NumberFormatException e) { - // Invalid argument, fall back to default value - } - } - - val = arguments.getString("connect_input_iterations"); - if (val != null) { - try { - sConnectInputIterations = Integer.parseInt(val); - } catch (NumberFormatException e) { - // Invalid argument, fall back to default value - } - } - - val = arguments.getString("connect_pan_iterations"); - if (val != null) { - try { - sConnectPanIterations = Integer.parseInt(val); - } catch (NumberFormatException e) { - // Invalid argument, fall back to default value - } - } - - val = arguments.getString("start_stop_sco_iterations"); - if (val != null) { - try { - sStartStopScoIterations = Integer.parseInt(val); - } catch (NumberFormatException e) { - // Invalid argument, fall back to default value - } - } - - val = arguments.getString("mce_set_message_status_iterations"); - if (val != null) { - try { - sMceSetMessageStatusIterations = Integer.parseInt(val); - } catch (NumberFormatException e) { - // Invalid argument, fall back to default value - } - } - - val = arguments.getString("device_address"); - if (val != null) { - sDeviceAddress = val; - } - - val = arguments.getString("device_pair_pin"); - if (val != null) { - byte[] pin = BluetoothDevice.convertPinToBytes(val); - if (pin != null) { - sDevicePairPin = pin; - } - } - - val = arguments.getString("device_pair_passkey"); - if (val != null) { - try { - sDevicePairPasskey = Integer.parseInt(val); - } catch (NumberFormatException e) { - // Invalid argument, fall back to default value - } - } - - Log.i(TAG, String.format("enable_iterations=%d", sEnableIterations)); - Log.i(TAG, String.format("discoverable_iterations=%d", sDiscoverableIterations)); - Log.i(TAG, String.format("scan_iterations=%d", sScanIterations)); - Log.i(TAG, String.format("pair_iterations=%d", sPairIterations)); - Log.i(TAG, String.format("connect_a2dp_iterations=%d", sConnectA2dpIterations)); - Log.i(TAG, String.format("connect_headset_iterations=%d", sConnectHeadsetIterations)); - Log.i(TAG, String.format("connect_input_iterations=%d", sConnectInputIterations)); - Log.i(TAG, String.format("connect_pan_iterations=%d", sConnectPanIterations)); - Log.i(TAG, String.format("start_stop_sco_iterations=%d", sStartStopScoIterations)); - Log.i(TAG, String.format("device_address=%s", sDeviceAddress)); - Log.i(TAG, String.format("device_pair_pin=%s", new String(sDevicePairPin))); - Log.i(TAG, String.format("device_pair_passkey=%d", sDevicePairPasskey)); - - // Call onCreate last since we want to set the static variables first. - super.onCreate(arguments); - } -} diff --git a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothTestUtils.java b/core/tests/bluetoothtests/src/android/bluetooth/BluetoothTestUtils.java deleted file mode 100644 index 409025bc670d774e1f24d82f031f95be4f312f86..0000000000000000000000000000000000000000 --- a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothTestUtils.java +++ /dev/null @@ -1,1649 +0,0 @@ -/* - * Copyright (C) 2010 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.bluetooth; - -import android.bluetooth.BluetoothPan; -import android.bluetooth.BluetoothProfile; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.media.AudioManager; -import android.os.Environment; -import android.util.Log; - -import junit.framework.Assert; - -import java.io.BufferedWriter; -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import java.util.Set; -import java.util.concurrent.Semaphore; -import java.util.concurrent.TimeUnit; - -public class BluetoothTestUtils extends Assert { - - /** Timeout for enable/disable in ms. */ - private static final int ENABLE_DISABLE_TIMEOUT = 20000; - /** Timeout for discoverable/undiscoverable in ms. */ - private static final int DISCOVERABLE_UNDISCOVERABLE_TIMEOUT = 5000; - /** Timeout for starting/stopping a scan in ms. */ - private static final int START_STOP_SCAN_TIMEOUT = 5000; - /** Timeout for pair/unpair in ms. */ - private static final int PAIR_UNPAIR_TIMEOUT = 20000; - /** Timeout for connecting/disconnecting a profile in ms. */ - private static final int CONNECT_DISCONNECT_PROFILE_TIMEOUT = 20000; - /** Timeout to start or stop a SCO channel in ms. */ - private static final int START_STOP_SCO_TIMEOUT = 10000; - /** Timeout to connect a profile proxy in ms. */ - private static final int CONNECT_PROXY_TIMEOUT = 5000; - /** Time between polls in ms. */ - private static final int POLL_TIME = 100; - /** Timeout to get map message in ms. */ - private static final int GET_UNREAD_MESSAGE_TIMEOUT = 10000; - /** Timeout to set map message status in ms. */ - private static final int SET_MESSAGE_STATUS_TIMEOUT = 2000; - - private abstract class FlagReceiver extends BroadcastReceiver { - private int mExpectedFlags = 0; - private int mFiredFlags = 0; - private long mCompletedTime = -1; - - public FlagReceiver(int expectedFlags) { - mExpectedFlags = expectedFlags; - } - - public int getFiredFlags() { - synchronized (this) { - return mFiredFlags; - } - } - - public long getCompletedTime() { - synchronized (this) { - return mCompletedTime; - } - } - - protected void setFiredFlag(int flag) { - synchronized (this) { - mFiredFlags |= flag; - if ((mFiredFlags & mExpectedFlags) == mExpectedFlags) { - mCompletedTime = System.currentTimeMillis(); - } - } - } - } - - private class BluetoothReceiver extends FlagReceiver { - private static final int DISCOVERY_STARTED_FLAG = 1; - private static final int DISCOVERY_FINISHED_FLAG = 1 << 1; - private static final int SCAN_MODE_NONE_FLAG = 1 << 2; - private static final int SCAN_MODE_CONNECTABLE_FLAG = 1 << 3; - private static final int SCAN_MODE_CONNECTABLE_DISCOVERABLE_FLAG = 1 << 4; - private static final int STATE_OFF_FLAG = 1 << 5; - private static final int STATE_TURNING_ON_FLAG = 1 << 6; - private static final int STATE_ON_FLAG = 1 << 7; - private static final int STATE_TURNING_OFF_FLAG = 1 << 8; - private static final int STATE_GET_MESSAGE_FINISHED_FLAG = 1 << 9; - private static final int STATE_SET_MESSAGE_STATUS_FINISHED_FLAG = 1 << 10; - - public BluetoothReceiver(int expectedFlags) { - super(expectedFlags); - } - - @Override - public void onReceive(Context context, Intent intent) { - if (BluetoothAdapter.ACTION_DISCOVERY_STARTED.equals(intent.getAction())) { - setFiredFlag(DISCOVERY_STARTED_FLAG); - } else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(intent.getAction())) { - setFiredFlag(DISCOVERY_FINISHED_FLAG); - } else if (BluetoothAdapter.ACTION_SCAN_MODE_CHANGED.equals(intent.getAction())) { - int mode = intent.getIntExtra(BluetoothAdapter.EXTRA_SCAN_MODE, -1); - assertNotSame(-1, mode); - switch (mode) { - case BluetoothAdapter.SCAN_MODE_NONE: - setFiredFlag(SCAN_MODE_NONE_FLAG); - break; - case BluetoothAdapter.SCAN_MODE_CONNECTABLE: - setFiredFlag(SCAN_MODE_CONNECTABLE_FLAG); - break; - case BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE: - setFiredFlag(SCAN_MODE_CONNECTABLE_DISCOVERABLE_FLAG); - break; - } - } else if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(intent.getAction())) { - int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1); - assertNotSame(-1, state); - switch (state) { - case BluetoothAdapter.STATE_OFF: - setFiredFlag(STATE_OFF_FLAG); - break; - case BluetoothAdapter.STATE_TURNING_ON: - setFiredFlag(STATE_TURNING_ON_FLAG); - break; - case BluetoothAdapter.STATE_ON: - setFiredFlag(STATE_ON_FLAG); - break; - case BluetoothAdapter.STATE_TURNING_OFF: - setFiredFlag(STATE_TURNING_OFF_FLAG); - break; - } - } - } - } - - private class PairReceiver extends FlagReceiver { - private static final int STATE_BONDED_FLAG = 1; - private static final int STATE_BONDING_FLAG = 1 << 1; - private static final int STATE_NONE_FLAG = 1 << 2; - - private BluetoothDevice mDevice; - private int mPasskey; - private byte[] mPin; - - public PairReceiver(BluetoothDevice device, int passkey, byte[] pin, int expectedFlags) { - super(expectedFlags); - - mDevice = device; - mPasskey = passkey; - mPin = pin; - } - - @Override - public void onReceive(Context context, Intent intent) { - if (!mDevice.equals(intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE))) { - return; - } - - if (BluetoothDevice.ACTION_PAIRING_REQUEST.equals(intent.getAction())) { - int varient = intent.getIntExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT, -1); - assertNotSame(-1, varient); - switch (varient) { - case BluetoothDevice.PAIRING_VARIANT_PIN: - case BluetoothDevice.PAIRING_VARIANT_PIN_16_DIGITS: - mDevice.setPin(mPin); - break; - case BluetoothDevice.PAIRING_VARIANT_PASSKEY: - break; - case BluetoothDevice.PAIRING_VARIANT_PASSKEY_CONFIRMATION: - case BluetoothDevice.PAIRING_VARIANT_CONSENT: - mDevice.setPairingConfirmation(true); - break; - case BluetoothDevice.PAIRING_VARIANT_OOB_CONSENT: - break; - } - } else if (BluetoothDevice.ACTION_BOND_STATE_CHANGED.equals(intent.getAction())) { - int state = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, -1); - assertNotSame(-1, state); - switch (state) { - case BluetoothDevice.BOND_NONE: - setFiredFlag(STATE_NONE_FLAG); - break; - case BluetoothDevice.BOND_BONDING: - setFiredFlag(STATE_BONDING_FLAG); - break; - case BluetoothDevice.BOND_BONDED: - setFiredFlag(STATE_BONDED_FLAG); - break; - } - } - } - } - - private class ConnectProfileReceiver extends FlagReceiver { - private static final int STATE_DISCONNECTED_FLAG = 1; - private static final int STATE_CONNECTING_FLAG = 1 << 1; - private static final int STATE_CONNECTED_FLAG = 1 << 2; - private static final int STATE_DISCONNECTING_FLAG = 1 << 3; - - private BluetoothDevice mDevice; - private int mProfile; - private String mConnectionAction; - - public ConnectProfileReceiver(BluetoothDevice device, int profile, int expectedFlags) { - super(expectedFlags); - - mDevice = device; - mProfile = profile; - - switch (mProfile) { - case BluetoothProfile.A2DP: - mConnectionAction = BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED; - break; - case BluetoothProfile.HEADSET: - mConnectionAction = BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED; - break; - case BluetoothProfile.HID_HOST: - mConnectionAction = BluetoothHidHost.ACTION_CONNECTION_STATE_CHANGED; - break; - case BluetoothProfile.PAN: - mConnectionAction = BluetoothPan.ACTION_CONNECTION_STATE_CHANGED; - break; - case BluetoothProfile.MAP_CLIENT: - mConnectionAction = BluetoothMapClient.ACTION_CONNECTION_STATE_CHANGED; - break; - default: - mConnectionAction = null; - } - } - - @Override - public void onReceive(Context context, Intent intent) { - if (mConnectionAction != null && mConnectionAction.equals(intent.getAction())) { - if (!mDevice.equals(intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE))) { - return; - } - - int state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1); - assertNotSame(-1, state); - switch (state) { - case BluetoothProfile.STATE_DISCONNECTED: - setFiredFlag(STATE_DISCONNECTED_FLAG); - break; - case BluetoothProfile.STATE_CONNECTING: - setFiredFlag(STATE_CONNECTING_FLAG); - break; - case BluetoothProfile.STATE_CONNECTED: - setFiredFlag(STATE_CONNECTED_FLAG); - break; - case BluetoothProfile.STATE_DISCONNECTING: - setFiredFlag(STATE_DISCONNECTING_FLAG); - break; - } - } - } - } - - private class ConnectPanReceiver extends ConnectProfileReceiver { - private int mRole; - - public ConnectPanReceiver(BluetoothDevice device, int role, int expectedFlags) { - super(device, BluetoothProfile.PAN, expectedFlags); - - mRole = role; - } - - @Override - public void onReceive(Context context, Intent intent) { - if (mRole != intent.getIntExtra(BluetoothPan.EXTRA_LOCAL_ROLE, -1)) { - return; - } - - super.onReceive(context, intent); - } - } - - private class StartStopScoReceiver extends FlagReceiver { - private static final int STATE_CONNECTED_FLAG = 1; - private static final int STATE_DISCONNECTED_FLAG = 1 << 1; - - public StartStopScoReceiver(int expectedFlags) { - super(expectedFlags); - } - - @Override - public void onReceive(Context context, Intent intent) { - if (AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED.equals(intent.getAction())) { - int state = intent.getIntExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, - AudioManager.SCO_AUDIO_STATE_ERROR); - assertNotSame(AudioManager.SCO_AUDIO_STATE_ERROR, state); - switch(state) { - case AudioManager.SCO_AUDIO_STATE_CONNECTED: - setFiredFlag(STATE_CONNECTED_FLAG); - break; - case AudioManager.SCO_AUDIO_STATE_DISCONNECTED: - setFiredFlag(STATE_DISCONNECTED_FLAG); - break; - } - } - } - } - - - private class MceSetMessageStatusReceiver extends FlagReceiver { - private static final int MESSAGE_RECEIVED_FLAG = 1; - private static final int STATUS_CHANGED_FLAG = 1 << 1; - - public MceSetMessageStatusReceiver(int expectedFlags) { - super(expectedFlags); - } - - @Override - public void onReceive(Context context, Intent intent) { - if (BluetoothMapClient.ACTION_MESSAGE_RECEIVED.equals(intent.getAction())) { - String handle = intent.getStringExtra(BluetoothMapClient.EXTRA_MESSAGE_HANDLE); - assertNotNull(handle); - setFiredFlag(MESSAGE_RECEIVED_FLAG); - mMsgHandle = handle; - } else if (BluetoothMapClient.ACTION_MESSAGE_DELETED_STATUS_CHANGED.equals(intent.getAction())) { - int result = intent.getIntExtra(BluetoothMapClient.EXTRA_RESULT_CODE, BluetoothMapClient.RESULT_FAILURE); - assertEquals(result, BluetoothMapClient.RESULT_SUCCESS); - setFiredFlag(STATUS_CHANGED_FLAG); - } else if (BluetoothMapClient.ACTION_MESSAGE_READ_STATUS_CHANGED.equals(intent.getAction())) { - int result = intent.getIntExtra(BluetoothMapClient.EXTRA_RESULT_CODE, BluetoothMapClient.RESULT_FAILURE); - assertEquals(result, BluetoothMapClient.RESULT_SUCCESS); - setFiredFlag(STATUS_CHANGED_FLAG); - } - } - } - - private BluetoothProfile.ServiceListener mServiceListener = - new BluetoothProfile.ServiceListener() { - @Override - public void onServiceConnected(int profile, BluetoothProfile proxy) { - synchronized (this) { - switch (profile) { - case BluetoothProfile.A2DP: - mA2dp = (BluetoothA2dp) proxy; - break; - case BluetoothProfile.HEADSET: - mHeadset = (BluetoothHeadset) proxy; - break; - case BluetoothProfile.HID_HOST: - mInput = (BluetoothHidHost) proxy; - break; - case BluetoothProfile.PAN: - mPan = (BluetoothPan) proxy; - break; - case BluetoothProfile.MAP_CLIENT: - mMce = (BluetoothMapClient) proxy; - break; - } - } - } - - @Override - public void onServiceDisconnected(int profile) { - synchronized (this) { - switch (profile) { - case BluetoothProfile.A2DP: - mA2dp = null; - break; - case BluetoothProfile.HEADSET: - mHeadset = null; - break; - case BluetoothProfile.HID_HOST: - mInput = null; - break; - case BluetoothProfile.PAN: - mPan = null; - break; - case BluetoothProfile.MAP_CLIENT: - mMce = null; - break; - } - } - } - }; - - private List mReceivers = new ArrayList(); - - private BufferedWriter mOutputWriter; - private String mTag; - private String mOutputFile; - - private Context mContext; - private BluetoothA2dp mA2dp = null; - private BluetoothHeadset mHeadset = null; - private BluetoothHidHost mInput = null; - private BluetoothPan mPan = null; - private BluetoothMapClient mMce = null; - private String mMsgHandle = null; - - /** - * Creates a utility instance for testing Bluetooth. - * - * @param context The context of the application using the utility. - * @param tag The log tag of the application using the utility. - */ - public BluetoothTestUtils(Context context, String tag) { - this(context, tag, null); - } - - /** - * Creates a utility instance for testing Bluetooth. - * - * @param context The context of the application using the utility. - * @param tag The log tag of the application using the utility. - * @param outputFile The path to an output file if the utility is to write results to a - * separate file. - */ - public BluetoothTestUtils(Context context, String tag, String outputFile) { - mContext = context; - mTag = tag; - mOutputFile = outputFile; - - if (mOutputFile == null) { - mOutputWriter = null; - } else { - try { - mOutputWriter = new BufferedWriter(new FileWriter(new File( - Environment.getExternalStorageDirectory(), mOutputFile), true)); - } catch (IOException e) { - Log.w(mTag, "Test output file could not be opened", e); - mOutputWriter = null; - } - } - } - - /** - * Closes the utility instance and unregisters any BroadcastReceivers. - */ - public void close() { - while (!mReceivers.isEmpty()) { - mContext.unregisterReceiver(mReceivers.remove(0)); - } - - if (mOutputWriter != null) { - try { - mOutputWriter.close(); - } catch (IOException e) { - Log.w(mTag, "Test output file could not be closed", e); - } - } - } - - /** - * Enables Bluetooth and checks to make sure that Bluetooth was turned on and that the correct - * actions were broadcast. - * - * @param adapter The BT adapter. - */ - public void enable(BluetoothAdapter adapter) { - writeOutput("Enabling Bluetooth adapter."); - assertFalse(adapter.isEnabled()); - int btState = adapter.getState(); - final Semaphore completionSemaphore = new Semaphore(0); - final BroadcastReceiver receiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - final String action = intent.getAction(); - if (!BluetoothAdapter.ACTION_STATE_CHANGED.equals(action)) { - return; - } - final int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, - BluetoothAdapter.ERROR); - if (state == BluetoothAdapter.STATE_ON) { - completionSemaphore.release(); - } - } - }; - - final IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED); - mContext.registerReceiver(receiver, filter); - // Note: for Wear Local Edition builds, which have Permission Review Mode enabled to - // obey China CMIIT, BluetoothAdapter may not startup immediately on methods enable/disable. - // So no assertion applied here. - adapter.enable(); - boolean success = false; - try { - success = completionSemaphore.tryAcquire(ENABLE_DISABLE_TIMEOUT, TimeUnit.MILLISECONDS); - writeOutput(String.format("enable() completed in 0 ms")); - } catch (final InterruptedException e) { - // This should never happen but just in case it does, the test will fail anyway. - } - mContext.unregisterReceiver(receiver); - if (!success) { - fail(String.format("enable() timeout: state=%d (expected %d)", btState, - BluetoothAdapter.STATE_ON)); - } - } - - /** - * Disables Bluetooth and checks to make sure that Bluetooth was turned off and that the correct - * actions were broadcast. - * - * @param adapter The BT adapter. - */ - public void disable(BluetoothAdapter adapter) { - writeOutput("Disabling Bluetooth adapter."); - assertTrue(adapter.isEnabled()); - int btState = adapter.getState(); - final Semaphore completionSemaphore = new Semaphore(0); - final BroadcastReceiver receiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - final String action = intent.getAction(); - if (!BluetoothAdapter.ACTION_STATE_CHANGED.equals(action)) { - return; - } - final int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, - BluetoothAdapter.ERROR); - if (state == BluetoothAdapter.STATE_OFF) { - completionSemaphore.release(); - } - } - }; - - final IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED); - mContext.registerReceiver(receiver, filter); - // Note: for Wear Local Edition builds, which have Permission Review Mode enabled to - // obey China CMIIT, BluetoothAdapter may not startup immediately on methods enable/disable. - // So no assertion applied here. - adapter.disable(); - boolean success = false; - try { - success = completionSemaphore.tryAcquire(ENABLE_DISABLE_TIMEOUT, TimeUnit.MILLISECONDS); - writeOutput(String.format("disable() completed in 0 ms")); - } catch (final InterruptedException e) { - // This should never happen but just in case it does, the test will fail anyway. - } - mContext.unregisterReceiver(receiver); - if (!success) { - fail(String.format("disable() timeout: state=%d (expected %d)", btState, - BluetoothAdapter.STATE_OFF)); - } - } - - /** - * Puts the local device into discoverable mode and checks to make sure that the local device - * is in discoverable mode and that the correct actions were broadcast. - * - * @param adapter The BT adapter. - */ - public void discoverable(BluetoothAdapter adapter) { - if (!adapter.isEnabled()) { - fail("discoverable() bluetooth not enabled"); - } - - int scanMode = adapter.getScanMode(); - if (scanMode != BluetoothAdapter.SCAN_MODE_CONNECTABLE) { - return; - } - - final Semaphore completionSemaphore = new Semaphore(0); - final BroadcastReceiver receiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - final String action = intent.getAction(); - if (!BluetoothAdapter.ACTION_SCAN_MODE_CHANGED.equals(action)) { - return; - } - final int mode = intent.getIntExtra(BluetoothAdapter.EXTRA_SCAN_MODE, - BluetoothAdapter.SCAN_MODE_NONE); - if (mode == BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) { - completionSemaphore.release(); - } - } - }; - - final IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED); - mContext.registerReceiver(receiver, filter); - assertTrue(adapter.setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE)); - boolean success = false; - try { - success = completionSemaphore.tryAcquire(DISCOVERABLE_UNDISCOVERABLE_TIMEOUT, - TimeUnit.MILLISECONDS); - writeOutput(String.format("discoverable() completed in 0 ms")); - } catch (final InterruptedException e) { - // This should never happen but just in case it does, the test will fail anyway. - } - mContext.unregisterReceiver(receiver); - if (!success) { - fail(String.format("discoverable() timeout: scanMode=%d (expected %d)", scanMode, - BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE)); - } - } - - /** - * Puts the local device into connectable only mode and checks to make sure that the local - * device is in in connectable mode and that the correct actions were broadcast. - * - * @param adapter The BT adapter. - */ - public void undiscoverable(BluetoothAdapter adapter) { - if (!adapter.isEnabled()) { - fail("undiscoverable() bluetooth not enabled"); - } - - int scanMode = adapter.getScanMode(); - if (scanMode != BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) { - return; - } - - final Semaphore completionSemaphore = new Semaphore(0); - final BroadcastReceiver receiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - final String action = intent.getAction(); - if (!BluetoothAdapter.ACTION_SCAN_MODE_CHANGED.equals(action)) { - return; - } - final int mode = intent.getIntExtra(BluetoothAdapter.EXTRA_SCAN_MODE, - BluetoothAdapter.SCAN_MODE_NONE); - if (mode == BluetoothAdapter.SCAN_MODE_CONNECTABLE) { - completionSemaphore.release(); - } - } - }; - - final IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED); - mContext.registerReceiver(receiver, filter); - assertTrue(adapter.setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE)); - boolean success = false; - try { - success = completionSemaphore.tryAcquire(DISCOVERABLE_UNDISCOVERABLE_TIMEOUT, - TimeUnit.MILLISECONDS); - writeOutput(String.format("undiscoverable() completed in 0 ms")); - } catch (InterruptedException e) { - // This should never happen but just in case it does, the test will fail anyway. - } - mContext.unregisterReceiver(receiver); - if (!success) { - fail(String.format("undiscoverable() timeout: scanMode=%d (expected %d)", scanMode, - BluetoothAdapter.SCAN_MODE_CONNECTABLE)); - } - } - - /** - * Starts a scan for remote devices and checks to make sure that the local device is scanning - * and that the correct actions were broadcast. - * - * @param adapter The BT adapter. - */ - public void startScan(BluetoothAdapter adapter) { - int mask = BluetoothReceiver.DISCOVERY_STARTED_FLAG; - - if (!adapter.isEnabled()) { - fail("startScan() bluetooth not enabled"); - } - - if (adapter.isDiscovering()) { - return; - } - - BluetoothReceiver receiver = getBluetoothReceiver(mask); - - long start = System.currentTimeMillis(); - assertTrue(adapter.startDiscovery()); - - while (System.currentTimeMillis() - start < START_STOP_SCAN_TIMEOUT) { - if (adapter.isDiscovering() && ((receiver.getFiredFlags() & mask) == mask)) { - writeOutput(String.format("startScan() completed in %d ms", - (receiver.getCompletedTime() - start))); - removeReceiver(receiver); - return; - } - sleep(POLL_TIME); - } - - int firedFlags = receiver.getFiredFlags(); - removeReceiver(receiver); - fail(String.format("startScan() timeout: isDiscovering=%b, flags=0x%x (expected 0x%x)", - adapter.isDiscovering(), firedFlags, mask)); - } - - /** - * Stops a scan for remote devices and checks to make sure that the local device is not scanning - * and that the correct actions were broadcast. - * - * @param adapter The BT adapter. - */ - public void stopScan(BluetoothAdapter adapter) { - int mask = BluetoothReceiver.DISCOVERY_FINISHED_FLAG; - - if (!adapter.isEnabled()) { - fail("stopScan() bluetooth not enabled"); - } - - if (!adapter.isDiscovering()) { - return; - } - - BluetoothReceiver receiver = getBluetoothReceiver(mask); - - long start = System.currentTimeMillis(); - assertTrue(adapter.cancelDiscovery()); - - while (System.currentTimeMillis() - start < START_STOP_SCAN_TIMEOUT) { - if (!adapter.isDiscovering() && ((receiver.getFiredFlags() & mask) == mask)) { - writeOutput(String.format("stopScan() completed in %d ms", - (receiver.getCompletedTime() - start))); - removeReceiver(receiver); - return; - } - sleep(POLL_TIME); - } - - int firedFlags = receiver.getFiredFlags(); - removeReceiver(receiver); - fail(String.format("stopScan() timeout: isDiscovering=%b, flags=0x%x (expected 0x%x)", - adapter.isDiscovering(), firedFlags, mask)); - - } - - /** - * Enables PAN tethering on the local device and checks to make sure that tethering is enabled. - * - * @param adapter The BT adapter. - */ - public void enablePan(BluetoothAdapter adapter) { - if (mPan == null) mPan = (BluetoothPan) connectProxy(adapter, BluetoothProfile.PAN); - assertNotNull(mPan); - - long start = System.currentTimeMillis(); - mPan.setBluetoothTethering(true); - long stop = System.currentTimeMillis(); - assertTrue(mPan.isTetheringOn()); - - writeOutput(String.format("enablePan() completed in %d ms", (stop - start))); - } - - /** - * Disables PAN tethering on the local device and checks to make sure that tethering is - * disabled. - * - * @param adapter The BT adapter. - */ - public void disablePan(BluetoothAdapter adapter) { - if (mPan == null) mPan = (BluetoothPan) connectProxy(adapter, BluetoothProfile.PAN); - assertNotNull(mPan); - - long start = System.currentTimeMillis(); - mPan.setBluetoothTethering(false); - long stop = System.currentTimeMillis(); - assertFalse(mPan.isTetheringOn()); - - writeOutput(String.format("disablePan() completed in %d ms", (stop - start))); - } - - /** - * Initiates a pairing with a remote device and checks to make sure that the devices are paired - * and that the correct actions were broadcast. - * - * @param adapter The BT adapter. - * @param device The remote device. - * @param passkey The pairing passkey if pairing requires a passkey. Any value if not. - * @param pin The pairing pin if pairing requires a pin. Any value if not. - */ - public void pair(BluetoothAdapter adapter, BluetoothDevice device, int passkey, byte[] pin) { - pairOrAcceptPair(adapter, device, passkey, pin, true); - } - - /** - * Accepts a pairing with a remote device and checks to make sure that the devices are paired - * and that the correct actions were broadcast. - * - * @param adapter The BT adapter. - * @param device The remote device. - * @param passkey The pairing passkey if pairing requires a passkey. Any value if not. - * @param pin The pairing pin if pairing requires a pin. Any value if not. - */ - public void acceptPair(BluetoothAdapter adapter, BluetoothDevice device, int passkey, - byte[] pin) { - pairOrAcceptPair(adapter, device, passkey, pin, false); - } - - /** - * Helper method used by {@link #pair(BluetoothAdapter, BluetoothDevice, int, byte[])} and - * {@link #acceptPair(BluetoothAdapter, BluetoothDevice, int, byte[])} to either pair or accept - * a pairing request. - * - * @param adapter The BT adapter. - * @param device The remote device. - * @param passkey The pairing passkey if pairing requires a passkey. Any value if not. - * @param pin The pairing pin if pairing requires a pin. Any value if not. - * @param shouldPair Whether to pair or accept the pair. - */ - private void pairOrAcceptPair(BluetoothAdapter adapter, BluetoothDevice device, int passkey, - byte[] pin, boolean shouldPair) { - int mask = PairReceiver.STATE_BONDING_FLAG | PairReceiver.STATE_BONDED_FLAG; - long start = -1; - String methodName; - if (shouldPair) { - methodName = String.format("pair(device=%s)", device); - } else { - methodName = String.format("acceptPair(device=%s)", device); - } - - if (!adapter.isEnabled()) { - fail(String.format("%s bluetooth not enabled", methodName)); - } - - PairReceiver receiver = getPairReceiver(device, passkey, pin, mask); - - int state = device.getBondState(); - switch (state) { - case BluetoothDevice.BOND_NONE: - assertFalse(adapter.getBondedDevices().contains(device)); - start = System.currentTimeMillis(); - if (shouldPair) { - assertTrue(device.createBond()); - } - break; - case BluetoothDevice.BOND_BONDING: - mask = 0; // Don't check for received intents since we might have missed them. - break; - case BluetoothDevice.BOND_BONDED: - assertTrue(adapter.getBondedDevices().contains(device)); - return; - default: - removeReceiver(receiver); - fail(String.format("%s invalid state: state=%d", methodName, state)); - } - - long s = System.currentTimeMillis(); - while (System.currentTimeMillis() - s < PAIR_UNPAIR_TIMEOUT) { - state = device.getBondState(); - if (state == BluetoothDevice.BOND_BONDED && (receiver.getFiredFlags() & mask) == mask) { - assertTrue(adapter.getBondedDevices().contains(device)); - long finish = receiver.getCompletedTime(); - if (start != -1 && finish != -1) { - writeOutput(String.format("%s completed in %d ms", methodName, - (finish - start))); - } else { - writeOutput(String.format("%s completed", methodName)); - } - removeReceiver(receiver); - return; - } - sleep(POLL_TIME); - } - - int firedFlags = receiver.getFiredFlags(); - removeReceiver(receiver); - fail(String.format("%s timeout: state=%d (expected %d), flags=0x%x (expected 0x%x)", - methodName, state, BluetoothDevice.BOND_BONDED, firedFlags, mask)); - } - - /** - * Deletes a pairing with a remote device and checks to make sure that the devices are unpaired - * and that the correct actions were broadcast. - * - * @param adapter The BT adapter. - * @param device The remote device. - */ - public void unpair(BluetoothAdapter adapter, BluetoothDevice device) { - int mask = PairReceiver.STATE_NONE_FLAG; - long start = -1; - String methodName = String.format("unpair(device=%s)", device); - - if (!adapter.isEnabled()) { - fail(String.format("%s bluetooth not enabled", methodName)); - } - - PairReceiver receiver = getPairReceiver(device, 0, null, mask); - - int state = device.getBondState(); - switch (state) { - case BluetoothDevice.BOND_NONE: - assertFalse(adapter.getBondedDevices().contains(device)); - removeReceiver(receiver); - return; - case BluetoothDevice.BOND_BONDING: - start = System.currentTimeMillis(); - assertTrue(device.removeBond()); - break; - case BluetoothDevice.BOND_BONDED: - assertTrue(adapter.getBondedDevices().contains(device)); - start = System.currentTimeMillis(); - assertTrue(device.removeBond()); - break; - default: - removeReceiver(receiver); - fail(String.format("%s invalid state: state=%d", methodName, state)); - } - - long s = System.currentTimeMillis(); - while (System.currentTimeMillis() - s < PAIR_UNPAIR_TIMEOUT) { - if (device.getBondState() == BluetoothDevice.BOND_NONE - && (receiver.getFiredFlags() & mask) == mask) { - assertFalse(adapter.getBondedDevices().contains(device)); - long finish = receiver.getCompletedTime(); - if (start != -1 && finish != -1) { - writeOutput(String.format("%s completed in %d ms", methodName, - (finish - start))); - } else { - writeOutput(String.format("%s completed", methodName)); - } - removeReceiver(receiver); - return; - } - } - - int firedFlags = receiver.getFiredFlags(); - removeReceiver(receiver); - fail(String.format("%s timeout: state=%d (expected %d), flags=0x%x (expected 0x%x)", - methodName, state, BluetoothDevice.BOND_BONDED, firedFlags, mask)); - } - - /** - * Deletes all pairings of remote devices - * @param adapter the BT adapter - */ - public void unpairAll(BluetoothAdapter adapter) { - Set devices = adapter.getBondedDevices(); - for (BluetoothDevice device : devices) { - unpair(adapter, device); - } - } - - /** - * Connects a profile from the local device to a remote device and checks to make sure that the - * profile is connected and that the correct actions were broadcast. - * - * @param adapter The BT adapter. - * @param device The remote device. - * @param profile The profile to connect. One of {@link BluetoothProfile#A2DP}, - * {@link BluetoothProfile#HEADSET}, {@link BluetoothProfile#HID_HOST} or {@link BluetoothProfile#MAP_CLIENT}.. - * @param methodName The method name to printed in the logs. If null, will be - * "connectProfile(profile=<profile>, device=<device>)" - */ - public void connectProfile(BluetoothAdapter adapter, BluetoothDevice device, int profile, - String methodName) { - if (methodName == null) { - methodName = String.format("connectProfile(profile=%d, device=%s)", profile, device); - } - int mask = (ConnectProfileReceiver.STATE_CONNECTING_FLAG - | ConnectProfileReceiver.STATE_CONNECTED_FLAG); - long start = -1; - - if (!adapter.isEnabled()) { - fail(String.format("%s bluetooth not enabled", methodName)); - } - - if (!adapter.getBondedDevices().contains(device)) { - fail(String.format("%s device not paired", methodName)); - } - - BluetoothProfile proxy = connectProxy(adapter, profile); - assertNotNull(proxy); - - ConnectProfileReceiver receiver = getConnectProfileReceiver(device, profile, mask); - - int state = proxy.getConnectionState(device); - switch (state) { - case BluetoothProfile.STATE_CONNECTED: - removeReceiver(receiver); - return; - case BluetoothProfile.STATE_CONNECTING: - mask = 0; // Don't check for received intents since we might have missed them. - break; - case BluetoothProfile.STATE_DISCONNECTED: - case BluetoothProfile.STATE_DISCONNECTING: - start = System.currentTimeMillis(); - if (profile == BluetoothProfile.A2DP) { - assertTrue(((BluetoothA2dp)proxy).connect(device)); - } else if (profile == BluetoothProfile.HEADSET) { - assertTrue(((BluetoothHeadset)proxy).connect(device)); - } else if (profile == BluetoothProfile.HID_HOST) { - assertTrue(((BluetoothHidHost)proxy).connect(device)); - } else if (profile == BluetoothProfile.MAP_CLIENT) { - assertTrue(((BluetoothMapClient)proxy).connect(device)); - } - break; - default: - removeReceiver(receiver); - fail(String.format("%s invalid state: state=%d", methodName, state)); - } - - long s = System.currentTimeMillis(); - while (System.currentTimeMillis() - s < CONNECT_DISCONNECT_PROFILE_TIMEOUT) { - state = proxy.getConnectionState(device); - if (state == BluetoothProfile.STATE_CONNECTED - && (receiver.getFiredFlags() & mask) == mask) { - long finish = receiver.getCompletedTime(); - if (start != -1 && finish != -1) { - writeOutput(String.format("%s completed in %d ms", methodName, - (finish - start))); - } else { - writeOutput(String.format("%s completed", methodName)); - } - removeReceiver(receiver); - return; - } - sleep(POLL_TIME); - } - - int firedFlags = receiver.getFiredFlags(); - removeReceiver(receiver); - fail(String.format("%s timeout: state=%d (expected %d), flags=0x%x (expected 0x%x)", - methodName, state, BluetoothProfile.STATE_CONNECTED, firedFlags, mask)); - } - - /** - * Disconnects a profile between the local device and a remote device and checks to make sure - * that the profile is disconnected and that the correct actions were broadcast. - * - * @param adapter The BT adapter. - * @param device The remote device. - * @param profile The profile to disconnect. One of {@link BluetoothProfile#A2DP}, - * {@link BluetoothProfile#HEADSET}, or {@link BluetoothProfile#HID_HOST}. - * @param methodName The method name to printed in the logs. If null, will be - * "connectProfile(profile=<profile>, device=<device>)" - */ - public void disconnectProfile(BluetoothAdapter adapter, BluetoothDevice device, int profile, - String methodName) { - if (methodName == null) { - methodName = String.format("disconnectProfile(profile=%d, device=%s)", profile, device); - } - int mask = (ConnectProfileReceiver.STATE_DISCONNECTING_FLAG - | ConnectProfileReceiver.STATE_DISCONNECTED_FLAG); - long start = -1; - - if (!adapter.isEnabled()) { - fail(String.format("%s bluetooth not enabled", methodName)); - } - - if (!adapter.getBondedDevices().contains(device)) { - fail(String.format("%s device not paired", methodName)); - } - - BluetoothProfile proxy = connectProxy(adapter, profile); - assertNotNull(proxy); - - ConnectProfileReceiver receiver = getConnectProfileReceiver(device, profile, mask); - - int state = proxy.getConnectionState(device); - switch (state) { - case BluetoothProfile.STATE_CONNECTED: - case BluetoothProfile.STATE_CONNECTING: - start = System.currentTimeMillis(); - if (profile == BluetoothProfile.A2DP) { - assertTrue(((BluetoothA2dp)proxy).disconnect(device)); - } else if (profile == BluetoothProfile.HEADSET) { - assertTrue(((BluetoothHeadset)proxy).disconnect(device)); - } else if (profile == BluetoothProfile.HID_HOST) { - assertTrue(((BluetoothHidHost)proxy).disconnect(device)); - } else if (profile == BluetoothProfile.MAP_CLIENT) { - assertTrue(((BluetoothMapClient)proxy).disconnect(device)); - } - break; - case BluetoothProfile.STATE_DISCONNECTED: - removeReceiver(receiver); - return; - case BluetoothProfile.STATE_DISCONNECTING: - mask = 0; // Don't check for received intents since we might have missed them. - break; - default: - removeReceiver(receiver); - fail(String.format("%s invalid state: state=%d", methodName, state)); - } - - long s = System.currentTimeMillis(); - while (System.currentTimeMillis() - s < CONNECT_DISCONNECT_PROFILE_TIMEOUT) { - state = proxy.getConnectionState(device); - if (state == BluetoothProfile.STATE_DISCONNECTED - && (receiver.getFiredFlags() & mask) == mask) { - long finish = receiver.getCompletedTime(); - if (start != -1 && finish != -1) { - writeOutput(String.format("%s completed in %d ms", methodName, - (finish - start))); - } else { - writeOutput(String.format("%s completed", methodName)); - } - removeReceiver(receiver); - return; - } - sleep(POLL_TIME); - } - - int firedFlags = receiver.getFiredFlags(); - removeReceiver(receiver); - fail(String.format("%s timeout: state=%d (expected %d), flags=0x%x (expected 0x%x)", - methodName, state, BluetoothProfile.STATE_DISCONNECTED, firedFlags, mask)); - } - - /** - * Connects the PANU to a remote NAP and checks to make sure that the PANU is connected and that - * the correct actions were broadcast. - * - * @param adapter The BT adapter. - * @param device The remote device. - */ - public void connectPan(BluetoothAdapter adapter, BluetoothDevice device) { - connectPanOrIncomingPanConnection(adapter, device, true); - } - - /** - * Checks that a remote PANU connects to the local NAP correctly and that the correct actions - * were broadcast. - * - * @param adapter The BT adapter. - * @param device The remote device. - */ - public void incomingPanConnection(BluetoothAdapter adapter, BluetoothDevice device) { - connectPanOrIncomingPanConnection(adapter, device, false); - } - - /** - * Helper method used by {@link #connectPan(BluetoothAdapter, BluetoothDevice)} and - * {@link #incomingPanConnection(BluetoothAdapter, BluetoothDevice)} to either connect to a - * remote NAP or verify that a remote device connected to the local NAP. - * - * @param adapter The BT adapter. - * @param device The remote device. - * @param connect If the method should initiate the connection (is PANU) - */ - private void connectPanOrIncomingPanConnection(BluetoothAdapter adapter, BluetoothDevice device, - boolean connect) { - long start = -1; - int mask, role; - String methodName; - - if (connect) { - methodName = String.format("connectPan(device=%s)", device); - mask = (ConnectProfileReceiver.STATE_CONNECTED_FLAG | - ConnectProfileReceiver.STATE_CONNECTING_FLAG); - role = BluetoothPan.LOCAL_PANU_ROLE; - } else { - methodName = String.format("incomingPanConnection(device=%s)", device); - mask = ConnectProfileReceiver.STATE_CONNECTED_FLAG; - role = BluetoothPan.LOCAL_NAP_ROLE; - } - - if (!adapter.isEnabled()) { - fail(String.format("%s bluetooth not enabled", methodName)); - } - - if (!adapter.getBondedDevices().contains(device)) { - fail(String.format("%s device not paired", methodName)); - } - - mPan = (BluetoothPan) connectProxy(adapter, BluetoothProfile.PAN); - assertNotNull(mPan); - ConnectPanReceiver receiver = getConnectPanReceiver(device, role, mask); - - int state = mPan.getConnectionState(device); - switch (state) { - case BluetoothPan.STATE_CONNECTED: - removeReceiver(receiver); - return; - case BluetoothPan.STATE_CONNECTING: - mask = 0; // Don't check for received intents since we might have missed them. - break; - case BluetoothPan.STATE_DISCONNECTED: - case BluetoothPan.STATE_DISCONNECTING: - start = System.currentTimeMillis(); - if (role == BluetoothPan.LOCAL_PANU_ROLE) { - Log.i("BT", "connect to pan"); - assertTrue(mPan.connect(device)); - } - break; - default: - removeReceiver(receiver); - fail(String.format("%s invalid state: state=%d", methodName, state)); - } - - long s = System.currentTimeMillis(); - while (System.currentTimeMillis() - s < CONNECT_DISCONNECT_PROFILE_TIMEOUT) { - state = mPan.getConnectionState(device); - if (state == BluetoothPan.STATE_CONNECTED - && (receiver.getFiredFlags() & mask) == mask) { - long finish = receiver.getCompletedTime(); - if (start != -1 && finish != -1) { - writeOutput(String.format("%s completed in %d ms", methodName, - (finish - start))); - } else { - writeOutput(String.format("%s completed", methodName)); - } - removeReceiver(receiver); - return; - } - sleep(POLL_TIME); - } - - int firedFlags = receiver.getFiredFlags(); - removeReceiver(receiver); - fail(String.format("%s timeout: state=%d (expected %d), flags=0x%x (expected 0x%s)", - methodName, state, BluetoothPan.STATE_CONNECTED, firedFlags, mask)); - } - - /** - * Disconnects the PANU from a remote NAP and checks to make sure that the PANU is disconnected - * and that the correct actions were broadcast. - * - * @param adapter The BT adapter. - * @param device The remote device. - */ - public void disconnectPan(BluetoothAdapter adapter, BluetoothDevice device) { - disconnectFromRemoteOrVerifyConnectNap(adapter, device, true); - } - - /** - * Checks that a remote PANU disconnects from the local NAP correctly and that the correct - * actions were broadcast. - * - * @param adapter The BT adapter. - * @param device The remote device. - */ - public void incomingPanDisconnection(BluetoothAdapter adapter, BluetoothDevice device) { - disconnectFromRemoteOrVerifyConnectNap(adapter, device, false); - } - - /** - * Helper method used by {@link #disconnectPan(BluetoothAdapter, BluetoothDevice)} and - * {@link #incomingPanDisconnection(BluetoothAdapter, BluetoothDevice)} to either disconnect - * from a remote NAP or verify that a remote device disconnected from the local NAP. - * - * @param adapter The BT adapter. - * @param device The remote device. - * @param disconnect Whether the method should connect or verify. - */ - private void disconnectFromRemoteOrVerifyConnectNap(BluetoothAdapter adapter, - BluetoothDevice device, boolean disconnect) { - long start = -1; - int mask, role; - String methodName; - - if (disconnect) { - methodName = String.format("disconnectPan(device=%s)", device); - mask = (ConnectProfileReceiver.STATE_DISCONNECTED_FLAG | - ConnectProfileReceiver.STATE_DISCONNECTING_FLAG); - role = BluetoothPan.LOCAL_PANU_ROLE; - } else { - methodName = String.format("incomingPanDisconnection(device=%s)", device); - mask = ConnectProfileReceiver.STATE_DISCONNECTED_FLAG; - role = BluetoothPan.LOCAL_NAP_ROLE; - } - - if (!adapter.isEnabled()) { - fail(String.format("%s bluetooth not enabled", methodName)); - } - - if (!adapter.getBondedDevices().contains(device)) { - fail(String.format("%s device not paired", methodName)); - } - - mPan = (BluetoothPan) connectProxy(adapter, BluetoothProfile.PAN); - assertNotNull(mPan); - ConnectPanReceiver receiver = getConnectPanReceiver(device, role, mask); - - int state = mPan.getConnectionState(device); - switch (state) { - case BluetoothPan.STATE_CONNECTED: - case BluetoothPan.STATE_CONNECTING: - start = System.currentTimeMillis(); - if (role == BluetoothPan.LOCAL_PANU_ROLE) { - assertTrue(mPan.disconnect(device)); - } - break; - case BluetoothPan.STATE_DISCONNECTED: - removeReceiver(receiver); - return; - case BluetoothPan.STATE_DISCONNECTING: - mask = 0; // Don't check for received intents since we might have missed them. - break; - default: - removeReceiver(receiver); - fail(String.format("%s invalid state: state=%d", methodName, state)); - } - - long s = System.currentTimeMillis(); - while (System.currentTimeMillis() - s < CONNECT_DISCONNECT_PROFILE_TIMEOUT) { - state = mPan.getConnectionState(device); - if (state == BluetoothHidHost.STATE_DISCONNECTED - && (receiver.getFiredFlags() & mask) == mask) { - long finish = receiver.getCompletedTime(); - if (start != -1 && finish != -1) { - writeOutput(String.format("%s completed in %d ms", methodName, - (finish - start))); - } else { - writeOutput(String.format("%s completed", methodName)); - } - removeReceiver(receiver); - return; - } - sleep(POLL_TIME); - } - - int firedFlags = receiver.getFiredFlags(); - removeReceiver(receiver); - fail(String.format("%s timeout: state=%d (expected %d), flags=0x%x (expected 0x%s)", - methodName, state, BluetoothHidHost.STATE_DISCONNECTED, firedFlags, mask)); - } - - /** - * Opens a SCO channel using {@link android.media.AudioManager#startBluetoothSco()} and checks - * to make sure that the channel is opened and that the correct actions were broadcast. - * - * @param adapter The BT adapter. - * @param device The remote device. - */ - public void startSco(BluetoothAdapter adapter, BluetoothDevice device) { - startStopSco(adapter, device, true); - } - - /** - * Closes a SCO channel using {@link android.media.AudioManager#stopBluetoothSco()} and checks - * to make sure that the channel is closed and that the correct actions were broadcast. - * - * @param adapter The BT adapter. - * @param device The remote device. - */ - public void stopSco(BluetoothAdapter adapter, BluetoothDevice device) { - startStopSco(adapter, device, false); - } - /** - * Helper method for {@link #startSco(BluetoothAdapter, BluetoothDevice)} and - * {@link #stopSco(BluetoothAdapter, BluetoothDevice)}. - * - * @param adapter The BT adapter. - * @param device The remote device. - * @param isStart Whether the SCO channel should be opened. - */ - private void startStopSco(BluetoothAdapter adapter, BluetoothDevice device, boolean isStart) { - long start = -1; - int mask; - String methodName; - - if (isStart) { - methodName = String.format("startSco(device=%s)", device); - mask = StartStopScoReceiver.STATE_CONNECTED_FLAG; - } else { - methodName = String.format("stopSco(device=%s)", device); - mask = StartStopScoReceiver.STATE_DISCONNECTED_FLAG; - } - - if (!adapter.isEnabled()) { - fail(String.format("%s bluetooth not enabled", methodName)); - } - - if (!adapter.getBondedDevices().contains(device)) { - fail(String.format("%s device not paired", methodName)); - } - - AudioManager manager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); - assertNotNull(manager); - - if (!manager.isBluetoothScoAvailableOffCall()) { - fail(String.format("%s device does not support SCO", methodName)); - } - - boolean isScoOn = manager.isBluetoothScoOn(); - if (isStart == isScoOn) { - return; - } - - StartStopScoReceiver receiver = getStartStopScoReceiver(mask); - start = System.currentTimeMillis(); - if (isStart) { - manager.startBluetoothSco(); - } else { - manager.stopBluetoothSco(); - } - - long s = System.currentTimeMillis(); - while (System.currentTimeMillis() - s < START_STOP_SCO_TIMEOUT) { - isScoOn = manager.isBluetoothScoOn(); - if (isStart == isScoOn && (receiver.getFiredFlags() & mask) == mask) { - long finish = receiver.getCompletedTime(); - if (start != -1 && finish != -1) { - writeOutput(String.format("%s completed in %d ms", methodName, - (finish - start))); - } else { - writeOutput(String.format("%s completed", methodName)); - } - removeReceiver(receiver); - return; - } - sleep(POLL_TIME); - } - - int firedFlags = receiver.getFiredFlags(); - removeReceiver(receiver); - fail(String.format("%s timeout: on=%b (expected %b), flags=0x%x (expected 0x%x)", - methodName, isScoOn, isStart, firedFlags, mask)); - } - - /** - * Writes a string to the logcat and a file if a file has been specified in the constructor. - * - * @param s The string to be written. - */ - public void writeOutput(String s) { - Log.i(mTag, s); - if (mOutputWriter == null) { - return; - } - try { - mOutputWriter.write(s + "\n"); - mOutputWriter.flush(); - } catch (IOException e) { - Log.w(mTag, "Could not write to output file", e); - } - } - - public void mceGetUnreadMessage(BluetoothAdapter adapter, BluetoothDevice device) { - int mask; - String methodName = "getUnreadMessage"; - - if (!adapter.isEnabled()) { - fail(String.format("%s bluetooth not enabled", methodName)); - } - - if (!adapter.getBondedDevices().contains(device)) { - fail(String.format("%s device not paired", methodName)); - } - - mMce = (BluetoothMapClient) connectProxy(adapter, BluetoothProfile.MAP_CLIENT); - assertNotNull(mMce); - - if (mMce.getConnectionState(device) != BluetoothProfile.STATE_CONNECTED) { - fail(String.format("%s device is not connected", methodName)); - } - - mMsgHandle = null; - mask = MceSetMessageStatusReceiver.MESSAGE_RECEIVED_FLAG; - MceSetMessageStatusReceiver receiver = getMceSetMessageStatusReceiver(device, mask); - assertTrue(mMce.getUnreadMessages(device)); - - long s = System.currentTimeMillis(); - while (System.currentTimeMillis() - s < GET_UNREAD_MESSAGE_TIMEOUT) { - if ((receiver.getFiredFlags() & mask) == mask) { - writeOutput(String.format("%s completed", methodName)); - removeReceiver(receiver); - return; - } - sleep(POLL_TIME); - } - int firedFlags = receiver.getFiredFlags(); - removeReceiver(receiver); - fail(String.format("%s timeout: state=%d (expected %d), flags=0x%x (expected 0x%s)", - methodName, mMce.getConnectionState(device), BluetoothMapClient.STATE_CONNECTED, firedFlags, mask)); - } - - /** - * Set a message to read/unread/deleted/undeleted - */ - public void mceSetMessageStatus(BluetoothAdapter adapter, BluetoothDevice device, int status) { - int mask; - String methodName = "setMessageStatus"; - - if (!adapter.isEnabled()) { - fail(String.format("%s bluetooth not enabled", methodName)); - } - - if (!adapter.getBondedDevices().contains(device)) { - fail(String.format("%s device not paired", methodName)); - } - - mMce = (BluetoothMapClient) connectProxy(adapter, BluetoothProfile.MAP_CLIENT); - assertNotNull(mMce); - - if (mMce.getConnectionState(device) != BluetoothProfile.STATE_CONNECTED) { - fail(String.format("%s device is not connected", methodName)); - } - - assertNotNull(mMsgHandle); - mask = MceSetMessageStatusReceiver.STATUS_CHANGED_FLAG; - MceSetMessageStatusReceiver receiver = getMceSetMessageStatusReceiver(device, mask); - - assertTrue(mMce.setMessageStatus(device, mMsgHandle, status)); - - long s = System.currentTimeMillis(); - while (System.currentTimeMillis() - s < SET_MESSAGE_STATUS_TIMEOUT) { - if ((receiver.getFiredFlags() & mask) == mask) { - writeOutput(String.format("%s completed", methodName)); - removeReceiver(receiver); - return; - } - sleep(POLL_TIME); - } - - int firedFlags = receiver.getFiredFlags(); - removeReceiver(receiver); - fail(String.format("%s timeout: state=%d (expected %d), flags=0x%x (expected 0x%s)", - methodName, mMce.getConnectionState(device), BluetoothPan.STATE_CONNECTED, firedFlags, mask)); - } - - private void addReceiver(BroadcastReceiver receiver, String[] actions) { - IntentFilter filter = new IntentFilter(); - for (String action: actions) { - filter.addAction(action); - } - mContext.registerReceiver(receiver, filter); - mReceivers.add(receiver); - } - - private BluetoothReceiver getBluetoothReceiver(int expectedFlags) { - String[] actions = { - BluetoothAdapter.ACTION_DISCOVERY_FINISHED, - BluetoothAdapter.ACTION_DISCOVERY_STARTED, - BluetoothAdapter.ACTION_SCAN_MODE_CHANGED, - BluetoothAdapter.ACTION_STATE_CHANGED}; - BluetoothReceiver receiver = new BluetoothReceiver(expectedFlags); - addReceiver(receiver, actions); - return receiver; - } - - private PairReceiver getPairReceiver(BluetoothDevice device, int passkey, byte[] pin, - int expectedFlags) { - String[] actions = { - BluetoothDevice.ACTION_PAIRING_REQUEST, - BluetoothDevice.ACTION_BOND_STATE_CHANGED}; - PairReceiver receiver = new PairReceiver(device, passkey, pin, expectedFlags); - addReceiver(receiver, actions); - return receiver; - } - - private ConnectProfileReceiver getConnectProfileReceiver(BluetoothDevice device, int profile, - int expectedFlags) { - String[] actions = { - BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED, - BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED, - BluetoothHidHost.ACTION_CONNECTION_STATE_CHANGED, - BluetoothMapClient.ACTION_CONNECTION_STATE_CHANGED}; - ConnectProfileReceiver receiver = new ConnectProfileReceiver(device, profile, - expectedFlags); - addReceiver(receiver, actions); - return receiver; - } - - private ConnectPanReceiver getConnectPanReceiver(BluetoothDevice device, int role, - int expectedFlags) { - String[] actions = {BluetoothPan.ACTION_CONNECTION_STATE_CHANGED}; - ConnectPanReceiver receiver = new ConnectPanReceiver(device, role, expectedFlags); - addReceiver(receiver, actions); - return receiver; - } - - private StartStopScoReceiver getStartStopScoReceiver(int expectedFlags) { - String[] actions = {AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED}; - StartStopScoReceiver receiver = new StartStopScoReceiver(expectedFlags); - addReceiver(receiver, actions); - return receiver; - } - - private MceSetMessageStatusReceiver getMceSetMessageStatusReceiver(BluetoothDevice device, - int expectedFlags) { - String[] actions = {BluetoothMapClient.ACTION_MESSAGE_RECEIVED, - BluetoothMapClient.ACTION_MESSAGE_READ_STATUS_CHANGED, - BluetoothMapClient.ACTION_MESSAGE_DELETED_STATUS_CHANGED}; - MceSetMessageStatusReceiver receiver = new MceSetMessageStatusReceiver(expectedFlags); - addReceiver(receiver, actions); - return receiver; - } - - private void removeReceiver(BroadcastReceiver receiver) { - mContext.unregisterReceiver(receiver); - mReceivers.remove(receiver); - } - - private BluetoothProfile connectProxy(BluetoothAdapter adapter, int profile) { - switch (profile) { - case BluetoothProfile.A2DP: - if (mA2dp != null) { - return mA2dp; - } - break; - case BluetoothProfile.HEADSET: - if (mHeadset != null) { - return mHeadset; - } - break; - case BluetoothProfile.HID_HOST: - if (mInput != null) { - return mInput; - } - break; - case BluetoothProfile.PAN: - if (mPan != null) { - return mPan; - } - case BluetoothProfile.MAP_CLIENT: - if (mMce != null) { - return mMce; - } - break; - default: - return null; - } - adapter.getProfileProxy(mContext, mServiceListener, profile); - long s = System.currentTimeMillis(); - switch (profile) { - case BluetoothProfile.A2DP: - while (mA2dp == null && System.currentTimeMillis() - s < CONNECT_PROXY_TIMEOUT) { - sleep(POLL_TIME); - } - return mA2dp; - case BluetoothProfile.HEADSET: - while (mHeadset == null && System.currentTimeMillis() - s < CONNECT_PROXY_TIMEOUT) { - sleep(POLL_TIME); - } - return mHeadset; - case BluetoothProfile.HID_HOST: - while (mInput == null && System.currentTimeMillis() - s < CONNECT_PROXY_TIMEOUT) { - sleep(POLL_TIME); - } - return mInput; - case BluetoothProfile.PAN: - while (mPan == null && System.currentTimeMillis() - s < CONNECT_PROXY_TIMEOUT) { - sleep(POLL_TIME); - } - return mPan; - case BluetoothProfile.MAP_CLIENT: - while (mMce == null && System.currentTimeMillis() - s < CONNECT_PROXY_TIMEOUT) { - sleep(POLL_TIME); - } - return mMce; - default: - return null; - } - } - - private void sleep(long time) { - try { - Thread.sleep(time); - } catch (InterruptedException e) { - } - } -} diff --git a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothUuidTest.java b/core/tests/bluetoothtests/src/android/bluetooth/BluetoothUuidTest.java deleted file mode 100644 index 536d722679b6c4b54f0db9d5fcaff7629e3a3482..0000000000000000000000000000000000000000 --- a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothUuidTest.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (C) 2014 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.bluetooth; - -import android.os.ParcelUuid; -import android.test.suitebuilder.annotation.SmallTest; - -import junit.framework.TestCase; - -/** - * Unit test cases for {@link BluetoothUuid}. - *

    - * To run this test, use adb shell am instrument -e class 'android.bluetooth.BluetoothUuidTest' -w - * 'com.android.bluetooth.tests/android.bluetooth.BluetoothTestRunner' - */ -public class BluetoothUuidTest extends TestCase { - - @SmallTest - public void testUuidParser() { - byte[] uuid16 = new byte[] { - 0x0B, 0x11 }; - assertEquals(ParcelUuid.fromString("0000110B-0000-1000-8000-00805F9B34FB"), - BluetoothUuid.parseUuidFrom(uuid16)); - - byte[] uuid32 = new byte[] { - 0x0B, 0x11, 0x33, (byte) 0xFE }; - assertEquals(ParcelUuid.fromString("FE33110B-0000-1000-8000-00805F9B34FB"), - BluetoothUuid.parseUuidFrom(uuid32)); - - byte[] uuid128 = new byte[] { - 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, - 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, (byte) 0xFF }; - assertEquals(ParcelUuid.fromString("FF0F0E0D-0C0B-0A09-0807-0060504030201"), - BluetoothUuid.parseUuidFrom(uuid128)); - } - - @SmallTest - public void testUuidType() { - assertTrue(BluetoothUuid.is16BitUuid( - ParcelUuid.fromString("0000110B-0000-1000-8000-00805F9B34FB"))); - assertFalse(BluetoothUuid.is32BitUuid( - ParcelUuid.fromString("0000110B-0000-1000-8000-00805F9B34FB"))); - - assertFalse(BluetoothUuid.is16BitUuid( - ParcelUuid.fromString("FE33110B-0000-1000-8000-00805F9B34FB"))); - assertTrue(BluetoothUuid.is32BitUuid( - ParcelUuid.fromString("FE33110B-0000-1000-8000-00805F9B34FB"))); - assertFalse(BluetoothUuid.is32BitUuid( - ParcelUuid.fromString("FE33110B-1000-1000-8000-00805F9B34FB"))); - - } -} diff --git a/core/tests/bluetoothtests/src/android/bluetooth/le/AdvertiseDataTest.java b/core/tests/bluetoothtests/src/android/bluetooth/le/AdvertiseDataTest.java deleted file mode 100644 index e58d905357e6e80363d8f9179f13ea506cfe9794..0000000000000000000000000000000000000000 --- a/core/tests/bluetoothtests/src/android/bluetooth/le/AdvertiseDataTest.java +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright (C) 2014 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.bluetooth.le; - -import android.os.Parcel; -import android.os.ParcelUuid; -import android.test.suitebuilder.annotation.SmallTest; - -import junit.framework.TestCase; - -/** - * Unit test cases for {@link AdvertiseData}. - *

    - * To run the test, use adb shell am instrument -e class 'android.bluetooth.le.AdvertiseDataTest' -w - * 'com.android.bluetooth.tests/android.bluetooth.BluetoothTestRunner' - */ -public class AdvertiseDataTest extends TestCase { - - private AdvertiseData.Builder mAdvertiseDataBuilder; - - @Override - protected void setUp() throws Exception { - mAdvertiseDataBuilder = new AdvertiseData.Builder(); - } - - @SmallTest - public void testEmptyData() { - Parcel parcel = Parcel.obtain(); - AdvertiseData data = mAdvertiseDataBuilder.build(); - data.writeToParcel(parcel, 0); - parcel.setDataPosition(0); - AdvertiseData dataFromParcel = - AdvertiseData.CREATOR.createFromParcel(parcel); - assertEquals(data, dataFromParcel); - } - - @SmallTest - public void testEmptyServiceUuid() { - Parcel parcel = Parcel.obtain(); - AdvertiseData data = mAdvertiseDataBuilder.setIncludeDeviceName(true).build(); - data.writeToParcel(parcel, 0); - parcel.setDataPosition(0); - AdvertiseData dataFromParcel = - AdvertiseData.CREATOR.createFromParcel(parcel); - assertEquals(data, dataFromParcel); - } - - @SmallTest - public void testEmptyManufacturerData() { - Parcel parcel = Parcel.obtain(); - int manufacturerId = 50; - byte[] manufacturerData = new byte[0]; - AdvertiseData data = - mAdvertiseDataBuilder.setIncludeDeviceName(true) - .addManufacturerData(manufacturerId, manufacturerData).build(); - data.writeToParcel(parcel, 0); - parcel.setDataPosition(0); - AdvertiseData dataFromParcel = - AdvertiseData.CREATOR.createFromParcel(parcel); - assertEquals(data, dataFromParcel); - } - - @SmallTest - public void testEmptyServiceData() { - Parcel parcel = Parcel.obtain(); - ParcelUuid uuid = ParcelUuid.fromString("0000110A-0000-1000-8000-00805F9B34FB"); - byte[] serviceData = new byte[0]; - AdvertiseData data = - mAdvertiseDataBuilder.setIncludeDeviceName(true) - .addServiceData(uuid, serviceData).build(); - data.writeToParcel(parcel, 0); - parcel.setDataPosition(0); - AdvertiseData dataFromParcel = - AdvertiseData.CREATOR.createFromParcel(parcel); - assertEquals(data, dataFromParcel); - } - - @SmallTest - public void testServiceUuid() { - Parcel parcel = Parcel.obtain(); - ParcelUuid uuid = ParcelUuid.fromString("0000110A-0000-1000-8000-00805F9B34FB"); - ParcelUuid uuid2 = ParcelUuid.fromString("0000110B-0000-1000-8000-00805F9B34FB"); - - AdvertiseData data = - mAdvertiseDataBuilder.setIncludeDeviceName(true) - .addServiceUuid(uuid).addServiceUuid(uuid2).build(); - data.writeToParcel(parcel, 0); - parcel.setDataPosition(0); - AdvertiseData dataFromParcel = - AdvertiseData.CREATOR.createFromParcel(parcel); - assertEquals(data, dataFromParcel); - } - - @SmallTest - public void testManufacturerData() { - Parcel parcel = Parcel.obtain(); - ParcelUuid uuid = ParcelUuid.fromString("0000110A-0000-1000-8000-00805F9B34FB"); - ParcelUuid uuid2 = ParcelUuid.fromString("0000110B-0000-1000-8000-00805F9B34FB"); - - int manufacturerId = 50; - byte[] manufacturerData = new byte[] { - (byte) 0xF0, 0x00, 0x02, 0x15 }; - AdvertiseData data = - mAdvertiseDataBuilder.setIncludeDeviceName(true) - .addServiceUuid(uuid).addServiceUuid(uuid2) - .addManufacturerData(manufacturerId, manufacturerData).build(); - - data.writeToParcel(parcel, 0); - parcel.setDataPosition(0); - AdvertiseData dataFromParcel = - AdvertiseData.CREATOR.createFromParcel(parcel); - assertEquals(data, dataFromParcel); - } - - @SmallTest - public void testServiceData() { - Parcel parcel = Parcel.obtain(); - ParcelUuid uuid = ParcelUuid.fromString("0000110A-0000-1000-8000-00805F9B34FB"); - byte[] serviceData = new byte[] { - (byte) 0xF0, 0x00, 0x02, 0x15 }; - AdvertiseData data = - mAdvertiseDataBuilder.setIncludeDeviceName(true) - .addServiceData(uuid, serviceData).build(); - data.writeToParcel(parcel, 0); - parcel.setDataPosition(0); - AdvertiseData dataFromParcel = - AdvertiseData.CREATOR.createFromParcel(parcel); - assertEquals(data, dataFromParcel); - } -} diff --git a/core/tests/bluetoothtests/src/android/bluetooth/le/ScanFilterTest.java b/core/tests/bluetoothtests/src/android/bluetooth/le/ScanFilterTest.java deleted file mode 100644 index 35da4bceb620fe9f4b67bea202b9f01e80535db9..0000000000000000000000000000000000000000 --- a/core/tests/bluetoothtests/src/android/bluetooth/le/ScanFilterTest.java +++ /dev/null @@ -1,215 +0,0 @@ -/* - * Copyright (C) 2014 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.bluetooth.le; - -import android.bluetooth.BluetoothAdapter; -import android.bluetooth.BluetoothDevice; -import android.bluetooth.le.ScanFilter; -import android.bluetooth.le.ScanRecord; -import android.os.Parcel; -import android.os.ParcelUuid; -import android.test.suitebuilder.annotation.SmallTest; - -import junit.framework.TestCase; - -/** - * Unit test cases for Bluetooth LE scan filters. - *

    - * To run this test, use adb shell am instrument -e class 'android.bluetooth.ScanFilterTest' -w - * 'com.android.bluetooth.tests/android.bluetooth.BluetoothTestRunner' - */ -public class ScanFilterTest extends TestCase { - - private static final String DEVICE_MAC = "01:02:03:04:05:AB"; - private ScanResult mScanResult; - private ScanFilter.Builder mFilterBuilder; - - @Override - protected void setUp() throws Exception { - byte[] scanRecord = new byte[] { - 0x02, 0x01, 0x1a, // advertising flags - 0x05, 0x02, 0x0b, 0x11, 0x0a, 0x11, // 16 bit service uuids - 0x04, 0x09, 0x50, 0x65, 0x64, // setName - 0x02, 0x0A, (byte) 0xec, // tx power level - 0x05, 0x16, 0x0b, 0x11, 0x50, 0x64, // service data - 0x05, (byte) 0xff, (byte) 0xe0, 0x00, 0x02, 0x15, // manufacturer specific data - 0x03, 0x50, 0x01, 0x02, // an unknown data type won't cause trouble - }; - - BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); - BluetoothDevice device = adapter.getRemoteDevice(DEVICE_MAC); - mScanResult = new ScanResult(device, ScanRecord.parseFromBytes(scanRecord), - -10, 1397545200000000L); - mFilterBuilder = new ScanFilter.Builder(); - } - - @SmallTest - public void testsetNameFilter() { - ScanFilter filter = mFilterBuilder.setDeviceName("Ped").build(); - assertTrue("setName filter fails", filter.matches(mScanResult)); - - filter = mFilterBuilder.setDeviceName("Pem").build(); - assertFalse("setName filter fails", filter.matches(mScanResult)); - - } - - @SmallTest - public void testDeviceFilter() { - ScanFilter filter = mFilterBuilder.setDeviceAddress(DEVICE_MAC).build(); - assertTrue("device filter fails", filter.matches(mScanResult)); - - filter = mFilterBuilder.setDeviceAddress("11:22:33:44:55:66").build(); - assertFalse("device filter fails", filter.matches(mScanResult)); - } - - @SmallTest - public void testsetServiceUuidFilter() { - ScanFilter filter = mFilterBuilder.setServiceUuid( - ParcelUuid.fromString("0000110A-0000-1000-8000-00805F9B34FB")).build(); - assertTrue("uuid filter fails", filter.matches(mScanResult)); - - filter = mFilterBuilder.setServiceUuid( - ParcelUuid.fromString("0000110C-0000-1000-8000-00805F9B34FB")).build(); - assertFalse("uuid filter fails", filter.matches(mScanResult)); - - filter = mFilterBuilder - .setServiceUuid(ParcelUuid.fromString("0000110C-0000-1000-8000-00805F9B34FB"), - ParcelUuid.fromString("FFFFFFF0-FFFF-FFFF-FFFF-FFFFFFFFFFFF")) - .build(); - assertTrue("uuid filter fails", filter.matches(mScanResult)); - } - - @SmallTest - public void testsetServiceDataFilter() { - byte[] setServiceData = new byte[] { - 0x50, 0x64 }; - ParcelUuid serviceDataUuid = ParcelUuid.fromString("0000110B-0000-1000-8000-00805F9B34FB"); - ScanFilter filter = mFilterBuilder.setServiceData(serviceDataUuid, setServiceData).build(); - assertTrue("service data filter fails", filter.matches(mScanResult)); - - byte[] emptyData = new byte[0]; - filter = mFilterBuilder.setServiceData(serviceDataUuid, emptyData).build(); - assertTrue("service data filter fails", filter.matches(mScanResult)); - - byte[] prefixData = new byte[] { - 0x50 }; - filter = mFilterBuilder.setServiceData(serviceDataUuid, prefixData).build(); - assertTrue("service data filter fails", filter.matches(mScanResult)); - - byte[] nonMatchData = new byte[] { - 0x51, 0x64 }; - byte[] mask = new byte[] { - (byte) 0x00, (byte) 0xFF }; - filter = mFilterBuilder.setServiceData(serviceDataUuid, nonMatchData, mask).build(); - assertTrue("partial service data filter fails", filter.matches(mScanResult)); - - filter = mFilterBuilder.setServiceData(serviceDataUuid, nonMatchData).build(); - assertFalse("service data filter fails", filter.matches(mScanResult)); - } - - @SmallTest - public void testManufacturerSpecificData() { - byte[] setManufacturerData = new byte[] { - 0x02, 0x15 }; - int manufacturerId = 0xE0; - ScanFilter filter = - mFilterBuilder.setManufacturerData(manufacturerId, setManufacturerData).build(); - assertTrue("manufacturer data filter fails", filter.matches(mScanResult)); - - byte[] emptyData = new byte[0]; - filter = mFilterBuilder.setManufacturerData(manufacturerId, emptyData).build(); - assertTrue("manufacturer data filter fails", filter.matches(mScanResult)); - - byte[] prefixData = new byte[] { - 0x02 }; - filter = mFilterBuilder.setManufacturerData(manufacturerId, prefixData).build(); - assertTrue("manufacturer data filter fails", filter.matches(mScanResult)); - - // Test data mask - byte[] nonMatchData = new byte[] { - 0x02, 0x14 }; - filter = mFilterBuilder.setManufacturerData(manufacturerId, nonMatchData).build(); - assertFalse("manufacturer data filter fails", filter.matches(mScanResult)); - byte[] mask = new byte[] { - (byte) 0xFF, (byte) 0x00 - }; - filter = mFilterBuilder.setManufacturerData(manufacturerId, nonMatchData, mask).build(); - assertTrue("partial setManufacturerData filter fails", filter.matches(mScanResult)); - } - - @SmallTest - public void testReadWriteParcel() { - ScanFilter filter = mFilterBuilder.build(); - testReadWriteParcelForFilter(filter); - - filter = mFilterBuilder.setDeviceName("Ped").build(); - testReadWriteParcelForFilter(filter); - - filter = mFilterBuilder.setDeviceAddress("11:22:33:44:55:66").build(); - testReadWriteParcelForFilter(filter); - - filter = mFilterBuilder.setServiceUuid( - ParcelUuid.fromString("0000110C-0000-1000-8000-00805F9B34FB")).build(); - testReadWriteParcelForFilter(filter); - - filter = mFilterBuilder.setServiceUuid( - ParcelUuid.fromString("0000110C-0000-1000-8000-00805F9B34FB"), - ParcelUuid.fromString("FFFFFFF0-FFFF-FFFF-FFFF-FFFFFFFFFFFF")).build(); - testReadWriteParcelForFilter(filter); - - byte[] serviceData = new byte[] { - 0x50, 0x64 }; - - ParcelUuid serviceDataUuid = ParcelUuid.fromString("0000110B-0000-1000-8000-00805F9B34FB"); - filter = mFilterBuilder.setServiceData(serviceDataUuid, serviceData).build(); - testReadWriteParcelForFilter(filter); - - filter = mFilterBuilder.setServiceData(serviceDataUuid, new byte[0]).build(); - testReadWriteParcelForFilter(filter); - - byte[] serviceDataMask = new byte[] { - (byte) 0xFF, (byte) 0xFF }; - filter = mFilterBuilder.setServiceData(serviceDataUuid, serviceData, serviceDataMask) - .build(); - testReadWriteParcelForFilter(filter); - - byte[] manufacturerData = new byte[] { - 0x02, 0x15 }; - int manufacturerId = 0xE0; - filter = mFilterBuilder.setManufacturerData(manufacturerId, manufacturerData).build(); - testReadWriteParcelForFilter(filter); - - filter = mFilterBuilder.setServiceData(serviceDataUuid, new byte[0]).build(); - testReadWriteParcelForFilter(filter); - - byte[] manufacturerDataMask = new byte[] { - (byte) 0xFF, (byte) 0xFF - }; - filter = mFilterBuilder.setManufacturerData(manufacturerId, manufacturerData, - manufacturerDataMask).build(); - testReadWriteParcelForFilter(filter); - } - - private void testReadWriteParcelForFilter(ScanFilter filter) { - Parcel parcel = Parcel.obtain(); - filter.writeToParcel(parcel, 0); - parcel.setDataPosition(0); - ScanFilter filterFromParcel = - ScanFilter.CREATOR.createFromParcel(parcel); - assertEquals(filter, filterFromParcel); - } -} diff --git a/core/tests/bluetoothtests/src/android/bluetooth/le/ScanRecordTest.java b/core/tests/bluetoothtests/src/android/bluetooth/le/ScanRecordTest.java deleted file mode 100644 index 4e817d4a0d91bdd207fb0c5a618debad09226d84..0000000000000000000000000000000000000000 --- a/core/tests/bluetoothtests/src/android/bluetooth/le/ScanRecordTest.java +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Copyright (C) 2014 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.bluetooth.le; - -import android.os.ParcelUuid; -import android.test.suitebuilder.annotation.SmallTest; - -import com.android.internal.util.HexDump; -import com.android.modules.utils.BytesMatcher; - -import junit.framework.TestCase; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.function.Predicate; - -/** - * Unit test cases for {@link ScanRecord}. - *

    - * To run this test, use adb shell am instrument -e class 'android.bluetooth.ScanRecordTest' -w - * 'com.android.bluetooth.tests/android.bluetooth.BluetoothTestRunner' - */ -public class ScanRecordTest extends TestCase { - /** - * Example raw beacons captured from a Blue Charm BC011 - */ - private static final String RECORD_URL = "0201060303AAFE1716AAFE10EE01626C7565636861726D626561636F6E730009168020691E0EFE13551109426C7565436861726D5F313639363835000000"; - private static final String RECORD_UUID = "0201060303AAFE1716AAFE00EE626C7565636861726D31000000000001000009168020691E0EFE13551109426C7565436861726D5F313639363835000000"; - private static final String RECORD_TLM = "0201060303AAFE1116AAFE20000BF017000008874803FB93540916802069080EFE13551109426C7565436861726D5F313639363835000000000000000000"; - private static final String RECORD_IBEACON = "0201061AFF4C000215426C7565436861726D426561636F6E730EFE1355C509168020691E0EFE13551109426C7565436861726D5F31363936383500000000"; - - @SmallTest - public void testMatchesAnyField_Eddystone_Parser() { - final List found = new ArrayList<>(); - final Predicate matcher = (v) -> { - found.add(HexDump.toHexString(v)); - return false; - }; - ScanRecord.parseFromBytes(HexDump.hexStringToByteArray(RECORD_URL)) - .matchesAnyField(matcher); - - assertEquals(Arrays.asList( - "020106", - "0303AAFE", - "1716AAFE10EE01626C7565636861726D626561636F6E7300", - "09168020691E0EFE1355", - "1109426C7565436861726D5F313639363835"), found); - } - - @SmallTest - public void testMatchesAnyField_Eddystone() { - final BytesMatcher matcher = BytesMatcher.decode("⊆0016AAFE/00FFFFFF"); - assertMatchesAnyField(RECORD_URL, matcher); - assertMatchesAnyField(RECORD_UUID, matcher); - assertMatchesAnyField(RECORD_TLM, matcher); - assertNotMatchesAnyField(RECORD_IBEACON, matcher); - } - - @SmallTest - public void testMatchesAnyField_iBeacon_Parser() { - final List found = new ArrayList<>(); - final Predicate matcher = (v) -> { - found.add(HexDump.toHexString(v)); - return false; - }; - ScanRecord.parseFromBytes(HexDump.hexStringToByteArray(RECORD_IBEACON)) - .matchesAnyField(matcher); - - assertEquals(Arrays.asList( - "020106", - "1AFF4C000215426C7565436861726D426561636F6E730EFE1355C5", - "09168020691E0EFE1355", - "1109426C7565436861726D5F313639363835"), found); - } - - @SmallTest - public void testMatchesAnyField_iBeacon() { - final BytesMatcher matcher = BytesMatcher.decode("⊆00FF4C0002/00FFFFFFFF"); - assertNotMatchesAnyField(RECORD_URL, matcher); - assertNotMatchesAnyField(RECORD_UUID, matcher); - assertNotMatchesAnyField(RECORD_TLM, matcher); - assertMatchesAnyField(RECORD_IBEACON, matcher); - } - - @SmallTest - public void testParser() { - byte[] scanRecord = new byte[] { - 0x02, 0x01, 0x1a, // advertising flags - 0x05, 0x02, 0x0b, 0x11, 0x0a, 0x11, // 16 bit service uuids - 0x04, 0x09, 0x50, 0x65, 0x64, // name - 0x02, 0x0A, (byte) 0xec, // tx power level - 0x05, 0x16, 0x0b, 0x11, 0x50, 0x64, // service data - 0x05, (byte) 0xff, (byte) 0xe0, 0x00, 0x02, 0x15, // manufacturer specific data - 0x03, 0x50, 0x01, 0x02, // an unknown data type won't cause trouble - }; - ScanRecord data = ScanRecord.parseFromBytes(scanRecord); - assertEquals(0x1a, data.getAdvertiseFlags()); - ParcelUuid uuid1 = ParcelUuid.fromString("0000110A-0000-1000-8000-00805F9B34FB"); - ParcelUuid uuid2 = ParcelUuid.fromString("0000110B-0000-1000-8000-00805F9B34FB"); - assertTrue(data.getServiceUuids().contains(uuid1)); - assertTrue(data.getServiceUuids().contains(uuid2)); - - assertEquals("Ped", data.getDeviceName()); - assertEquals(-20, data.getTxPowerLevel()); - - assertTrue(data.getManufacturerSpecificData().get(0x00E0) != null); - assertArrayEquals(new byte[] { - 0x02, 0x15 }, data.getManufacturerSpecificData().get(0x00E0)); - - assertTrue(data.getServiceData().containsKey(uuid2)); - assertArrayEquals(new byte[] { - 0x50, 0x64 }, data.getServiceData().get(uuid2)); - } - - // Assert two byte arrays are equal. - private static void assertArrayEquals(byte[] expected, byte[] actual) { - if (!Arrays.equals(expected, actual)) { - fail("expected:<" + Arrays.toString(expected) + - "> but was:<" + Arrays.toString(actual) + ">"); - } - - } - - private static void assertMatchesAnyField(String record, BytesMatcher matcher) { - assertTrue(ScanRecord.parseFromBytes(HexDump.hexStringToByteArray(record)) - .matchesAnyField(matcher)); - } - - private static void assertNotMatchesAnyField(String record, BytesMatcher matcher) { - assertFalse(ScanRecord.parseFromBytes(HexDump.hexStringToByteArray(record)) - .matchesAnyField(matcher)); - } -} diff --git a/core/tests/bluetoothtests/src/android/bluetooth/le/ScanResultTest.java b/core/tests/bluetoothtests/src/android/bluetooth/le/ScanResultTest.java deleted file mode 100644 index 01d5c593bf27990126df3b64529f0c905e76b802..0000000000000000000000000000000000000000 --- a/core/tests/bluetoothtests/src/android/bluetooth/le/ScanResultTest.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (C) 2014 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.bluetooth.le; - -import android.bluetooth.BluetoothAdapter; -import android.bluetooth.BluetoothDevice; -import android.os.Parcel; -import android.test.suitebuilder.annotation.SmallTest; - -import junit.framework.TestCase; - -/** - * Unit test cases for Bluetooth LE scans. - *

    - * To run this test, use adb shell am instrument -e class 'android.bluetooth.ScanResultTest' -w - * 'com.android.bluetooth.tests/android.bluetooth.BluetoothTestRunner' - */ -public class ScanResultTest extends TestCase { - - /** - * Test read and write parcel of ScanResult - */ - @SmallTest - public void testScanResultParceling() { - BluetoothDevice device = BluetoothAdapter.getDefaultAdapter().getRemoteDevice( - "01:02:03:04:05:06"); - byte[] scanRecord = new byte[] { - 1, 2, 3 }; - int rssi = -10; - long timestampMicros = 10000L; - - ScanResult result = new ScanResult(device, ScanRecord.parseFromBytes(scanRecord), rssi, - timestampMicros); - Parcel parcel = Parcel.obtain(); - result.writeToParcel(parcel, 0); - // Need to reset parcel data position to the beginning. - parcel.setDataPosition(0); - ScanResult resultFromParcel = ScanResult.CREATOR.createFromParcel(parcel); - assertEquals(result, resultFromParcel); - } - -} diff --git a/core/tests/bluetoothtests/src/android/bluetooth/le/ScanSettingsTest.java b/core/tests/bluetoothtests/src/android/bluetooth/le/ScanSettingsTest.java deleted file mode 100644 index 7c42c3b46775a0af57e88a5a25fbaff90b04ae84..0000000000000000000000000000000000000000 --- a/core/tests/bluetoothtests/src/android/bluetooth/le/ScanSettingsTest.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (C) 2014 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.bluetooth.le; - -import android.test.suitebuilder.annotation.SmallTest; - -import junit.framework.TestCase; - -/** - * Test for Bluetooth LE {@link ScanSettings}. - */ -public class ScanSettingsTest extends TestCase { - - @SmallTest - public void testCallbackType() { - ScanSettings.Builder builder = new ScanSettings.Builder(); - builder.setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES); - builder.setCallbackType(ScanSettings.CALLBACK_TYPE_FIRST_MATCH); - builder.setCallbackType(ScanSettings.CALLBACK_TYPE_MATCH_LOST); - builder.setCallbackType( - ScanSettings.CALLBACK_TYPE_FIRST_MATCH | ScanSettings.CALLBACK_TYPE_MATCH_LOST); - try { - builder.setCallbackType( - ScanSettings.CALLBACK_TYPE_ALL_MATCHES | ScanSettings.CALLBACK_TYPE_MATCH_LOST); - fail("should have thrown IllegalArgumentException!"); - } catch (IllegalArgumentException e) { - // nothing to do - } - - try { - builder.setCallbackType( - ScanSettings.CALLBACK_TYPE_ALL_MATCHES | - ScanSettings.CALLBACK_TYPE_FIRST_MATCH); - fail("should have thrown IllegalArgumentException!"); - } catch (IllegalArgumentException e) { - // nothing to do - } - - try { - builder.setCallbackType( - ScanSettings.CALLBACK_TYPE_ALL_MATCHES | - ScanSettings.CALLBACK_TYPE_FIRST_MATCH | - ScanSettings.CALLBACK_TYPE_MATCH_LOST); - fail("should have thrown IllegalArgumentException!"); - } catch (IllegalArgumentException e) { - // nothing to do - } - - } -} diff --git a/services/Android.bp b/services/Android.bp index 841edc7ed50958985129b2a5c243255a855e4f42..8fb9ae86a15f6cbe52e6e659d29f67fbc4296296 100644 --- a/services/Android.bp +++ b/services/Android.bp @@ -74,6 +74,7 @@ filegroup { ":services.appwidget-sources", ":services.autofill-sources", ":services.backup-sources", + ":services.bluetooth-sources", // TODO(b/214988855) : Remove once apex/service-bluetooth jar is ready ":backuplib-sources", ":services.companion-sources", ":services.contentcapture-sources", diff --git a/services/core/Android.bp b/services/core/Android.bp index 7a4f1de95e0cec8a2df31dc28945832c272fd567..960f7ca63b1d8dd36f16a102b00a581a29b81eed 100644 --- a/services/core/Android.bp +++ b/services/core/Android.bp @@ -93,6 +93,7 @@ java_library_static { defaults: ["platform_service_defaults"], srcs: [ ":statslog-art-java-gen", + ":services.bluetooth-sources", // TODO(b/214988855) : Remove once apex is ready ":services.core-sources", ":services.core.protologsrc", ":dumpstate_aidl", diff --git a/services/core/java/com/android/server/BluetoothAirplaneModeListener.java b/services/core/java/com/android/server/BluetoothAirplaneModeListener.java deleted file mode 100644 index 380b1f37b9817d0e7df22cc07e1f8a93d9e3e9b5..0000000000000000000000000000000000000000 --- a/services/core/java/com/android/server/BluetoothAirplaneModeListener.java +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright 2019 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.android.server; - -import android.annotation.RequiresPermission; -import android.content.Context; -import android.database.ContentObserver; -import android.os.Handler; -import android.os.Looper; -import android.os.Message; -import android.provider.Settings; -import android.util.Log; - -import com.android.internal.annotations.VisibleForTesting; - -/** - * The BluetoothAirplaneModeListener handles system airplane mode change callback and checks - * whether we need to inform BluetoothManagerService on this change. - * - * The information of airplane mode turns on would not be passed to the BluetoothManagerService - * when Bluetooth is on and Bluetooth is in one of the following situations: - * 1. Bluetooth A2DP is connected. - * 2. Bluetooth Hearing Aid profile is connected. - * 3. Bluetooth LE Audio is connected - */ -class BluetoothAirplaneModeListener { - private static final String TAG = "BluetoothAirplaneModeListener"; - @VisibleForTesting static final String TOAST_COUNT = "bluetooth_airplane_toast_count"; - - private static final int MSG_AIRPLANE_MODE_CHANGED = 0; - - @VisibleForTesting static final int MAX_TOAST_COUNT = 10; // 10 times - - private final BluetoothManagerService mBluetoothManager; - private final BluetoothAirplaneModeHandler mHandler; - private BluetoothModeChangeHelper mAirplaneHelper; - - @VisibleForTesting int mToastCount = 0; - - BluetoothAirplaneModeListener(BluetoothManagerService service, Looper looper, Context context) { - mBluetoothManager = service; - - mHandler = new BluetoothAirplaneModeHandler(looper); - context.getContentResolver().registerContentObserver( - Settings.Global.getUriFor(Settings.Global.AIRPLANE_MODE_ON), true, - mAirplaneModeObserver); - } - - private final ContentObserver mAirplaneModeObserver = new ContentObserver(null) { - @Override - public void onChange(boolean unused) { - // Post from system main thread to android_io thread. - Message msg = mHandler.obtainMessage(MSG_AIRPLANE_MODE_CHANGED); - mHandler.sendMessage(msg); - } - }; - - private class BluetoothAirplaneModeHandler extends Handler { - BluetoothAirplaneModeHandler(Looper looper) { - super(looper); - } - - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case MSG_AIRPLANE_MODE_CHANGED: - handleAirplaneModeChange(); - break; - default: - Log.e(TAG, "Invalid message: " + msg.what); - break; - } - } - } - - /** - * Call after boot complete - */ - @VisibleForTesting - void start(BluetoothModeChangeHelper helper) { - Log.i(TAG, "start"); - mAirplaneHelper = helper; - mToastCount = mAirplaneHelper.getSettingsInt(TOAST_COUNT); - } - - @VisibleForTesting - boolean shouldPopToast() { - if (mToastCount >= MAX_TOAST_COUNT) { - return false; - } - mToastCount++; - mAirplaneHelper.setSettingsInt(TOAST_COUNT, mToastCount); - return true; - } - - @VisibleForTesting - @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) - void handleAirplaneModeChange() { - if (shouldSkipAirplaneModeChange()) { - Log.i(TAG, "Ignore airplane mode change"); - // Airplane mode enabled when Bluetooth is being used for audio/headering aid. - // Bluetooth is not disabled in such case, only state is changed to - // BLUETOOTH_ON_AIRPLANE mode. - mAirplaneHelper.setSettingsInt(Settings.Global.BLUETOOTH_ON, - BluetoothManagerService.BLUETOOTH_ON_AIRPLANE); - if (shouldPopToast()) { - mAirplaneHelper.showToastMessage(); - } - return; - } - if (mAirplaneHelper != null) { - mAirplaneHelper.onAirplaneModeChanged(mBluetoothManager); - } - } - - @VisibleForTesting - boolean shouldSkipAirplaneModeChange() { - if (mAirplaneHelper == null) { - return false; - } - if (!mAirplaneHelper.isBluetoothOn() || !mAirplaneHelper.isAirplaneModeOn() - || !mAirplaneHelper.isMediaProfileConnected()) { - return false; - } - return true; - } -} diff --git a/services/core/java/com/android/server/BluetoothDeviceConfigListener.java b/services/core/java/com/android/server/BluetoothDeviceConfigListener.java deleted file mode 100644 index 611a37de70f4380c353911dcca24462564ea899c..0000000000000000000000000000000000000000 --- a/services/core/java/com/android/server/BluetoothDeviceConfigListener.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright 2020 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.android.server; - -import android.provider.DeviceConfig; -import android.util.Slog; - -import java.util.ArrayList; - -/** - * The BluetoothDeviceConfigListener handles system device config change callback and checks - * whether we need to inform BluetoothManagerService on this change. - * - * The information of device config change would not be passed to the BluetoothManagerService - * when Bluetooth is on and Bluetooth is in one of the following situations: - * 1. Bluetooth A2DP is connected. - * 2. Bluetooth Hearing Aid profile is connected. - */ -class BluetoothDeviceConfigListener { - private static final String TAG = "BluetoothDeviceConfigListener"; - - private final BluetoothManagerService mService; - private final boolean mLogDebug; - - BluetoothDeviceConfigListener(BluetoothManagerService service, boolean logDebug) { - mService = service; - mLogDebug = logDebug; - DeviceConfig.addOnPropertiesChangedListener( - DeviceConfig.NAMESPACE_BLUETOOTH, - (Runnable r) -> r.run(), - mDeviceConfigChangedListener); - } - - private final DeviceConfig.OnPropertiesChangedListener mDeviceConfigChangedListener = - new DeviceConfig.OnPropertiesChangedListener() { - @Override - public void onPropertiesChanged(DeviceConfig.Properties properties) { - if (!properties.getNamespace().equals(DeviceConfig.NAMESPACE_BLUETOOTH)) { - return; - } - if (mLogDebug) { - ArrayList flags = new ArrayList<>(); - for (String name : properties.getKeyset()) { - flags.add(name + "='" + properties.getString(name, "") + "'"); - } - Slog.d(TAG, "onPropertiesChanged: " + String.join(",", flags)); - } - boolean foundInit = false; - for (String name : properties.getKeyset()) { - if (name.startsWith("INIT_")) { - foundInit = true; - break; - } - } - if (!foundInit) { - return; - } - mService.onInitFlagsChanged(); - } - }; - -} diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java deleted file mode 100644 index c8b4f1109b5eaf8f1ddb0ed3e599f89387d29197..0000000000000000000000000000000000000000 --- a/services/core/java/com/android/server/BluetoothManagerService.java +++ /dev/null @@ -1,2960 +0,0 @@ -/* - * Copyright (C) 2012 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.android.server; - -import static android.Manifest.permission.BLUETOOTH_CONNECT; -import static android.content.PermissionChecker.PERMISSION_HARD_DENIED; -import static android.content.PermissionChecker.PID_UNKNOWN; -import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY; -import static android.content.pm.PackageManager.PERMISSION_GRANTED; -import static android.os.PowerExemptionManager.TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_ALLOWED; -import static android.os.UserHandle.USER_SYSTEM; - -import android.Manifest; -import android.annotation.NonNull; -import android.annotation.RequiresPermission; -import android.annotation.SuppressLint; -import android.app.ActivityManager; -import android.app.AppGlobals; -import android.app.AppOpsManager; -import android.app.BroadcastOptions; -import android.bluetooth.BluetoothA2dp; -import android.bluetooth.BluetoothAdapter; -import android.bluetooth.BluetoothHearingAid; -import android.bluetooth.BluetoothLeAudio; -import android.bluetooth.BluetoothProfile; -import android.bluetooth.BluetoothProtoEnums; -import android.bluetooth.IBluetooth; -import android.bluetooth.IBluetoothCallback; -import android.bluetooth.IBluetoothGatt; -import android.bluetooth.IBluetoothHeadset; -import android.bluetooth.IBluetoothManager; -import android.bluetooth.IBluetoothManagerCallback; -import android.bluetooth.IBluetoothProfileServiceConnection; -import android.bluetooth.IBluetoothStateChangeCallback; -import android.bluetooth.IBluetoothLeCallControl; -import android.content.ActivityNotFoundException; -import android.content.AttributionSource; -import android.content.BroadcastReceiver; -import android.content.ComponentName; -import android.content.ContentResolver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.PermissionChecker; -import android.content.ServiceConnection; -import android.content.pm.ApplicationInfo; -import android.content.pm.IPackageManager; -import android.content.pm.PackageManager; -import android.content.pm.PackageManagerInternal; -import android.content.pm.UserInfo; -import android.database.ContentObserver; -import android.os.Binder; -import android.os.Bundle; -import android.os.Handler; -import android.os.IBinder; -import android.os.Looper; -import android.os.Message; -import android.os.PowerExemptionManager; -import android.os.Process; -import android.os.RemoteCallbackList; -import android.os.RemoteException; -import android.os.SystemClock; -import android.os.SystemProperties; -import android.os.UserHandle; -import android.os.UserManager; -import android.provider.Settings; -import android.provider.Settings.SettingNotFoundException; -import android.text.TextUtils; -import android.util.FeatureFlagUtils; -import android.util.Log; -import android.util.Slog; -import android.util.proto.ProtoOutputStream; - -import com.android.internal.R; -import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.util.DumpUtils; -import com.android.internal.util.FrameworkStatsLog; -import com.android.server.pm.UserManagerInternal; -import com.android.server.pm.UserManagerInternal.UserRestrictionsListener; -import com.android.server.pm.UserRestrictionsUtils; - -import java.io.FileDescriptor; -import java.io.PrintWriter; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.Locale; -import java.util.Map; -import java.util.NoSuchElementException; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.locks.ReentrantReadWriteLock; - -class BluetoothManagerService extends IBluetoothManager.Stub { - private static final String TAG = "BluetoothManagerService"; - private static final boolean DBG = true; - - private static final String BLUETOOTH_PRIVILEGED = - android.Manifest.permission.BLUETOOTH_PRIVILEGED; - - private static final String SECURE_SETTINGS_BLUETOOTH_ADDR_VALID = "bluetooth_addr_valid"; - private static final String SECURE_SETTINGS_BLUETOOTH_ADDRESS = "bluetooth_address"; - private static final String SECURE_SETTINGS_BLUETOOTH_NAME = "bluetooth_name"; - - private static final int ACTIVE_LOG_MAX_SIZE = 20; - private static final int CRASH_LOG_MAX_SIZE = 100; - - private static final int TIMEOUT_BIND_MS = 3000; //Maximum msec to wait for a bind - //Maximum msec to wait for service restart - private static final int SERVICE_RESTART_TIME_MS = 400; - //Maximum msec to wait for restart due to error - private static final int ERROR_RESTART_TIME_MS = 3000; - //Maximum msec to delay MESSAGE_USER_SWITCHED - private static final int USER_SWITCHED_TIME_MS = 200; - // Delay for the addProxy function in msec - private static final int ADD_PROXY_DELAY_MS = 100; - // Delay for retrying enable and disable in msec - private static final int ENABLE_DISABLE_DELAY_MS = 300; - private static final int DELAY_BEFORE_RESTART_DUE_TO_INIT_FLAGS_CHANGED_MS = 300; - private static final int DELAY_FOR_RETRY_INIT_FLAG_CHECK_MS = 86400; - - private static final int MESSAGE_ENABLE = 1; - private static final int MESSAGE_DISABLE = 2; - private static final int MESSAGE_HANDLE_ENABLE_DELAYED = 3; - private static final int MESSAGE_HANDLE_DISABLE_DELAYED = 4; - private static final int MESSAGE_REGISTER_STATE_CHANGE_CALLBACK = 30; - private static final int MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK = 31; - private static final int MESSAGE_BLUETOOTH_SERVICE_CONNECTED = 40; - private static final int MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED = 41; - private static final int MESSAGE_RESTART_BLUETOOTH_SERVICE = 42; - private static final int MESSAGE_BLUETOOTH_STATE_CHANGE = 60; - private static final int MESSAGE_TIMEOUT_BIND = 100; - private static final int MESSAGE_TIMEOUT_UNBIND = 101; - private static final int MESSAGE_GET_NAME_AND_ADDRESS = 200; - private static final int MESSAGE_USER_SWITCHED = 300; - private static final int MESSAGE_USER_UNLOCKED = 301; - private static final int MESSAGE_ADD_PROXY_DELAYED = 400; - private static final int MESSAGE_BIND_PROFILE_SERVICE = 401; - private static final int MESSAGE_RESTORE_USER_SETTING = 500; - private static final int MESSAGE_INIT_FLAGS_CHANGED = 600; - - private static final int RESTORE_SETTING_TO_ON = 1; - private static final int RESTORE_SETTING_TO_OFF = 0; - - private static final int MAX_ERROR_RESTART_RETRIES = 6; - private static final int MAX_WAIT_FOR_ENABLE_DISABLE_RETRIES = 10; - - // Bluetooth persisted setting is off - private static final int BLUETOOTH_OFF = 0; - // Bluetooth persisted setting is on - // and Airplane mode won't affect Bluetooth state at start up - private static final int BLUETOOTH_ON_BLUETOOTH = 1; - // Bluetooth persisted setting is on - // but Airplane mode will affect Bluetooth state at start up - // and Airplane mode will have higher priority. - @VisibleForTesting - static final int BLUETOOTH_ON_AIRPLANE = 2; - - private static final int SERVICE_IBLUETOOTH = 1; - private static final int SERVICE_IBLUETOOTHGATT = 2; - - private final Context mContext; - - // Locks are not provided for mName and mAddress. - // They are accessed in handler or broadcast receiver, same thread context. - private String mAddress; - private String mName; - private final ContentResolver mContentResolver; - private final int mUserId; - private final RemoteCallbackList mCallbacks; - private final RemoteCallbackList mStateChangeCallbacks; - private IBinder mBluetoothBinder; - private IBluetooth mBluetooth; - private IBluetoothGatt mBluetoothGatt; - private final ReentrantReadWriteLock mBluetoothLock = new ReentrantReadWriteLock(); - private boolean mBinding; - private boolean mUnbinding; - - private BluetoothModeChangeHelper mBluetoothModeChangeHelper; - - private BluetoothAirplaneModeListener mBluetoothAirplaneModeListener; - - private BluetoothDeviceConfigListener mBluetoothDeviceConfigListener; - - // used inside handler thread - private boolean mQuietEnable = false; - private boolean mEnable; - - private static CharSequence timeToLog(long timestamp) { - return android.text.format.DateFormat.format("MM-dd HH:mm:ss", timestamp); - } - - /** - * Used for tracking apps that enabled / disabled Bluetooth. - */ - private class ActiveLog { - private int mReason; - private String mPackageName; - private boolean mEnable; - private long mTimestamp; - - ActiveLog(int reason, String packageName, boolean enable, long timestamp) { - mReason = reason; - mPackageName = packageName; - mEnable = enable; - mTimestamp = timestamp; - } - - public String toString() { - return timeToLog(mTimestamp) + (mEnable ? " Enabled " : " Disabled ") - + " due to " + getEnableDisableReasonString(mReason) + " by " + mPackageName; - } - - void dump(ProtoOutputStream proto) { - proto.write(BluetoothManagerServiceDumpProto.ActiveLog.TIMESTAMP_MS, mTimestamp); - proto.write(BluetoothManagerServiceDumpProto.ActiveLog.ENABLE, mEnable); - proto.write(BluetoothManagerServiceDumpProto.ActiveLog.PACKAGE_NAME, mPackageName); - proto.write(BluetoothManagerServiceDumpProto.ActiveLog.REASON, mReason); - } - } - - private final LinkedList mActiveLogs = new LinkedList<>(); - private final LinkedList mCrashTimestamps = new LinkedList<>(); - private int mCrashes; - private long mLastEnabledTime; - - // configuration from external IBinder call which is used to - // synchronize with broadcast receiver. - private boolean mQuietEnableExternal; - private boolean mEnableExternal; - - // Map of apps registered to keep BLE scanning on. - private Map mBleApps = - new ConcurrentHashMap(); - - private int mState; - private final BluetoothHandler mHandler; - private int mErrorRecoveryRetryCounter; - private final int mSystemUiUid; - - private boolean mIsHearingAidProfileSupported; - - private AppOpsManager mAppOps; - - // Save a ProfileServiceConnections object for each of the bound - // bluetooth profile services - private final Map mProfileServices = new HashMap<>(); - - private final boolean mWirelessConsentRequired; - - private final IBluetoothCallback mBluetoothCallback = new IBluetoothCallback.Stub() { - @Override - public void onBluetoothStateChange(int prevState, int newState) throws RemoteException { - Message msg = - mHandler.obtainMessage(MESSAGE_BLUETOOTH_STATE_CHANGE, prevState, newState); - mHandler.sendMessage(msg); - } - }; - - private final UserRestrictionsListener mUserRestrictionsListener = - new UserRestrictionsListener() { - @Override - public void onUserRestrictionsChanged(int userId, Bundle newRestrictions, - Bundle prevRestrictions) { - - if (UserRestrictionsUtils.restrictionsChanged(prevRestrictions, newRestrictions, - UserManager.DISALLOW_BLUETOOTH_SHARING)) { - updateOppLauncherComponentState(userId, - newRestrictions.getBoolean(UserManager.DISALLOW_BLUETOOTH_SHARING)); - } - - // DISALLOW_BLUETOOTH can only be set by DO or PO on the system user. - if (userId == USER_SYSTEM - && UserRestrictionsUtils.restrictionsChanged(prevRestrictions, - newRestrictions, UserManager.DISALLOW_BLUETOOTH)) { - if (userId == USER_SYSTEM && newRestrictions.getBoolean( - UserManager.DISALLOW_BLUETOOTH)) { - updateOppLauncherComponentState(userId, true); // Sharing disallowed - sendDisableMsg(BluetoothProtoEnums.ENABLE_DISABLE_REASON_DISALLOWED, - mContext.getPackageName()); - } else { - updateOppLauncherComponentState(userId, newRestrictions.getBoolean( - UserManager.DISALLOW_BLUETOOTH_SHARING)); - } - } - } - }; - - @VisibleForTesting - public void onInitFlagsChanged() { - mHandler.removeMessages(MESSAGE_INIT_FLAGS_CHANGED); - mHandler.sendEmptyMessageDelayed( - MESSAGE_INIT_FLAGS_CHANGED, - DELAY_BEFORE_RESTART_DUE_TO_INIT_FLAGS_CHANGED_MS); - } - - public boolean onFactoryReset(AttributionSource attributionSource) { - mContext.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, - "Need BLUETOOTH_PRIVILEGED permission"); - - // Wait for stable state if bluetooth is temporary state. - int state = getState(); - if (state == BluetoothAdapter.STATE_BLE_TURNING_ON - || state == BluetoothAdapter.STATE_TURNING_ON - || state == BluetoothAdapter.STATE_TURNING_OFF) { - if (!waitForState(Set.of(BluetoothAdapter.STATE_BLE_ON, BluetoothAdapter.STATE_ON))) { - return false; - } - } - - // Clear registered LE apps to force shut-off Bluetooth - clearBleApps(); - state = getState(); - try { - mBluetoothLock.readLock().lock(); - if (mBluetooth == null) { - return false; - } - if (state == BluetoothAdapter.STATE_BLE_ON) { - addActiveLog( - BluetoothProtoEnums.ENABLE_DISABLE_REASON_FACTORY_RESET, - mContext.getPackageName(), false); - mBluetooth.onBrEdrDown(attributionSource); - return true; - } else if (state == BluetoothAdapter.STATE_ON) { - addActiveLog( - BluetoothProtoEnums.ENABLE_DISABLE_REASON_FACTORY_RESET, - mContext.getPackageName(), false); - mBluetooth.disable(attributionSource); - return true; - } - } catch (RemoteException e) { - Slog.e(TAG, "Unable to shutdown Bluetooth", e); - } finally { - mBluetoothLock.readLock().unlock(); - } - return false; - } - - @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) - public void onAirplaneModeChanged() { - synchronized (this) { - if (isBluetoothPersistedStateOn()) { - if (isAirplaneModeOn()) { - persistBluetoothSetting(BLUETOOTH_ON_AIRPLANE); - } else { - persistBluetoothSetting(BLUETOOTH_ON_BLUETOOTH); - } - } - - int st = BluetoothAdapter.STATE_OFF; - try { - mBluetoothLock.readLock().lock(); - if (mBluetooth != null) { - st = mBluetooth.getState(); - } - } catch (RemoteException e) { - Slog.e(TAG, "Unable to call getState", e); - return; - } finally { - mBluetoothLock.readLock().unlock(); - } - - Slog.d(TAG, - "Airplane Mode change - current state: " + BluetoothAdapter.nameForState( - st) + ", isAirplaneModeOn()=" + isAirplaneModeOn()); - - if (isAirplaneModeOn()) { - // Clear registered LE apps to force shut-off - clearBleApps(); - - // If state is BLE_ON make sure we trigger disableBLE - if (st == BluetoothAdapter.STATE_BLE_ON) { - try { - mBluetoothLock.readLock().lock(); - if (mBluetooth != null) { - addActiveLog( - BluetoothProtoEnums.ENABLE_DISABLE_REASON_AIRPLANE_MODE, - mContext.getPackageName(), false); - mBluetooth.onBrEdrDown(mContext.getAttributionSource()); - mEnable = false; - mEnableExternal = false; - } - } catch (RemoteException e) { - Slog.e(TAG, "Unable to call onBrEdrDown", e); - } finally { - mBluetoothLock.readLock().unlock(); - } - } else if (st == BluetoothAdapter.STATE_ON) { - sendDisableMsg(BluetoothProtoEnums.ENABLE_DISABLE_REASON_AIRPLANE_MODE, - mContext.getPackageName()); - } - } else if (mEnableExternal) { - sendEnableMsg(mQuietEnableExternal, - BluetoothProtoEnums.ENABLE_DISABLE_REASON_AIRPLANE_MODE, - mContext.getPackageName()); - } - } - } - - private final BroadcastReceiver mReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - String action = intent.getAction(); - if (BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED.equals(action)) { - String newName = intent.getStringExtra(BluetoothAdapter.EXTRA_LOCAL_NAME); - if (DBG) { - Slog.d(TAG, "Bluetooth Adapter name changed to " + newName + " by " - + mContext.getPackageName()); - } - if (newName != null) { - storeNameAndAddress(newName, null); - } - } else if (BluetoothAdapter.ACTION_BLUETOOTH_ADDRESS_CHANGED.equals(action)) { - String newAddress = intent.getStringExtra(BluetoothAdapter.EXTRA_BLUETOOTH_ADDRESS); - if (newAddress != null) { - if (DBG) { - Slog.d(TAG, "Bluetooth Adapter address changed to " + newAddress); - } - storeNameAndAddress(null, newAddress); - } else { - if (DBG) { - Slog.e(TAG, "No Bluetooth Adapter address parameter found"); - } - } - } else if (Intent.ACTION_SETTING_RESTORED.equals(action)) { - final String name = intent.getStringExtra(Intent.EXTRA_SETTING_NAME); - if (Settings.Global.BLUETOOTH_ON.equals(name)) { - // The Bluetooth On state may be changed during system restore. - final String prevValue = - intent.getStringExtra(Intent.EXTRA_SETTING_PREVIOUS_VALUE); - final String newValue = intent.getStringExtra(Intent.EXTRA_SETTING_NEW_VALUE); - - if (DBG) { - Slog.d(TAG, - "ACTION_SETTING_RESTORED with BLUETOOTH_ON, prevValue=" + prevValue - + ", newValue=" + newValue); - } - - if ((newValue != null) && (prevValue != null) && !prevValue.equals(newValue)) { - Message msg = mHandler.obtainMessage(MESSAGE_RESTORE_USER_SETTING, - newValue.equals("0") ? RESTORE_SETTING_TO_OFF - : RESTORE_SETTING_TO_ON, 0); - mHandler.sendMessage(msg); - } - } - } else if (BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED.equals(action) - || BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED.equals(action) - || BluetoothLeAudio.ACTION_LE_AUDIO_CONNECTION_STATE_CHANGED.equals(action)) { - final int state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, - BluetoothProfile.STATE_CONNECTED); - if (mHandler.hasMessages(MESSAGE_INIT_FLAGS_CHANGED) - && state == BluetoothProfile.STATE_DISCONNECTED - && !mBluetoothModeChangeHelper.isMediaProfileConnected()) { - Slog.i(TAG, "Device disconnected, reactivating pending flag changes"); - onInitFlagsChanged(); - } - } - } - }; - - BluetoothManagerService(Context context) { - mHandler = new BluetoothHandler(IoThread.get().getLooper()); - - mContext = context; - - mWirelessConsentRequired = context.getResources() - .getBoolean(com.android.internal.R.bool.config_wirelessConsentRequired); - - mCrashes = 0; - mBluetooth = null; - mBluetoothBinder = null; - mBluetoothGatt = null; - mBinding = false; - mUnbinding = false; - mEnable = false; - mState = BluetoothAdapter.STATE_OFF; - mQuietEnableExternal = false; - mEnableExternal = false; - mAddress = null; - mName = null; - mErrorRecoveryRetryCounter = 0; - mContentResolver = context.getContentResolver(); - mUserId = mContentResolver.getUserId(); - // Observe BLE scan only mode settings change. - registerForBleScanModeChange(); - mCallbacks = new RemoteCallbackList(); - mStateChangeCallbacks = new RemoteCallbackList(); - - mIsHearingAidProfileSupported = context.getResources() - .getBoolean(com.android.internal.R.bool.config_hearing_aid_profile_supported); - - // TODO: We need a more generic way to initialize the persist keys of FeatureFlagUtils - String value = SystemProperties.get(FeatureFlagUtils.PERSIST_PREFIX + FeatureFlagUtils.HEARING_AID_SETTINGS); - if (!TextUtils.isEmpty(value)) { - boolean isHearingAidEnabled = Boolean.parseBoolean(value); - Log.v(TAG, "set feature flag HEARING_AID_SETTINGS to " + isHearingAidEnabled); - FeatureFlagUtils.setEnabled(context, FeatureFlagUtils.HEARING_AID_SETTINGS, isHearingAidEnabled); - if (isHearingAidEnabled && !mIsHearingAidProfileSupported) { - // Overwrite to enable support by FeatureFlag - mIsHearingAidProfileSupported = true; - } - } - - IntentFilter filter = new IntentFilter(); - filter.addAction(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED); - filter.addAction(BluetoothAdapter.ACTION_BLUETOOTH_ADDRESS_CHANGED); - filter.addAction(Intent.ACTION_SETTING_RESTORED); - filter.addAction(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED); - filter.addAction(BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED); - filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY); - mContext.registerReceiver(mReceiver, filter); - - loadStoredNameAndAddress(); - if (isBluetoothPersistedStateOn()) { - if (DBG) { - Slog.d(TAG, "Startup: Bluetooth persisted state is ON."); - } - mEnableExternal = true; - } - - String airplaneModeRadios = - Settings.Global.getString(mContentResolver, Settings.Global.AIRPLANE_MODE_RADIOS); - if (airplaneModeRadios == null || airplaneModeRadios.contains( - Settings.Global.RADIO_BLUETOOTH)) { - mBluetoothAirplaneModeListener = new BluetoothAirplaneModeListener( - this, IoThread.get().getLooper(), context); - } - - int systemUiUid = -1; - // Check if device is configured with no home screen, which implies no SystemUI. - boolean noHome = mContext.getResources().getBoolean(R.bool.config_noHomeScreen); - if (!noHome) { - PackageManagerInternal pm = LocalServices.getService(PackageManagerInternal.class); - systemUiUid = pm.getPackageUid(pm.getSystemUiServiceComponent().getPackageName(), - MATCH_SYSTEM_ONLY, USER_SYSTEM); - } - if (systemUiUid >= 0) { - Slog.d(TAG, "Detected SystemUiUid: " + Integer.toString(systemUiUid)); - } else { - // Some platforms, such as wearables do not have a system ui. - Slog.w(TAG, "Unable to resolve SystemUI's UID."); - } - mSystemUiUid = systemUiUid; - } - - /** - * Returns true if airplane mode is currently on - */ - private boolean isAirplaneModeOn() { - return Settings.Global.getInt(mContext.getContentResolver(), - Settings.Global.AIRPLANE_MODE_ON, 0) == 1; - } - - private boolean supportBluetoothPersistedState() { - return mContext.getResources().getBoolean(R.bool.config_supportBluetoothPersistedState); - } - - /** - * Returns true if the Bluetooth saved state is "on" - */ - private boolean isBluetoothPersistedStateOn() { - if (!supportBluetoothPersistedState()) { - return false; - } - int state = Settings.Global.getInt(mContentResolver, Settings.Global.BLUETOOTH_ON, -1); - if (DBG) { - Slog.d(TAG, "Bluetooth persisted state: " + state); - } - return state != BLUETOOTH_OFF; - } - - private boolean isBluetoothPersistedStateOnAirplane() { - if (!supportBluetoothPersistedState()) { - return false; - } - int state = Settings.Global.getInt(mContentResolver, Settings.Global.BLUETOOTH_ON, -1); - if (DBG) { - Slog.d(TAG, "Bluetooth persisted state: " + state); - } - return state == BLUETOOTH_ON_AIRPLANE; - } - - /** - * Returns true if the Bluetooth saved state is BLUETOOTH_ON_BLUETOOTH - */ - private boolean isBluetoothPersistedStateOnBluetooth() { - if (!supportBluetoothPersistedState()) { - return false; - } - return Settings.Global.getInt(mContentResolver, Settings.Global.BLUETOOTH_ON, - BLUETOOTH_ON_BLUETOOTH) == BLUETOOTH_ON_BLUETOOTH; - } - - /** - * Save the Bluetooth on/off state - */ - private void persistBluetoothSetting(int value) { - if (DBG) { - Slog.d(TAG, "Persisting Bluetooth Setting: " + value); - } - // waive WRITE_SECURE_SETTINGS permission check - final long callingIdentity = Binder.clearCallingIdentity(); - try { - Settings.Global.putInt(mContext.getContentResolver(), - Settings.Global.BLUETOOTH_ON, value); - } finally { - Binder.restoreCallingIdentity(callingIdentity); - } - } - - /** - * Returns true if the Bluetooth Adapter's name and address is - * locally cached - * @return - */ - private boolean isNameAndAddressSet() { - return mName != null && mAddress != null && mName.length() > 0 && mAddress.length() > 0; - } - - /** - * Retrieve the Bluetooth Adapter's name and address and save it in - * in the local cache - */ - private void loadStoredNameAndAddress() { - if (DBG) { - Slog.d(TAG, "Loading stored name and address"); - } - if (mContext.getResources() - .getBoolean(com.android.internal.R.bool.config_bluetooth_address_validation) - && Settings.Secure.getIntForUser(mContentResolver, - SECURE_SETTINGS_BLUETOOTH_ADDR_VALID, 0, mUserId) - == 0) { - // if the valid flag is not set, don't load the address and name - if (DBG) { - Slog.d(TAG, "invalid bluetooth name and address stored"); - } - return; - } - mName = Settings.Secure.getStringForUser( - mContentResolver, SECURE_SETTINGS_BLUETOOTH_NAME, mUserId); - mAddress = Settings.Secure.getStringForUser( - mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDRESS, mUserId); - if (DBG) { - Slog.d(TAG, "Stored bluetooth Name=" + mName + ",Address=" + mAddress); - } - } - - /** - * Save the Bluetooth name and address in the persistent store. - * Only non-null values will be saved. - * @param name - * @param address - */ - private void storeNameAndAddress(String name, String address) { - if (name != null) { - Settings.Secure.putStringForUser(mContentResolver, SECURE_SETTINGS_BLUETOOTH_NAME, name, - mUserId); - mName = name; - if (DBG) { - Slog.d(TAG, "Stored Bluetooth name: " + Settings.Secure.getStringForUser( - mContentResolver, SECURE_SETTINGS_BLUETOOTH_NAME, - mUserId)); - } - } - - if (address != null) { - Settings.Secure.putStringForUser(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDRESS, - address, mUserId); - mAddress = address; - if (DBG) { - Slog.d(TAG, - "Stored Bluetoothaddress: " + Settings.Secure.getStringForUser( - mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDRESS, - mUserId)); - } - } - - if ((name != null) && (address != null)) { - Settings.Secure.putIntForUser(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDR_VALID, 1, - mUserId); - } - } - - public IBluetooth registerAdapter(IBluetoothManagerCallback callback) { - if (callback == null) { - Slog.w(TAG, "Callback is null in registerAdapter"); - return null; - } - synchronized (mCallbacks) { - mCallbacks.register(callback); - } - return mBluetooth; - } - - public void unregisterAdapter(IBluetoothManagerCallback callback) { - if (callback == null) { - Slog.w(TAG, "Callback is null in unregisterAdapter"); - return; - } - synchronized (mCallbacks) { - mCallbacks.unregister(callback); - } - } - - public void registerStateChangeCallback(IBluetoothStateChangeCallback callback) { - if (callback == null) { - Slog.w(TAG, "registerStateChangeCallback: Callback is null!"); - return; - } - Message msg = mHandler.obtainMessage(MESSAGE_REGISTER_STATE_CHANGE_CALLBACK); - msg.obj = callback; - mHandler.sendMessage(msg); - } - - public void unregisterStateChangeCallback(IBluetoothStateChangeCallback callback) { - if (callback == null) { - Slog.w(TAG, "unregisterStateChangeCallback: Callback is null!"); - return; - } - Message msg = mHandler.obtainMessage(MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK); - msg.obj = callback; - mHandler.sendMessage(msg); - } - - public boolean isEnabled() { - return getState() == BluetoothAdapter.STATE_ON; - } - - public int getState() { - if ((Binder.getCallingUid() != Process.SYSTEM_UID) && (!checkIfCallerIsForegroundUser())) { - Slog.w(TAG, "getState(): report OFF for non-active and non system user"); - return BluetoothAdapter.STATE_OFF; - } - - try { - mBluetoothLock.readLock().lock(); - if (mBluetooth != null) { - return mBluetooth.getState(); - } - } catch (RemoteException e) { - Slog.e(TAG, "getState()", e); - } finally { - mBluetoothLock.readLock().unlock(); - } - return BluetoothAdapter.STATE_OFF; - } - - class ClientDeathRecipient implements IBinder.DeathRecipient { - private String mPackageName; - - ClientDeathRecipient(String packageName) { - mPackageName = packageName; - } - - public void binderDied() { - if (DBG) { - Slog.d(TAG, "Binder is dead - unregister " + mPackageName); - } - - for (Map.Entry entry : mBleApps.entrySet()) { - IBinder token = entry.getKey(); - ClientDeathRecipient deathRec = entry.getValue(); - if (deathRec.equals(this)) { - updateBleAppCount(token, false, mPackageName); - break; - } - } - } - - public String getPackageName() { - return mPackageName; - } - } - - @Override - public boolean isBleScanAlwaysAvailable() { - if (isAirplaneModeOn() && !mEnable) { - return false; - } - try { - return Settings.Global.getInt(mContentResolver, - Settings.Global.BLE_SCAN_ALWAYS_AVAILABLE) != 0; - } catch (SettingNotFoundException e) { - } - return false; - } - - @Override - public boolean isHearingAidProfileSupported() { - return mIsHearingAidProfileSupported; - } - - private boolean isDeviceProvisioned() { - return Settings.Global.getInt(mContentResolver, Settings.Global.DEVICE_PROVISIONED, - 0) != 0; - } - - // Monitor change of BLE scan only mode settings. - private void registerForProvisioningStateChange() { - ContentObserver contentObserver = new ContentObserver(null) { - @Override - public void onChange(boolean selfChange) { - if (!isDeviceProvisioned()) { - if (DBG) { - Slog.d(TAG, "DEVICE_PROVISIONED setting changed, but device is not " - + "provisioned"); - } - return; - } - if (mHandler.hasMessages(MESSAGE_INIT_FLAGS_CHANGED)) { - Slog.i(TAG, "Device provisioned, reactivating pending flag changes"); - onInitFlagsChanged(); - } - } - }; - - mContentResolver.registerContentObserver( - Settings.Global.getUriFor(Settings.Global.DEVICE_PROVISIONED), false, - contentObserver); - } - - // Monitor change of BLE scan only mode settings. - private void registerForBleScanModeChange() { - ContentObserver contentObserver = new ContentObserver(null) { - @Override - public void onChange(boolean selfChange) { - if (isBleScanAlwaysAvailable()) { - // Nothing to do - return; - } - // BLE scan is not available. - disableBleScanMode(); - clearBleApps(); - try { - mBluetoothLock.readLock().lock(); - if (mBluetooth != null) { - addActiveLog(BluetoothProtoEnums.ENABLE_DISABLE_REASON_APPLICATION_REQUEST, - mContext.getPackageName(), false); - mBluetooth.onBrEdrDown(mContext.getAttributionSource()); - } - } catch (RemoteException e) { - Slog.e(TAG, "error when disabling bluetooth", e); - } finally { - mBluetoothLock.readLock().unlock(); - } - } - }; - - mContentResolver.registerContentObserver( - Settings.Global.getUriFor(Settings.Global.BLE_SCAN_ALWAYS_AVAILABLE), false, - contentObserver); - } - - // Disable ble scan only mode. - private void disableBleScanMode() { - try { - mBluetoothLock.writeLock().lock(); - if (mBluetooth != null && (mBluetooth.getState() != BluetoothAdapter.STATE_ON)) { - if (DBG) { - Slog.d(TAG, "Reseting the mEnable flag for clean disable"); - } - mEnable = false; - } - } catch (RemoteException e) { - Slog.e(TAG, "getState()", e); - } finally { - mBluetoothLock.writeLock().unlock(); - } - } - - private int updateBleAppCount(IBinder token, boolean enable, String packageName) { - ClientDeathRecipient r = mBleApps.get(token); - if (r == null && enable) { - ClientDeathRecipient deathRec = new ClientDeathRecipient(packageName); - try { - token.linkToDeath(deathRec, 0); - } catch (RemoteException ex) { - throw new IllegalArgumentException("BLE app (" + packageName + ") already dead!"); - } - mBleApps.put(token, deathRec); - if (DBG) { - Slog.d(TAG, "Registered for death of " + packageName); - } - } else if (!enable && r != null) { - // Unregister death recipient as the app goes away. - token.unlinkToDeath(r, 0); - mBleApps.remove(token); - if (DBG) { - Slog.d(TAG, "Unregistered for death of " + packageName); - } - } - int appCount = mBleApps.size(); - if (DBG) { - Slog.d(TAG, appCount + " registered Ble Apps"); - } - return appCount; - } - - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - private boolean checkBluetoothPermissions(AttributionSource attributionSource, String message, - boolean requireForeground) { - if (isBluetoothDisallowed()) { - if (DBG) { - Slog.d(TAG, "checkBluetoothPermissions: bluetooth disallowed"); - } - return false; - } - // Check if packageName belongs to callingUid - final int callingUid = Binder.getCallingUid(); - final boolean isCallerSystem = UserHandle.getAppId(callingUid) == Process.SYSTEM_UID; - if (!isCallerSystem) { - checkPackage(callingUid, attributionSource.getPackageName()); - - if (requireForeground && !checkIfCallerIsForegroundUser()) { - Slog.w(TAG, "Not allowed for non-active and non system user"); - return false; - } - - if (!checkConnectPermissionForDataDelivery(mContext, attributionSource, message)) { - return false; - } - } - return true; - } - - public boolean enableBle(AttributionSource attributionSource, IBinder token) - throws RemoteException { - final String packageName = attributionSource.getPackageName(); - if (!checkBluetoothPermissions(attributionSource, "enableBle", false)) { - if (DBG) { - Slog.d(TAG, "enableBle(): bluetooth disallowed"); - } - return false; - } - - if (DBG) { - Slog.d(TAG, "enableBle(" + packageName + "): mBluetooth =" + mBluetooth - + " mBinding = " + mBinding + " mState = " - + BluetoothAdapter.nameForState(mState)); - } - updateBleAppCount(token, true, packageName); - - if (mState == BluetoothAdapter.STATE_ON - || mState == BluetoothAdapter.STATE_BLE_ON - || mState == BluetoothAdapter.STATE_TURNING_ON - || mState == BluetoothAdapter.STATE_TURNING_OFF - || mState == BluetoothAdapter.STATE_BLE_TURNING_ON) { - Log.d(TAG, "enableBLE(): Bluetooth is already enabled or is turning on"); - return true; - } - synchronized (mReceiver) { - // waive WRITE_SECURE_SETTINGS permission check - sendEnableMsg(false, BluetoothProtoEnums.ENABLE_DISABLE_REASON_APPLICATION_REQUEST, - packageName, true); - } - return true; - } - - @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) - public boolean disableBle(AttributionSource attributionSource, IBinder token) - throws RemoteException { - final String packageName = attributionSource.getPackageName(); - if (!checkBluetoothPermissions(attributionSource, "disableBle", false)) { - if (DBG) { - Slog.d(TAG, "disableBLE(): bluetooth disallowed"); - } - return false; - } - - if (DBG) { - Slog.d(TAG, "disableBle(" + packageName + "): mBluetooth =" + mBluetooth - + " mBinding = " + mBinding + " mState = " - + BluetoothAdapter.nameForState(mState)); - } - - if (mState == BluetoothAdapter.STATE_OFF) { - Slog.d(TAG, "disableBLE(): Already disabled"); - return false; - } - updateBleAppCount(token, false, packageName); - - if (mState == BluetoothAdapter.STATE_BLE_ON && !isBleAppPresent()) { - if (mEnable) { - disableBleScanMode(); - } - if (!mEnableExternal) { - addActiveLog(BluetoothProtoEnums.ENABLE_DISABLE_REASON_APPLICATION_REQUEST, - packageName, false); - sendBrEdrDownCallback(attributionSource); - } - } - return true; - } - - // Clear all apps using BLE scan only mode. - private void clearBleApps() { - mBleApps.clear(); - } - - /** @hide */ - public boolean isBleAppPresent() { - if (DBG) { - Slog.d(TAG, "isBleAppPresent() count: " + mBleApps.size()); - } - return mBleApps.size() > 0; - } - - /** - * Call IBluetooth.onLeServiceUp() to continue if Bluetooth should be on, - * call IBluetooth.onBrEdrDown() to disable if Bluetooth should be off. - */ - @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) - private void continueFromBleOnState() { - if (DBG) { - Slog.d(TAG, "continueFromBleOnState()"); - } - try { - mBluetoothLock.readLock().lock(); - if (mBluetooth == null) { - Slog.e(TAG, "onBluetoothServiceUp: mBluetooth is null!"); - return; - } - if (!mEnableExternal && !isBleAppPresent()) { - Slog.i(TAG, "Bluetooth was disabled while enabling BLE, disable BLE now"); - mEnable = false; - mBluetooth.onBrEdrDown(mContext.getAttributionSource()); - return; - } - if (isBluetoothPersistedStateOnBluetooth() || !isBleAppPresent()) { - // This triggers transition to STATE_ON - mBluetooth.onLeServiceUp(mContext.getAttributionSource()); - persistBluetoothSetting(BLUETOOTH_ON_BLUETOOTH); - } - } catch (RemoteException e) { - Slog.e(TAG, "Unable to call onServiceUp", e); - } finally { - mBluetoothLock.readLock().unlock(); - } - } - - /** - * Inform BluetoothAdapter instances that BREDR part is down - * and turn off all service and stack if no LE app needs it - */ - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) - private void sendBrEdrDownCallback(AttributionSource attributionSource) { - if (DBG) { - Slog.d(TAG, "Calling sendBrEdrDownCallback callbacks"); - } - - if (mBluetooth == null) { - Slog.w(TAG, "Bluetooth handle is null"); - return; - } - - if (isBleAppPresent()) { - // Need to stay at BLE ON. Disconnect all Gatt connections - try { - mBluetoothGatt.unregAll(attributionSource); - } catch (RemoteException e) { - Slog.e(TAG, "Unable to disconnect all apps.", e); - } - } else { - try { - mBluetoothLock.readLock().lock(); - if (mBluetooth != null) { - mBluetooth.onBrEdrDown(attributionSource); - } - } catch (RemoteException e) { - Slog.e(TAG, "Call to onBrEdrDown() failed.", e); - } finally { - mBluetoothLock.readLock().unlock(); - } - } - - } - - public boolean enableNoAutoConnect(AttributionSource attributionSource) { - final String packageName = attributionSource.getPackageName(); - if (!checkBluetoothPermissions(attributionSource, "enableNoAutoConnect", false)) { - if (DBG) { - Slog.d(TAG, "enableNoAutoConnect(): not enabling - bluetooth disallowed"); - } - return false; - } - - if (DBG) { - Slog.d(TAG, "enableNoAutoConnect(): mBluetooth =" + mBluetooth + " mBinding = " - + mBinding); - } - - int callingAppId = UserHandle.getAppId(Binder.getCallingUid()); - if (callingAppId != Process.NFC_UID) { - throw new SecurityException("no permission to enable Bluetooth quietly"); - } - - synchronized (mReceiver) { - mQuietEnableExternal = true; - mEnableExternal = true; - sendEnableMsg(true, - BluetoothProtoEnums.ENABLE_DISABLE_REASON_APPLICATION_REQUEST, packageName); - } - return true; - } - - public boolean enable(AttributionSource attributionSource) throws RemoteException { - final String packageName = attributionSource.getPackageName(); - if (!checkBluetoothPermissions(attributionSource, "enable", true)) { - if (DBG) { - Slog.d(TAG, "enable(): not enabling - bluetooth disallowed"); - } - return false; - } - - final int callingUid = Binder.getCallingUid(); - final boolean callerSystem = UserHandle.getAppId(callingUid) == Process.SYSTEM_UID; - if (!callerSystem && !isEnabled() && mWirelessConsentRequired - && startConsentUiIfNeeded(packageName, - callingUid, BluetoothAdapter.ACTION_REQUEST_ENABLE)) { - return false; - } - - if (DBG) { - Slog.d(TAG, "enable(" + packageName + "): mBluetooth =" + mBluetooth + " mBinding = " - + mBinding + " mState = " + BluetoothAdapter.nameForState(mState)); - } - - synchronized (mReceiver) { - mQuietEnableExternal = false; - mEnableExternal = true; - // waive WRITE_SECURE_SETTINGS permission check - sendEnableMsg(false, - BluetoothProtoEnums.ENABLE_DISABLE_REASON_APPLICATION_REQUEST, packageName); - } - if (DBG) { - Slog.d(TAG, "enable returning"); - } - return true; - } - - public boolean disable(AttributionSource attributionSource, boolean persist) - throws RemoteException { - if (!persist) { - mContext.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, - "Need BLUETOOTH_PRIVILEGED permission"); - } - - final String packageName = attributionSource.getPackageName(); - if (!checkBluetoothPermissions(attributionSource, "disable", true)) { - if (DBG) { - Slog.d(TAG, "disable(): not disabling - bluetooth disallowed"); - } - return false; - } - - final int callingUid = Binder.getCallingUid(); - final boolean callerSystem = UserHandle.getAppId(callingUid) == Process.SYSTEM_UID; - if (!callerSystem && isEnabled() && mWirelessConsentRequired - && startConsentUiIfNeeded(packageName, - callingUid, BluetoothAdapter.ACTION_REQUEST_DISABLE)) { - return false; - } - - if (DBG) { - Slog.d(TAG, "disable(): mBluetooth = " + mBluetooth + " mBinding = " + mBinding); - } - - synchronized (mReceiver) { - if (!isBluetoothPersistedStateOnAirplane()) { - if (persist) { - persistBluetoothSetting(BLUETOOTH_OFF); - } - mEnableExternal = false; - } - sendDisableMsg(BluetoothProtoEnums.ENABLE_DISABLE_REASON_APPLICATION_REQUEST, - packageName); - } - return true; - } - - private boolean startConsentUiIfNeeded(String packageName, - int callingUid, String intentAction) throws RemoteException { - if (checkBluetoothPermissionWhenWirelessConsentRequired()) { - return false; - } - try { - // Validate the package only if we are going to use it - ApplicationInfo applicationInfo = mContext.getPackageManager() - .getApplicationInfoAsUser(packageName, - PackageManager.MATCH_DEBUG_TRIAGED_MISSING, - UserHandle.getUserId(callingUid)); - if (applicationInfo.uid != callingUid) { - throw new SecurityException("Package " + packageName - + " not in uid " + callingUid); - } - - Intent intent = new Intent(intentAction); - intent.putExtra(Intent.EXTRA_PACKAGE_NAME, packageName); - intent.setFlags( - Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); - try { - mContext.startActivity(intent); - } catch (ActivityNotFoundException e) { - // Shouldn't happen - Slog.e(TAG, "Intent to handle action " + intentAction + " missing"); - return false; - } - return true; - } catch (PackageManager.NameNotFoundException e) { - throw new RemoteException(e.getMessage()); - } - } - - /** - * Check if AppOpsManager is available and the packageName belongs to uid - * - * A null package belongs to any uid - */ - private void checkPackage(int uid, String packageName) { - if (mAppOps == null) { - Slog.w(TAG, "checkPackage(): called before system boot up, uid " - + uid + ", packageName " + packageName); - throw new IllegalStateException("System has not boot yet"); - } - if (packageName == null) { - Slog.w(TAG, "checkPackage(): called with null packageName from " + uid); - return; - } - try { - mAppOps.checkPackage(uid, packageName); - } catch (SecurityException e) { - Slog.w(TAG, "checkPackage(): " + packageName + " does not belong to uid " + uid); - throw new SecurityException(e.getMessage()); - } - } - - /** - * Check if the caller must still pass permission check or if the caller is exempted - * from the consent UI via the MANAGE_BLUETOOTH_WHEN_WIRELESS_CONSENT_REQUIRED check. - * - * Commands from some callers may be exempted from triggering the consent UI when - * enabling bluetooth. This exemption is checked via the - * MANAGE_BLUETOOTH_WHEN_WIRELESS_CONSENT_REQUIRED and allows calls to skip - * the consent UI where it may otherwise be required. - * - * @hide - */ - @SuppressLint("AndroidFrameworkRequiresPermission") - private boolean checkBluetoothPermissionWhenWirelessConsentRequired() { - int result = mContext.checkCallingPermission( - android.Manifest.permission.MANAGE_BLUETOOTH_WHEN_WIRELESS_CONSENT_REQUIRED); - return result == PackageManager.PERMISSION_GRANTED; - } - - @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) - public void unbindAndFinish() { - if (DBG) { - Slog.d(TAG, "unbindAndFinish(): " + mBluetooth + " mBinding = " + mBinding - + " mUnbinding = " + mUnbinding); - } - - try { - mBluetoothLock.writeLock().lock(); - if (mUnbinding) { - return; - } - mUnbinding = true; - mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE); - mHandler.removeMessages(MESSAGE_BIND_PROFILE_SERVICE); - if (mBluetooth != null) { - //Unregister callback object - try { - mBluetooth.unregisterCallback(mBluetoothCallback, - mContext.getAttributionSource()); - } catch (RemoteException re) { - Slog.e(TAG, "Unable to unregister BluetoothCallback", re); - } - mBluetoothBinder = null; - mBluetooth = null; - mContext.unbindService(mConnection); - mUnbinding = false; - mBinding = false; - } else { - mUnbinding = false; - } - mBluetoothGatt = null; - } finally { - mBluetoothLock.writeLock().unlock(); - } - } - - public IBluetoothGatt getBluetoothGatt() { - // sync protection - return mBluetoothGatt; - } - - @Override - public boolean bindBluetoothProfileService(int bluetoothProfile, - IBluetoothProfileServiceConnection proxy) { - if (mState != BluetoothAdapter.STATE_ON) { - if (DBG) { - Slog.d(TAG, "Trying to bind to profile: " + bluetoothProfile - + ", while Bluetooth was disabled"); - } - return false; - } - synchronized (mProfileServices) { - ProfileServiceConnections psc = mProfileServices.get(new Integer(bluetoothProfile)); - if (psc == null) { - if (DBG) { - Slog.d(TAG, "Creating new ProfileServiceConnections object for" + " profile: " - + bluetoothProfile); - } - - Intent intent; - if (bluetoothProfile == BluetoothProfile.HEADSET) { - intent = new Intent(IBluetoothHeadset.class.getName()); - } else if (bluetoothProfile== BluetoothProfile.LE_CALL_CONTROL) { - intent = new Intent(IBluetoothLeCallControl.class.getName()); - } else { - return false; - } - - psc = new ProfileServiceConnections(intent); - if (!psc.bindService()) { - return false; - } - - mProfileServices.put(new Integer(bluetoothProfile), psc); - } - } - - // Introducing a delay to give the client app time to prepare - Message addProxyMsg = mHandler.obtainMessage(MESSAGE_ADD_PROXY_DELAYED); - addProxyMsg.arg1 = bluetoothProfile; - addProxyMsg.obj = proxy; - mHandler.sendMessageDelayed(addProxyMsg, ADD_PROXY_DELAY_MS); - return true; - } - - @Override - public void unbindBluetoothProfileService(int bluetoothProfile, - IBluetoothProfileServiceConnection proxy) { - synchronized (mProfileServices) { - Integer profile = new Integer(bluetoothProfile); - ProfileServiceConnections psc = mProfileServices.get(profile); - if (psc == null) { - return; - } - psc.removeProxy(proxy); - if (psc.isEmpty()) { - // All prxoies are disconnected, unbind with the service. - try { - mContext.unbindService(psc); - } catch (IllegalArgumentException e) { - Slog.e(TAG, "Unable to unbind service with intent: " + psc.mIntent, e); - } - mProfileServices.remove(profile); - } - } - } - - private void unbindAllBluetoothProfileServices() { - synchronized (mProfileServices) { - for (Integer i : mProfileServices.keySet()) { - ProfileServiceConnections psc = mProfileServices.get(i); - try { - mContext.unbindService(psc); - } catch (IllegalArgumentException e) { - Slog.e(TAG, "Unable to unbind service with intent: " + psc.mIntent, e); - } - psc.removeAllProxies(); - } - mProfileServices.clear(); - } - } - - /** - * Send enable message and set adapter name and address. Called when the boot phase becomes - * PHASE_SYSTEM_SERVICES_READY. - */ - public void handleOnBootPhase() { - if (DBG) { - Slog.d(TAG, "Bluetooth boot completed"); - } - mAppOps = mContext.getSystemService(AppOpsManager.class); - UserManagerInternal userManagerInternal = - LocalServices.getService(UserManagerInternal.class); - userManagerInternal.addUserRestrictionsListener(mUserRestrictionsListener); - final boolean isBluetoothDisallowed = isBluetoothDisallowed(); - if (isBluetoothDisallowed) { - return; - } - final boolean isSafeMode = mContext.getPackageManager().isSafeMode(); - if (mEnableExternal && isBluetoothPersistedStateOnBluetooth() && !isSafeMode) { - if (DBG) { - Slog.d(TAG, "Auto-enabling Bluetooth."); - } - sendEnableMsg(mQuietEnableExternal, - BluetoothProtoEnums.ENABLE_DISABLE_REASON_SYSTEM_BOOT, - mContext.getPackageName()); - } else if (!isNameAndAddressSet()) { - if (DBG) { - Slog.d(TAG, "Getting adapter name and address"); - } - Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS); - mHandler.sendMessage(getMsg); - } - - mBluetoothModeChangeHelper = new BluetoothModeChangeHelper(mContext); - if (mBluetoothAirplaneModeListener != null) { - mBluetoothAirplaneModeListener.start(mBluetoothModeChangeHelper); - } - registerForProvisioningStateChange(); - mBluetoothDeviceConfigListener = new BluetoothDeviceConfigListener(this, DBG); - } - - /** - * Called when switching to a different foreground user. - */ - public void handleOnSwitchUser(int userHandle) { - if (DBG) { - Slog.d(TAG, "User " + userHandle + " switched"); - } - mHandler.obtainMessage(MESSAGE_USER_SWITCHED, userHandle, 0).sendToTarget(); - } - - /** - * Called when user is unlocked. - */ - public void handleOnUnlockUser(int userHandle) { - if (DBG) { - Slog.d(TAG, "User " + userHandle + " unlocked"); - } - mHandler.obtainMessage(MESSAGE_USER_UNLOCKED, userHandle, 0).sendToTarget(); - } - - /** - * This class manages the clients connected to a given ProfileService - * and maintains the connection with that service. - */ - private final class ProfileServiceConnections - implements ServiceConnection, IBinder.DeathRecipient { - final RemoteCallbackList mProxies = - new RemoteCallbackList(); - IBinder mService; - ComponentName mClassName; - Intent mIntent; - boolean mInvokingProxyCallbacks = false; - - ProfileServiceConnections(Intent intent) { - mService = null; - mClassName = null; - mIntent = intent; - } - - private boolean bindService() { - int state = BluetoothAdapter.STATE_OFF; - try { - mBluetoothLock.readLock().lock(); - if (mBluetooth != null) { - state = mBluetooth.getState(); - } - } catch (RemoteException e) { - Slog.e(TAG, "Unable to call getState", e); - return false; - } finally { - mBluetoothLock.readLock().unlock(); - } - - if (state != BluetoothAdapter.STATE_ON) { - if (DBG) { - Slog.d(TAG, "Unable to bindService while Bluetooth is disabled"); - } - return false; - } - - if (mIntent != null && mService == null && doBind(mIntent, this, 0, - UserHandle.CURRENT_OR_SELF)) { - Message msg = mHandler.obtainMessage(MESSAGE_BIND_PROFILE_SERVICE); - msg.obj = this; - mHandler.sendMessageDelayed(msg, TIMEOUT_BIND_MS); - return true; - } - Slog.w(TAG, "Unable to bind with intent: " + mIntent); - return false; - } - - private void addProxy(IBluetoothProfileServiceConnection proxy) { - mProxies.register(proxy); - if (mService != null) { - try { - proxy.onServiceConnected(mClassName, mService); - } catch (RemoteException e) { - Slog.e(TAG, "Unable to connect to proxy", e); - } - } else { - if (!mHandler.hasMessages(MESSAGE_BIND_PROFILE_SERVICE, this)) { - Message msg = mHandler.obtainMessage(MESSAGE_BIND_PROFILE_SERVICE); - msg.obj = this; - mHandler.sendMessage(msg); - } - } - } - - private void removeProxy(IBluetoothProfileServiceConnection proxy) { - if (proxy != null) { - if (mProxies.unregister(proxy)) { - try { - proxy.onServiceDisconnected(mClassName); - } catch (RemoteException e) { - Slog.e(TAG, "Unable to disconnect proxy", e); - } - } - } else { - Slog.w(TAG, "Trying to remove a null proxy"); - } - } - - private void removeAllProxies() { - onServiceDisconnected(mClassName); - mProxies.kill(); - } - - private boolean isEmpty() { - return mProxies.getRegisteredCallbackCount() == 0; - } - - @Override - public void onServiceConnected(ComponentName className, IBinder service) { - // remove timeout message - mHandler.removeMessages(MESSAGE_BIND_PROFILE_SERVICE, this); - mService = service; - mClassName = className; - try { - mService.linkToDeath(this, 0); - } catch (RemoteException e) { - Slog.e(TAG, "Unable to linkToDeath", e); - } - - if (mInvokingProxyCallbacks) { - Slog.e(TAG, "Proxy callbacks already in progress."); - return; - } - mInvokingProxyCallbacks = true; - - final int n = mProxies.beginBroadcast(); - try { - for (int i = 0; i < n; i++) { - try { - mProxies.getBroadcastItem(i).onServiceConnected(className, service); - } catch (RemoteException e) { - Slog.e(TAG, "Unable to connect to proxy", e); - } - } - } finally { - mProxies.finishBroadcast(); - mInvokingProxyCallbacks = false; - } - } - - @Override - public void onServiceDisconnected(ComponentName className) { - if (mService == null) { - return; - } - try { - mService.unlinkToDeath(this, 0); - } catch (NoSuchElementException e) { - Log.e(TAG, "error unlinking to death", e); - } - mService = null; - mClassName = null; - - if (mInvokingProxyCallbacks) { - Slog.e(TAG, "Proxy callbacks already in progress."); - return; - } - mInvokingProxyCallbacks = true; - - final int n = mProxies.beginBroadcast(); - try { - for (int i = 0; i < n; i++) { - try { - mProxies.getBroadcastItem(i).onServiceDisconnected(className); - } catch (RemoteException e) { - Slog.e(TAG, "Unable to disconnect from proxy", e); - } - } - } finally { - mProxies.finishBroadcast(); - mInvokingProxyCallbacks = false; - } - } - - @Override - public void binderDied() { - if (DBG) { - Slog.w(TAG, "Profile service for profile: " + mClassName + " died."); - } - onServiceDisconnected(mClassName); - // Trigger rebind - Message msg = mHandler.obtainMessage(MESSAGE_BIND_PROFILE_SERVICE); - msg.obj = this; - mHandler.sendMessageDelayed(msg, TIMEOUT_BIND_MS); - } - } - - private void sendBluetoothStateCallback(boolean isUp) { - try { - int n = mStateChangeCallbacks.beginBroadcast(); - if (DBG) { - Slog.d(TAG, "Broadcasting onBluetoothStateChange(" + isUp + ") to " + n - + " receivers."); - } - for (int i = 0; i < n; i++) { - try { - mStateChangeCallbacks.getBroadcastItem(i).onBluetoothStateChange(isUp); - } catch (RemoteException e) { - Slog.e(TAG, "Unable to call onBluetoothStateChange() on callback #" + i, e); - } - } - } finally { - mStateChangeCallbacks.finishBroadcast(); - } - } - - /** - * Inform BluetoothAdapter instances that Adapter service is up - */ - private void sendBluetoothServiceUpCallback() { - synchronized (mCallbacks) { - try { - int n = mCallbacks.beginBroadcast(); - Slog.d(TAG, "Broadcasting onBluetoothServiceUp() to " + n + " receivers."); - for (int i = 0; i < n; i++) { - try { - mCallbacks.getBroadcastItem(i).onBluetoothServiceUp(mBluetooth); - } catch (RemoteException e) { - Slog.e(TAG, "Unable to call onBluetoothServiceUp() on callback #" + i, e); - } - } - } finally { - mCallbacks.finishBroadcast(); - } - } - } - - /** - * Inform BluetoothAdapter instances that Adapter service is down - */ - private void sendBluetoothServiceDownCallback() { - synchronized (mCallbacks) { - try { - int n = mCallbacks.beginBroadcast(); - Slog.d(TAG, "Broadcasting onBluetoothServiceDown() to " + n + " receivers."); - for (int i = 0; i < n; i++) { - try { - mCallbacks.getBroadcastItem(i).onBluetoothServiceDown(); - } catch (RemoteException e) { - Slog.e(TAG, "Unable to call onBluetoothServiceDown() on callback #" + i, e); - } - } - } finally { - mCallbacks.finishBroadcast(); - } - } - } - - public String getAddress(AttributionSource attributionSource) { - if (!checkConnectPermissionForDataDelivery(mContext, attributionSource, "getAddress")) { - return null; - } - - if ((Binder.getCallingUid() != Process.SYSTEM_UID) && (!checkIfCallerIsForegroundUser())) { - Slog.w(TAG, "getAddress(): not allowed for non-active and non system user"); - return null; - } - - if (mContext.checkCallingOrSelfPermission(Manifest.permission.LOCAL_MAC_ADDRESS) - != PackageManager.PERMISSION_GRANTED) { - return BluetoothAdapter.DEFAULT_MAC_ADDRESS; - } - - try { - mBluetoothLock.readLock().lock(); - if (mBluetooth != null) { - return mBluetooth.getAddressWithAttribution(attributionSource); - } - } catch (RemoteException e) { - Slog.e(TAG, - "getAddress(): Unable to retrieve address remotely. Returning cached address", - e); - } finally { - mBluetoothLock.readLock().unlock(); - } - - // mAddress is accessed from outside. - // It is alright without a lock. Here, bluetooth is off, no other thread is - // changing mAddress - return mAddress; - } - - public String getName(AttributionSource attributionSource) { - if (!checkConnectPermissionForDataDelivery(mContext, attributionSource, "getName")) { - return null; - } - - if ((Binder.getCallingUid() != Process.SYSTEM_UID) && (!checkIfCallerIsForegroundUser())) { - Slog.w(TAG, "getName(): not allowed for non-active and non system user"); - return null; - } - - try { - mBluetoothLock.readLock().lock(); - if (mBluetooth != null) { - return mBluetooth.getName(attributionSource); - } - } catch (RemoteException e) { - Slog.e(TAG, "getName(): Unable to retrieve name remotely. Returning cached name", e); - } finally { - mBluetoothLock.readLock().unlock(); - } - - // mName is accessed from outside. - // It alright without a lock. Here, bluetooth is off, no other thread is - // changing mName - return mName; - } - - private class BluetoothServiceConnection implements ServiceConnection { - public void onServiceConnected(ComponentName componentName, IBinder service) { - String name = componentName.getClassName(); - if (DBG) { - Slog.d(TAG, "BluetoothServiceConnection: " + name); - } - Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_CONNECTED); - if (name.equals("com.android.bluetooth.btservice.AdapterService")) { - msg.arg1 = SERVICE_IBLUETOOTH; - } else if (name.equals("com.android.bluetooth.gatt.GattService")) { - msg.arg1 = SERVICE_IBLUETOOTHGATT; - } else { - Slog.e(TAG, "Unknown service connected: " + name); - return; - } - msg.obj = service; - mHandler.sendMessage(msg); - } - - public void onServiceDisconnected(ComponentName componentName) { - // Called if we unexpectedly disconnect. - String name = componentName.getClassName(); - if (DBG) { - Slog.d(TAG, "BluetoothServiceConnection, disconnected: " + name); - } - Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED); - if (name.equals("com.android.bluetooth.btservice.AdapterService")) { - msg.arg1 = SERVICE_IBLUETOOTH; - } else if (name.equals("com.android.bluetooth.gatt.GattService")) { - msg.arg1 = SERVICE_IBLUETOOTHGATT; - } else { - Slog.e(TAG, "Unknown service disconnected: " + name); - return; - } - mHandler.sendMessage(msg); - } - } - - private BluetoothServiceConnection mConnection = new BluetoothServiceConnection(); - - private class BluetoothHandler extends Handler { - boolean mGetNameAddressOnly = false; - private int mWaitForEnableRetry; - private int mWaitForDisableRetry; - - BluetoothHandler(Looper looper) { - super(looper); - } - - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case MESSAGE_GET_NAME_AND_ADDRESS: - if (DBG) { - Slog.d(TAG, "MESSAGE_GET_NAME_AND_ADDRESS"); - } - try { - mBluetoothLock.writeLock().lock(); - if ((mBluetooth == null) && (!mBinding)) { - if (DBG) { - Slog.d(TAG, "Binding to service to get name and address"); - } - mGetNameAddressOnly = true; - Message timeoutMsg = mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND); - mHandler.sendMessageDelayed(timeoutMsg, TIMEOUT_BIND_MS); - Intent i = new Intent(IBluetooth.class.getName()); - if (!doBind(i, mConnection, - Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT, - UserHandle.CURRENT)) { - mHandler.removeMessages(MESSAGE_TIMEOUT_BIND); - } else { - mBinding = true; - } - } else if (mBluetooth != null) { - try { - storeNameAndAddress( - mBluetooth.getName(mContext.getAttributionSource()), - mBluetooth.getAddressWithAttribution( - mContext.getAttributionSource())); - } catch (RemoteException re) { - Slog.e(TAG, "Unable to grab names", re); - } - if (mGetNameAddressOnly && !mEnable) { - unbindAndFinish(); - } - mGetNameAddressOnly = false; - } - } finally { - mBluetoothLock.writeLock().unlock(); - } - break; - - case MESSAGE_ENABLE: - int quietEnable = msg.arg1; - int isBle = msg.arg2; - if (mHandler.hasMessages(MESSAGE_HANDLE_DISABLE_DELAYED) - || mHandler.hasMessages(MESSAGE_HANDLE_ENABLE_DELAYED)) { - // We are handling enable or disable right now, wait for it. - mHandler.sendMessageDelayed(mHandler.obtainMessage(MESSAGE_ENABLE, - quietEnable, isBle), ENABLE_DISABLE_DELAY_MS); - break; - } - - if (DBG) { - Slog.d(TAG, "MESSAGE_ENABLE(" + quietEnable + "): mBluetooth = " - + mBluetooth); - } - mHandler.removeMessages(MESSAGE_RESTART_BLUETOOTH_SERVICE); - mEnable = true; - - if (isBle == 0) { - persistBluetoothSetting(BLUETOOTH_ON_BLUETOOTH); - } - - // Use service interface to get the exact state - try { - mBluetoothLock.readLock().lock(); - if (mBluetooth != null) { - boolean isHandled = true; - int state = mBluetooth.getState(); - switch (state) { - case BluetoothAdapter.STATE_BLE_ON: - if (isBle == 1) { - Slog.i(TAG, "Already at BLE_ON State"); - } else { - Slog.w(TAG, "BT Enable in BLE_ON State, going to ON"); - mBluetooth.onLeServiceUp(mContext.getAttributionSource()); - } - break; - case BluetoothAdapter.STATE_BLE_TURNING_ON: - case BluetoothAdapter.STATE_TURNING_ON: - case BluetoothAdapter.STATE_ON: - Slog.i(TAG, "MESSAGE_ENABLE: already enabled"); - break; - default: - isHandled = false; - break; - } - if (isHandled) break; - } - } catch (RemoteException e) { - Slog.e(TAG, "", e); - } finally { - mBluetoothLock.readLock().unlock(); - } - - mQuietEnable = (quietEnable == 1); - if (mBluetooth == null) { - handleEnable(mQuietEnable); - } else { - // - // We need to wait until transitioned to STATE_OFF and - // the previous Bluetooth process has exited. The - // waiting period has three components: - // (a) Wait until the local state is STATE_OFF. This - // is accomplished by sending delay a message - // MESSAGE_HANDLE_ENABLE_DELAYED - // (b) Wait until the STATE_OFF state is updated to - // all components. - // (c) Wait until the Bluetooth process exits, and - // ActivityManager detects it. - // The waiting for (b) and (c) is accomplished by - // delaying the MESSAGE_RESTART_BLUETOOTH_SERVICE - // message. The delay time is backed off if Bluetooth - // continuously failed to turn on itself. - // - mWaitForEnableRetry = 0; - Message enableDelayedMsg = - mHandler.obtainMessage(MESSAGE_HANDLE_ENABLE_DELAYED); - mHandler.sendMessageDelayed(enableDelayedMsg, ENABLE_DISABLE_DELAY_MS); - } - break; - - case MESSAGE_DISABLE: - if (mHandler.hasMessages(MESSAGE_HANDLE_DISABLE_DELAYED) || mBinding - || mHandler.hasMessages(MESSAGE_HANDLE_ENABLE_DELAYED)) { - // We are handling enable or disable right now, wait for it. - mHandler.sendMessageDelayed(mHandler.obtainMessage(MESSAGE_DISABLE), - ENABLE_DISABLE_DELAY_MS); - break; - } - - if (DBG) { - Slog.d(TAG, "MESSAGE_DISABLE: mBluetooth = " + mBluetooth - + ", mBinding = " + mBinding); - } - mHandler.removeMessages(MESSAGE_RESTART_BLUETOOTH_SERVICE); - - if (mEnable && mBluetooth != null) { - mWaitForDisableRetry = 0; - Message disableDelayedMsg = - mHandler.obtainMessage(MESSAGE_HANDLE_DISABLE_DELAYED, 0, 0); - mHandler.sendMessageDelayed(disableDelayedMsg, ENABLE_DISABLE_DELAY_MS); - } else { - mEnable = false; - handleDisable(); - } - break; - - case MESSAGE_HANDLE_ENABLE_DELAYED: { - // The Bluetooth is turning off, wait for STATE_OFF - if (mState != BluetoothAdapter.STATE_OFF) { - if (mWaitForEnableRetry < MAX_WAIT_FOR_ENABLE_DISABLE_RETRIES) { - mWaitForEnableRetry++; - Message enableDelayedMsg = - mHandler.obtainMessage(MESSAGE_HANDLE_ENABLE_DELAYED); - mHandler.sendMessageDelayed(enableDelayedMsg, ENABLE_DISABLE_DELAY_MS); - break; - } else { - Slog.e(TAG, "Wait for STATE_OFF timeout"); - } - } - // Either state is changed to STATE_OFF or reaches the maximum retry, we - // should move forward to the next step. - mWaitForEnableRetry = 0; - Message restartMsg = - mHandler.obtainMessage(MESSAGE_RESTART_BLUETOOTH_SERVICE); - mHandler.sendMessageDelayed(restartMsg, getServiceRestartMs()); - Slog.d(TAG, "Handle enable is finished"); - break; - } - - case MESSAGE_HANDLE_DISABLE_DELAYED: { - boolean disabling = (msg.arg1 == 1); - Slog.d(TAG, "MESSAGE_HANDLE_DISABLE_DELAYED: disabling:" + disabling); - if (!disabling) { - // The Bluetooth is turning on, wait for STATE_ON - if (mState != BluetoothAdapter.STATE_ON) { - if (mWaitForDisableRetry < MAX_WAIT_FOR_ENABLE_DISABLE_RETRIES) { - mWaitForDisableRetry++; - Message disableDelayedMsg = mHandler.obtainMessage( - MESSAGE_HANDLE_DISABLE_DELAYED, 0, 0); - mHandler.sendMessageDelayed(disableDelayedMsg, - ENABLE_DISABLE_DELAY_MS); - break; - } else { - Slog.e(TAG, "Wait for STATE_ON timeout"); - } - } - // Either state is changed to STATE_ON or reaches the maximum retry, we - // should move forward to the next step. - mWaitForDisableRetry = 0; - mEnable = false; - handleDisable(); - // Wait for state exiting STATE_ON - Message disableDelayedMsg = - mHandler.obtainMessage(MESSAGE_HANDLE_DISABLE_DELAYED, 1, 0); - mHandler.sendMessageDelayed(disableDelayedMsg, ENABLE_DISABLE_DELAY_MS); - } else { - // The Bluetooth is turning off, wait for exiting STATE_ON - if (mState == BluetoothAdapter.STATE_ON) { - if (mWaitForDisableRetry < MAX_WAIT_FOR_ENABLE_DISABLE_RETRIES) { - mWaitForDisableRetry++; - Message disableDelayedMsg = mHandler.obtainMessage( - MESSAGE_HANDLE_DISABLE_DELAYED, 1, 0); - mHandler.sendMessageDelayed(disableDelayedMsg, - ENABLE_DISABLE_DELAY_MS); - break; - } else { - Slog.e(TAG, "Wait for exiting STATE_ON timeout"); - } - } - // Either state is exited from STATE_ON or reaches the maximum retry, we - // should move forward to the next step. - Slog.d(TAG, "Handle disable is finished"); - } - break; - } - - case MESSAGE_RESTORE_USER_SETTING: - if ((msg.arg1 == RESTORE_SETTING_TO_OFF) && mEnable) { - if (DBG) { - Slog.d(TAG, "Restore Bluetooth state to disabled"); - } - persistBluetoothSetting(BLUETOOTH_OFF); - mEnableExternal = false; - sendDisableMsg( - BluetoothProtoEnums.ENABLE_DISABLE_REASON_RESTORE_USER_SETTING, - mContext.getPackageName()); - } else if ((msg.arg1 == RESTORE_SETTING_TO_ON) && !mEnable) { - if (DBG) { - Slog.d(TAG, "Restore Bluetooth state to enabled"); - } - mQuietEnableExternal = false; - mEnableExternal = true; - // waive WRITE_SECURE_SETTINGS permission check - sendEnableMsg(false, - BluetoothProtoEnums.ENABLE_DISABLE_REASON_RESTORE_USER_SETTING, - mContext.getPackageName()); - } - break; - case MESSAGE_REGISTER_STATE_CHANGE_CALLBACK: { - IBluetoothStateChangeCallback callback = - (IBluetoothStateChangeCallback) msg.obj; - mStateChangeCallbacks.register(callback); - break; - } - case MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK: { - IBluetoothStateChangeCallback callback = - (IBluetoothStateChangeCallback) msg.obj; - mStateChangeCallbacks.unregister(callback); - break; - } - case MESSAGE_ADD_PROXY_DELAYED: { - ProfileServiceConnections psc = mProfileServices.get(msg.arg1); - if (psc == null) { - break; - } - IBluetoothProfileServiceConnection proxy = - (IBluetoothProfileServiceConnection) msg.obj; - psc.addProxy(proxy); - break; - } - case MESSAGE_BIND_PROFILE_SERVICE: { - ProfileServiceConnections psc = (ProfileServiceConnections) msg.obj; - removeMessages(MESSAGE_BIND_PROFILE_SERVICE, msg.obj); - if (psc == null) { - break; - } - psc.bindService(); - break; - } - case MESSAGE_BLUETOOTH_SERVICE_CONNECTED: { - if (DBG) { - Slog.d(TAG, "MESSAGE_BLUETOOTH_SERVICE_CONNECTED: " + msg.arg1); - } - - IBinder service = (IBinder) msg.obj; - try { - mBluetoothLock.writeLock().lock(); - if (msg.arg1 == SERVICE_IBLUETOOTHGATT) { - mBluetoothGatt = - IBluetoothGatt.Stub.asInterface(Binder.allowBlocking(service)); - continueFromBleOnState(); - break; - } // else must be SERVICE_IBLUETOOTH - - //Remove timeout - mHandler.removeMessages(MESSAGE_TIMEOUT_BIND); - - mBinding = false; - mBluetoothBinder = service; - mBluetooth = IBluetooth.Stub.asInterface(Binder.allowBlocking(service)); - - if (!isNameAndAddressSet()) { - Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS); - mHandler.sendMessage(getMsg); - if (mGetNameAddressOnly) { - return; - } - } - - //Register callback object - try { - mBluetooth.registerCallback(mBluetoothCallback, - mContext.getAttributionSource()); - } catch (RemoteException re) { - Slog.e(TAG, "Unable to register BluetoothCallback", re); - } - //Inform BluetoothAdapter instances that service is up - sendBluetoothServiceUpCallback(); - - //Do enable request - try { - if (!mBluetooth.enable(mQuietEnable, mContext.getAttributionSource())) { - Slog.e(TAG, "IBluetooth.enable() returned false"); - } - } catch (RemoteException e) { - Slog.e(TAG, "Unable to call enable()", e); - } - } finally { - mBluetoothLock.writeLock().unlock(); - } - - if (!mEnable) { - waitForState(Set.of(BluetoothAdapter.STATE_ON)); - handleDisable(); - waitForState(Set.of(BluetoothAdapter.STATE_OFF, - BluetoothAdapter.STATE_TURNING_ON, - BluetoothAdapter.STATE_TURNING_OFF, - BluetoothAdapter.STATE_BLE_TURNING_ON, - BluetoothAdapter.STATE_BLE_ON, - BluetoothAdapter.STATE_BLE_TURNING_OFF)); - } - break; - } - case MESSAGE_BLUETOOTH_STATE_CHANGE: { - int prevState = msg.arg1; - int newState = msg.arg2; - if (DBG) { - Slog.d(TAG, - "MESSAGE_BLUETOOTH_STATE_CHANGE: " + BluetoothAdapter.nameForState( - prevState) + " > " + BluetoothAdapter.nameForState( - newState)); - } - mState = newState; - bluetoothStateChangeHandler(prevState, newState); - // handle error state transition case from TURNING_ON to OFF - // unbind and rebind bluetooth service and enable bluetooth - if ((prevState == BluetoothAdapter.STATE_BLE_TURNING_ON) && (newState - == BluetoothAdapter.STATE_OFF) && (mBluetooth != null) && mEnable) { - recoverBluetoothServiceFromError(false); - } - if ((prevState == BluetoothAdapter.STATE_TURNING_ON) && (newState - == BluetoothAdapter.STATE_BLE_ON) && (mBluetooth != null) && mEnable) { - recoverBluetoothServiceFromError(true); - } - // If we tried to enable BT while BT was in the process of shutting down, - // wait for the BT process to fully tear down and then force a restart - // here. This is a bit of a hack (b/29363429). - if ((prevState == BluetoothAdapter.STATE_BLE_TURNING_OFF) && (newState - == BluetoothAdapter.STATE_OFF)) { - if (mEnable) { - Slog.d(TAG, "Entering STATE_OFF but mEnabled is true; restarting."); - waitForState(Set.of(BluetoothAdapter.STATE_OFF)); - Message restartMsg = - mHandler.obtainMessage(MESSAGE_RESTART_BLUETOOTH_SERVICE); - mHandler.sendMessageDelayed(restartMsg, getServiceRestartMs()); - } - } - if (newState == BluetoothAdapter.STATE_ON - || newState == BluetoothAdapter.STATE_BLE_ON) { - // bluetooth is working, reset the counter - if (mErrorRecoveryRetryCounter != 0) { - Slog.w(TAG, "bluetooth is recovered from error"); - mErrorRecoveryRetryCounter = 0; - } - } - break; - } - case MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED: { - Slog.e(TAG, "MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED(" + msg.arg1 + ")"); - try { - mBluetoothLock.writeLock().lock(); - if (msg.arg1 == SERVICE_IBLUETOOTH) { - // if service is unbinded already, do nothing and return - if (mBluetooth == null) { - break; - } - mBluetooth = null; - } else if (msg.arg1 == SERVICE_IBLUETOOTHGATT) { - mBluetoothGatt = null; - break; - } else { - Slog.e(TAG, "Unknown argument for service disconnect!"); - break; - } - } finally { - mBluetoothLock.writeLock().unlock(); - } - - // log the unexpected crash - addCrashLog(); - addActiveLog(BluetoothProtoEnums.ENABLE_DISABLE_REASON_CRASH, - mContext.getPackageName(), false); - if (mEnable) { - mEnable = false; - // Send a Bluetooth Restart message - Message restartMsg = - mHandler.obtainMessage(MESSAGE_RESTART_BLUETOOTH_SERVICE); - mHandler.sendMessageDelayed(restartMsg, getServiceRestartMs()); - } - - sendBluetoothServiceDownCallback(); - - // Send BT state broadcast to update - // the BT icon correctly - if ((mState == BluetoothAdapter.STATE_TURNING_ON) || (mState - == BluetoothAdapter.STATE_ON)) { - bluetoothStateChangeHandler(BluetoothAdapter.STATE_ON, - BluetoothAdapter.STATE_TURNING_OFF); - mState = BluetoothAdapter.STATE_TURNING_OFF; - } - if (mState == BluetoothAdapter.STATE_TURNING_OFF) { - bluetoothStateChangeHandler(BluetoothAdapter.STATE_TURNING_OFF, - BluetoothAdapter.STATE_OFF); - } - - mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE); - mState = BluetoothAdapter.STATE_OFF; - break; - } - case MESSAGE_RESTART_BLUETOOTH_SERVICE: { - mErrorRecoveryRetryCounter++; - Slog.d(TAG, "MESSAGE_RESTART_BLUETOOTH_SERVICE: retry count=" - + mErrorRecoveryRetryCounter); - if (mErrorRecoveryRetryCounter < MAX_ERROR_RESTART_RETRIES) { - /* Enable without persisting the setting as - it doesnt change when IBluetooth - service restarts */ - mEnable = true; - addActiveLog(BluetoothProtoEnums.ENABLE_DISABLE_REASON_RESTARTED, - mContext.getPackageName(), true); - handleEnable(mQuietEnable); - } else { - Slog.e(TAG, "Reach maximum retry to restart Bluetooth!"); - } - break; - } - case MESSAGE_TIMEOUT_BIND: { - Slog.e(TAG, "MESSAGE_TIMEOUT_BIND"); - mBluetoothLock.writeLock().lock(); - mBinding = false; - mBluetoothLock.writeLock().unlock(); - break; - } - case MESSAGE_TIMEOUT_UNBIND: { - Slog.e(TAG, "MESSAGE_TIMEOUT_UNBIND"); - mBluetoothLock.writeLock().lock(); - mUnbinding = false; - mBluetoothLock.writeLock().unlock(); - break; - } - - case MESSAGE_USER_SWITCHED: { - if (DBG) { - Slog.d(TAG, "MESSAGE_USER_SWITCHED"); - } - mHandler.removeMessages(MESSAGE_USER_SWITCHED); - - /* disable and enable BT when detect a user switch */ - if (mBluetooth != null && isEnabled()) { - restartForReason(BluetoothProtoEnums.ENABLE_DISABLE_REASON_USER_SWITCH); - } else if (mBinding || mBluetooth != null) { - Message userMsg = mHandler.obtainMessage(MESSAGE_USER_SWITCHED); - userMsg.arg2 = 1 + msg.arg2; - // if user is switched when service is binding retry after a delay - mHandler.sendMessageDelayed(userMsg, USER_SWITCHED_TIME_MS); - if (DBG) { - Slog.d(TAG, "Retry MESSAGE_USER_SWITCHED " + userMsg.arg2); - } - } - break; - } - case MESSAGE_USER_UNLOCKED: { - if (DBG) { - Slog.d(TAG, "MESSAGE_USER_UNLOCKED"); - } - mHandler.removeMessages(MESSAGE_USER_SWITCHED); - - if (mEnable && !mBinding && (mBluetooth == null)) { - // We should be connected, but we gave up for some - // reason; maybe the Bluetooth service wasn't encryption - // aware, so try binding again. - if (DBG) { - Slog.d(TAG, "Enabled but not bound; retrying after unlock"); - } - handleEnable(mQuietEnable); - } - break; - } - case MESSAGE_INIT_FLAGS_CHANGED: { - if (DBG) { - Slog.d(TAG, "MESSAGE_INIT_FLAGS_CHANGED"); - } - mHandler.removeMessages(MESSAGE_INIT_FLAGS_CHANGED); - if (mBluetoothModeChangeHelper.isMediaProfileConnected()) { - Slog.i(TAG, "Delaying MESSAGE_INIT_FLAGS_CHANGED by " - + DELAY_FOR_RETRY_INIT_FLAG_CHECK_MS - + " ms due to existing connections"); - mHandler.sendEmptyMessageDelayed( - MESSAGE_INIT_FLAGS_CHANGED, - DELAY_FOR_RETRY_INIT_FLAG_CHECK_MS); - break; - } - if (!isDeviceProvisioned()) { - Slog.i(TAG, "Delaying MESSAGE_INIT_FLAGS_CHANGED by " - + DELAY_FOR_RETRY_INIT_FLAG_CHECK_MS - + "ms because device is not provisioned"); - mHandler.sendEmptyMessageDelayed( - MESSAGE_INIT_FLAGS_CHANGED, - DELAY_FOR_RETRY_INIT_FLAG_CHECK_MS); - break; - } - if (mBluetooth != null && isEnabled()) { - Slog.i(TAG, "Restarting Bluetooth due to init flag change"); - restartForReason( - BluetoothProtoEnums.ENABLE_DISABLE_REASON_INIT_FLAGS_CHANGED); - } - break; - } - } - } - - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED - }) - private void restartForReason(int reason) { - try { - mBluetoothLock.readLock().lock(); - if (mBluetooth != null) { - mBluetooth.unregisterCallback(mBluetoothCallback, - mContext.getAttributionSource()); - } - } catch (RemoteException re) { - Slog.e(TAG, "Unable to unregister", re); - } finally { - mBluetoothLock.readLock().unlock(); - } - - if (mState == BluetoothAdapter.STATE_TURNING_OFF) { - // MESSAGE_USER_SWITCHED happened right after MESSAGE_ENABLE - bluetoothStateChangeHandler(mState, BluetoothAdapter.STATE_OFF); - mState = BluetoothAdapter.STATE_OFF; - } - if (mState == BluetoothAdapter.STATE_OFF) { - bluetoothStateChangeHandler(mState, BluetoothAdapter.STATE_TURNING_ON); - mState = BluetoothAdapter.STATE_TURNING_ON; - } - - waitForState(Set.of(BluetoothAdapter.STATE_ON)); - - if (mState == BluetoothAdapter.STATE_TURNING_ON) { - bluetoothStateChangeHandler(mState, BluetoothAdapter.STATE_ON); - } - - unbindAllBluetoothProfileServices(); - // disable - addActiveLog(reason, mContext.getPackageName(), false); - handleDisable(); - // Pbap service need receive STATE_TURNING_OFF intent to close - bluetoothStateChangeHandler(BluetoothAdapter.STATE_ON, - BluetoothAdapter.STATE_TURNING_OFF); - - boolean didDisableTimeout = - !waitForState(Set.of(BluetoothAdapter.STATE_OFF)); - - bluetoothStateChangeHandler(BluetoothAdapter.STATE_TURNING_OFF, - BluetoothAdapter.STATE_OFF); - sendBluetoothServiceDownCallback(); - - try { - mBluetoothLock.writeLock().lock(); - if (mBluetooth != null) { - mBluetooth = null; - // Unbind - mContext.unbindService(mConnection); - } - mBluetoothGatt = null; - } finally { - mBluetoothLock.writeLock().unlock(); - } - - // - // If disabling Bluetooth times out, wait for an - // additional amount of time to ensure the process is - // shut down completely before attempting to restart. - // - if (didDisableTimeout) { - SystemClock.sleep(3000); - } else { - SystemClock.sleep(100); - } - - mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE); - mState = BluetoothAdapter.STATE_OFF; - // enable - addActiveLog(reason, mContext.getPackageName(), true); - // mEnable flag could have been reset on disableBLE. Reenable it. - mEnable = true; - handleEnable(mQuietEnable); - } - } - - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - private void handleEnable(boolean quietMode) { - mQuietEnable = quietMode; - - try { - mBluetoothLock.writeLock().lock(); - if ((mBluetooth == null) && (!mBinding)) { - Slog.d(TAG, "binding Bluetooth service"); - //Start bind timeout and bind - Message timeoutMsg = mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND); - mHandler.sendMessageDelayed(timeoutMsg, TIMEOUT_BIND_MS); - Intent i = new Intent(IBluetooth.class.getName()); - if (!doBind(i, mConnection, Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT, - UserHandle.CURRENT)) { - mHandler.removeMessages(MESSAGE_TIMEOUT_BIND); - } else { - mBinding = true; - } - } else if (mBluetooth != null) { - //Enable bluetooth - try { - if (!mBluetooth.enable(mQuietEnable, mContext.getAttributionSource())) { - Slog.e(TAG, "IBluetooth.enable() returned false"); - } - } catch (RemoteException e) { - Slog.e(TAG, "Unable to call enable()", e); - } - } - } finally { - mBluetoothLock.writeLock().unlock(); - } - } - - boolean doBind(Intent intent, ServiceConnection conn, int flags, UserHandle user) { - ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0); - intent.setComponent(comp); - if (comp == null || !mContext.bindServiceAsUser(intent, conn, flags, user)) { - Slog.e(TAG, "Fail to bind to: " + intent); - return false; - } - return true; - } - - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - private void handleDisable() { - try { - mBluetoothLock.readLock().lock(); - if (mBluetooth != null) { - if (DBG) { - Slog.d(TAG, "Sending off request."); - } - if (!mBluetooth.disable(mContext.getAttributionSource())) { - Slog.e(TAG, "IBluetooth.disable() returned false"); - } - } - } catch (RemoteException e) { - Slog.e(TAG, "Unable to call disable()", e); - } finally { - mBluetoothLock.readLock().unlock(); - } - } - - private boolean checkIfCallerIsForegroundUser() { - int foregroundUser; - int callingUser = UserHandle.getCallingUserId(); - int callingUid = Binder.getCallingUid(); - final long callingIdentity = Binder.clearCallingIdentity(); - UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE); - UserInfo ui = um.getProfileParent(callingUser); - int parentUser = (ui != null) ? ui.id : UserHandle.USER_NULL; - int callingAppId = UserHandle.getAppId(callingUid); - boolean valid = false; - try { - foregroundUser = ActivityManager.getCurrentUser(); - valid = (callingUser == foregroundUser) || parentUser == foregroundUser - || callingAppId == Process.NFC_UID || callingAppId == mSystemUiUid - || callingAppId == Process.SHELL_UID; - if (DBG && !valid) { - Slog.d(TAG, "checkIfCallerIsForegroundUser: valid=" + valid + " callingUser=" - + callingUser + " parentUser=" + parentUser + " foregroundUser=" - + foregroundUser); - } - } finally { - Binder.restoreCallingIdentity(callingIdentity); - } - return valid; - } - - private void sendBleStateChanged(int prevState, int newState) { - if (DBG) { - Slog.d(TAG, - "Sending BLE State Change: " + BluetoothAdapter.nameForState(prevState) + " > " - + BluetoothAdapter.nameForState(newState)); - } - // Send broadcast message to everyone else - Intent intent = new Intent(BluetoothAdapter.ACTION_BLE_STATE_CHANGED); - 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, null, getTempAllowlistBroadcastOptions()); - } - - private boolean isBleState(int state) { - switch (state) { - case BluetoothAdapter.STATE_BLE_ON: - case BluetoothAdapter.STATE_BLE_TURNING_ON: - case BluetoothAdapter.STATE_BLE_TURNING_OFF: - return true; - } - return false; - } - - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) - private void bluetoothStateChangeHandler(int prevState, int newState) { - boolean isStandardBroadcast = true; - if (prevState == newState) { // No change. Nothing to do. - return; - } - // Notify all proxy objects first of adapter state change - if (newState == BluetoothAdapter.STATE_BLE_ON || newState == BluetoothAdapter.STATE_OFF) { - boolean intermediate_off = (prevState == BluetoothAdapter.STATE_TURNING_OFF - && newState == BluetoothAdapter.STATE_BLE_ON); - - if (newState == BluetoothAdapter.STATE_OFF) { - // If Bluetooth is off, send service down event to proxy objects, and unbind - if (DBG) { - Slog.d(TAG, "Bluetooth is complete send Service Down"); - } - sendBluetoothServiceDownCallback(); - unbindAndFinish(); - sendBleStateChanged(prevState, newState); - - /* Currently, the OFF intent is broadcasted externally only when we transition - * from TURNING_OFF to BLE_ON state. So if the previous state is a BLE state, - * we are guaranteed that the OFF intent has been broadcasted earlier and we - * can safely skip it. - * Conversely, if the previous state is not a BLE state, it indicates that some - * sort of crash has occurred, moving us directly to STATE_OFF without ever - * passing through BLE_ON. We should broadcast the OFF intent in this case. */ - isStandardBroadcast = !isBleState(prevState); - - } else if (!intermediate_off) { - // connect to GattService - if (DBG) { - Slog.d(TAG, "Bluetooth is in LE only mode"); - } - if (mBluetoothGatt != null || !mContext.getPackageManager() - .hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) { - continueFromBleOnState(); - } else { - if (DBG) { - Slog.d(TAG, "Binding Bluetooth GATT service"); - } - Intent i = new Intent(IBluetoothGatt.class.getName()); - doBind(i, mConnection, Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT, - UserHandle.CURRENT); - } - sendBleStateChanged(prevState, newState); - //Don't broadcase this as std intent - isStandardBroadcast = false; - - } else if (intermediate_off) { - if (DBG) { - Slog.d(TAG, "Intermediate off, back to LE only mode"); - } - // For LE only mode, broadcast as is - sendBleStateChanged(prevState, newState); - sendBluetoothStateCallback(false); // BT is OFF for general users - // Broadcast as STATE_OFF - newState = BluetoothAdapter.STATE_OFF; - sendBrEdrDownCallback(mContext.getAttributionSource()); - } - } else if (newState == BluetoothAdapter.STATE_ON) { - boolean isUp = (newState == BluetoothAdapter.STATE_ON); - sendBluetoothStateCallback(isUp); - sendBleStateChanged(prevState, newState); - - } else if (newState == BluetoothAdapter.STATE_BLE_TURNING_ON - || newState == BluetoothAdapter.STATE_BLE_TURNING_OFF) { - sendBleStateChanged(prevState, newState); - isStandardBroadcast = false; - - } else if (newState == BluetoothAdapter.STATE_TURNING_ON - || newState == BluetoothAdapter.STATE_TURNING_OFF) { - sendBleStateChanged(prevState, newState); - } - - if (isStandardBroadcast) { - if (prevState == BluetoothAdapter.STATE_BLE_ON) { - // Show prevState of BLE_ON as OFF to standard users - prevState = BluetoothAdapter.STATE_OFF; - } - if (DBG) { - Slog.d(TAG, - "Sending State Change: " + BluetoothAdapter.nameForState(prevState) + " > " - + BluetoothAdapter.nameForState(newState)); - } - Intent intent = new Intent(BluetoothAdapter.ACTION_STATE_CHANGED); - 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, null, - getTempAllowlistBroadcastOptions()); - } - } - - private boolean waitForState(Set states) { - int i = 0; - while (i < 10) { - try { - mBluetoothLock.readLock().lock(); - if (mBluetooth == null) { - break; - } - if (states.contains(mBluetooth.getState())) { - return true; - } - } catch (RemoteException e) { - Slog.e(TAG, "getState()", e); - break; - } finally { - mBluetoothLock.readLock().unlock(); - } - SystemClock.sleep(300); - i++; - } - Slog.e(TAG, "waitForState " + states + " time out"); - return false; - } - - private void sendDisableMsg(int reason, String packageName) { - mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_DISABLE)); - addActiveLog(reason, packageName, false); - } - - private void sendEnableMsg(boolean quietMode, int reason, String packageName) { - sendEnableMsg(quietMode, reason, packageName, false); - } - - private void sendEnableMsg(boolean quietMode, int reason, String packageName, boolean isBle) { - mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_ENABLE, quietMode ? 1 : 0, - isBle ? 1 : 0)); - addActiveLog(reason, packageName, true); - mLastEnabledTime = SystemClock.elapsedRealtime(); - } - - private void addActiveLog(int reason, String packageName, boolean enable) { - synchronized (mActiveLogs) { - if (mActiveLogs.size() > ACTIVE_LOG_MAX_SIZE) { - mActiveLogs.remove(); - } - mActiveLogs.add( - new ActiveLog(reason, packageName, enable, System.currentTimeMillis())); - } - - int state = enable ? FrameworkStatsLog.BLUETOOTH_ENABLED_STATE_CHANGED__STATE__ENABLED : - FrameworkStatsLog.BLUETOOTH_ENABLED_STATE_CHANGED__STATE__DISABLED; - FrameworkStatsLog.write_non_chained(FrameworkStatsLog.BLUETOOTH_ENABLED_STATE_CHANGED, - Binder.getCallingUid(), null, state, reason, packageName); - } - - private void addCrashLog() { - synchronized (mCrashTimestamps) { - if (mCrashTimestamps.size() == CRASH_LOG_MAX_SIZE) { - mCrashTimestamps.removeFirst(); - } - mCrashTimestamps.add(System.currentTimeMillis()); - mCrashes++; - } - } - - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) - private void recoverBluetoothServiceFromError(boolean clearBle) { - Slog.e(TAG, "recoverBluetoothServiceFromError"); - try { - mBluetoothLock.readLock().lock(); - if (mBluetooth != null) { - //Unregister callback object - mBluetooth.unregisterCallback(mBluetoothCallback, mContext.getAttributionSource()); - } - } catch (RemoteException re) { - Slog.e(TAG, "Unable to unregister", re); - } finally { - mBluetoothLock.readLock().unlock(); - } - - SystemClock.sleep(500); - - // disable - addActiveLog(BluetoothProtoEnums.ENABLE_DISABLE_REASON_START_ERROR, - mContext.getPackageName(), false); - handleDisable(); - - waitForState(Set.of(BluetoothAdapter.STATE_OFF)); - - sendBluetoothServiceDownCallback(); - - try { - mBluetoothLock.writeLock().lock(); - if (mBluetooth != null) { - mBluetooth = null; - // Unbind - mContext.unbindService(mConnection); - } - mBluetoothGatt = null; - } finally { - mBluetoothLock.writeLock().unlock(); - } - - mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE); - mState = BluetoothAdapter.STATE_OFF; - - if (clearBle) { - clearBleApps(); - } - - mEnable = false; - - // Send a Bluetooth Restart message to reenable bluetooth - Message restartMsg = mHandler.obtainMessage(MESSAGE_RESTART_BLUETOOTH_SERVICE); - mHandler.sendMessageDelayed(restartMsg, ERROR_RESTART_TIME_MS); - } - - private boolean isBluetoothDisallowed() { - final long callingIdentity = Binder.clearCallingIdentity(); - try { - return mContext.getSystemService(UserManager.class) - .hasUserRestriction(UserManager.DISALLOW_BLUETOOTH, UserHandle.SYSTEM); - } finally { - Binder.restoreCallingIdentity(callingIdentity); - } - } - - /** - * Disables BluetoothOppLauncherActivity component, so the Bluetooth sharing option is not - * offered to the user if Bluetooth or sharing is disallowed. Puts the component to its default - * state if Bluetooth is not disallowed. - * - * @param userId user to disable bluetooth sharing for. - * @param bluetoothSharingDisallowed whether bluetooth sharing is disallowed. - */ - private void updateOppLauncherComponentState(int userId, boolean bluetoothSharingDisallowed) { - final ComponentName oppLauncherComponent = new ComponentName("com.android.bluetooth", - "com.android.bluetooth.opp.BluetoothOppLauncherActivity"); - final int newState = - bluetoothSharingDisallowed ? PackageManager.COMPONENT_ENABLED_STATE_DISABLED - : PackageManager.COMPONENT_ENABLED_STATE_DEFAULT; - try { - final IPackageManager imp = AppGlobals.getPackageManager(); - imp.setComponentEnabledSetting(oppLauncherComponent, newState, - PackageManager.DONT_KILL_APP, userId); - } catch (Exception e) { - // The component was not found, do nothing. - } - } - - private int getServiceRestartMs() { - return (mErrorRecoveryRetryCounter + 1) * SERVICE_RESTART_TIME_MS; - } - - @Override - public void dump(FileDescriptor fd, PrintWriter writer, String[] args) { - if (!DumpUtils.checkDumpPermission(mContext, TAG, writer)) { - return; - } - if ((args.length > 0) && args[0].startsWith("--proto")) { - dumpProto(fd); - return; - } - String errorMsg = null; - - writer.println("Bluetooth Status"); - writer.println(" enabled: " + isEnabled()); - writer.println(" state: " + BluetoothAdapter.nameForState(mState)); - writer.println(" address: " + mAddress); - writer.println(" name: " + mName); - if (mEnable) { - long onDuration = SystemClock.elapsedRealtime() - mLastEnabledTime; - String onDurationString = String.format(Locale.US, "%02d:%02d:%02d.%03d", - (int) (onDuration / (1000 * 60 * 60)), - (int) ((onDuration / (1000 * 60)) % 60), (int) ((onDuration / 1000) % 60), - (int) (onDuration % 1000)); - writer.println(" time since enabled: " + onDurationString); - } - - if (mActiveLogs.size() == 0) { - writer.println("\nBluetooth never enabled!"); - } else { - writer.println("\nEnable log:"); - for (ActiveLog log : mActiveLogs) { - writer.println(" " + log); - } - } - - writer.println( - "\nBluetooth crashed " + mCrashes + " time" + (mCrashes == 1 ? "" : "s")); - if (mCrashes == CRASH_LOG_MAX_SIZE) { - writer.println("(last " + CRASH_LOG_MAX_SIZE + ")"); - } - for (Long time : mCrashTimestamps) { - writer.println(" " + timeToLog(time)); - } - - writer.println("\n" + mBleApps.size() + " BLE app" + (mBleApps.size() == 1 ? "" : "s") - + " registered"); - for (ClientDeathRecipient app : mBleApps.values()) { - writer.println(" " + app.getPackageName()); - } - - writer.println("\nBluetoothManagerService:"); - writer.println(" mEnable:" + mEnable); - writer.println(" mQuietEnable:" + mQuietEnable); - writer.println(" mEnableExternal:" + mEnableExternal); - writer.println(" mQuietEnableExternal:" + mQuietEnableExternal); - - writer.println(""); - writer.flush(); - if (args.length == 0) { - // Add arg to produce output - args = new String[1]; - args[0] = "--print"; - } - - if (mBluetoothBinder == null) { - errorMsg = "Bluetooth Service not connected"; - } else { - try { - mBluetoothBinder.dump(fd, args); - } catch (RemoteException re) { - errorMsg = "RemoteException while dumping Bluetooth Service"; - } - } - if (errorMsg != null) { - writer.println(errorMsg); - } - } - - private void dumpProto(FileDescriptor fd) { - final ProtoOutputStream proto = new ProtoOutputStream(fd); - proto.write(BluetoothManagerServiceDumpProto.ENABLED, isEnabled()); - proto.write(BluetoothManagerServiceDumpProto.STATE, mState); - proto.write(BluetoothManagerServiceDumpProto.STATE_NAME, - BluetoothAdapter.nameForState(mState)); - proto.write(BluetoothManagerServiceDumpProto.ADDRESS, mAddress); - proto.write(BluetoothManagerServiceDumpProto.NAME, mName); - if (mEnable) { - proto.write(BluetoothManagerServiceDumpProto.LAST_ENABLED_TIME_MS, mLastEnabledTime); - } - proto.write(BluetoothManagerServiceDumpProto.CURR_TIMESTAMP_MS, - SystemClock.elapsedRealtime()); - for (ActiveLog log : mActiveLogs) { - long token = proto.start(BluetoothManagerServiceDumpProto.ACTIVE_LOGS); - log.dump(proto); - proto.end(token); - } - proto.write(BluetoothManagerServiceDumpProto.NUM_CRASHES, mCrashes); - proto.write(BluetoothManagerServiceDumpProto.CRASH_LOG_MAXED, - mCrashes == CRASH_LOG_MAX_SIZE); - for (Long time : mCrashTimestamps) { - proto.write(BluetoothManagerServiceDumpProto.CRASH_TIMESTAMPS_MS, time); - } - proto.write(BluetoothManagerServiceDumpProto.NUM_BLE_APPS, mBleApps.size()); - for (ClientDeathRecipient app : mBleApps.values()) { - proto.write(BluetoothManagerServiceDumpProto.BLE_APP_PACKAGE_NAMES, - app.getPackageName()); - } - proto.flush(); - } - - private static String getEnableDisableReasonString(int reason) { - switch (reason) { - case BluetoothProtoEnums.ENABLE_DISABLE_REASON_APPLICATION_REQUEST: - return "APPLICATION_REQUEST"; - case BluetoothProtoEnums.ENABLE_DISABLE_REASON_AIRPLANE_MODE: - return "AIRPLANE_MODE"; - case BluetoothProtoEnums.ENABLE_DISABLE_REASON_DISALLOWED: - return "DISALLOWED"; - case BluetoothProtoEnums.ENABLE_DISABLE_REASON_RESTARTED: - return "RESTARTED"; - case BluetoothProtoEnums.ENABLE_DISABLE_REASON_START_ERROR: - return "START_ERROR"; - case BluetoothProtoEnums.ENABLE_DISABLE_REASON_SYSTEM_BOOT: - return "SYSTEM_BOOT"; - case BluetoothProtoEnums.ENABLE_DISABLE_REASON_CRASH: - return "CRASH"; - case BluetoothProtoEnums.ENABLE_DISABLE_REASON_USER_SWITCH: - return "USER_SWITCH"; - case BluetoothProtoEnums.ENABLE_DISABLE_REASON_RESTORE_USER_SETTING: - return "RESTORE_USER_SETTING"; - case BluetoothProtoEnums.ENABLE_DISABLE_REASON_FACTORY_RESET: - return "FACTORY_RESET"; - case BluetoothProtoEnums.ENABLE_DISABLE_REASON_INIT_FLAGS_CHANGED: - return "INIT_FLAGS_CHANGED"; - case BluetoothProtoEnums.ENABLE_DISABLE_REASON_UNSPECIFIED: - default: return "UNKNOWN[" + reason + "]"; - } - } - - @SuppressLint("AndroidFrameworkRequiresPermission") - private static boolean checkPermissionForDataDelivery(Context context, String permission, - AttributionSource attributionSource, String message) { - final int result = PermissionChecker.checkPermissionForDataDeliveryFromDataSource( - context, permission, PID_UNKNOWN, - new AttributionSource(context.getAttributionSource(), attributionSource), message); - if (result == PERMISSION_GRANTED) { - return true; - } - - final String msg = "Need " + permission + " permission for " + attributionSource + ": " - + message; - if (result == PERMISSION_HARD_DENIED) { - throw new SecurityException(msg); - } else { - Log.w(TAG, msg); - return false; - } - } - - /** - * Returns true if the BLUETOOTH_CONNECT permission is granted for the calling app. Returns - * false if the result is a soft denial. Throws SecurityException if the result is a hard - * denial. - * - *

    Should be used in situations where the app op should not be noted. - */ - @SuppressLint("AndroidFrameworkRequiresPermission") - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public static boolean checkConnectPermissionForDataDelivery( - Context context, AttributionSource attributionSource, String message) { - return checkPermissionForDataDelivery(context, BLUETOOTH_CONNECT, - attributionSource, message); - } - - static @NonNull Bundle getTempAllowlistBroadcastOptions() { - final long duration = 10_000; - final BroadcastOptions bOptions = BroadcastOptions.makeBasic(); - bOptions.setTemporaryAppAllowlist(duration, - TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_ALLOWED, - PowerExemptionManager.REASON_BLUETOOTH_BROADCAST, ""); - return bOptions.toBundle(); - } -} diff --git a/services/core/java/com/android/server/BluetoothModeChangeHelper.java b/services/core/java/com/android/server/BluetoothModeChangeHelper.java deleted file mode 100644 index e5854c968207a1d6f06f3e489fc8be516928035c..0000000000000000000000000000000000000000 --- a/services/core/java/com/android/server/BluetoothModeChangeHelper.java +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Copyright 2020 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.android.server; - -import android.annotation.RequiresPermission; -import android.bluetooth.BluetoothA2dp; -import android.bluetooth.BluetoothAdapter; -import android.bluetooth.BluetoothHearingAid; -import android.bluetooth.BluetoothLeAudio; -import android.bluetooth.BluetoothProfile; -import android.bluetooth.BluetoothProfile.ServiceListener; -import android.content.Context; -import android.content.res.Resources; -import android.provider.Settings; -import android.widget.Toast; - -import com.android.internal.R; -import com.android.internal.annotations.VisibleForTesting; - -/** - * Helper class that handles callout and callback methods without - * complex logic. - */ -public class BluetoothModeChangeHelper { - private volatile BluetoothA2dp mA2dp; - private volatile BluetoothHearingAid mHearingAid; - private volatile BluetoothLeAudio mLeAudio; - private final BluetoothAdapter mAdapter; - private final Context mContext; - - BluetoothModeChangeHelper(Context context) { - mAdapter = BluetoothAdapter.getDefaultAdapter(); - mContext = context; - - mAdapter.getProfileProxy(mContext, mProfileServiceListener, BluetoothProfile.A2DP); - mAdapter.getProfileProxy(mContext, mProfileServiceListener, - BluetoothProfile.HEARING_AID); - mAdapter.getProfileProxy(mContext, mProfileServiceListener, BluetoothProfile.LE_AUDIO); - } - - private final ServiceListener mProfileServiceListener = new ServiceListener() { - @Override - public void onServiceConnected(int profile, BluetoothProfile proxy) { - // Setup Bluetooth profile proxies - switch (profile) { - case BluetoothProfile.A2DP: - mA2dp = (BluetoothA2dp) proxy; - break; - case BluetoothProfile.HEARING_AID: - mHearingAid = (BluetoothHearingAid) proxy; - break; - case BluetoothProfile.LE_AUDIO: - mLeAudio = (BluetoothLeAudio) proxy; - break; - default: - break; - } - } - - @Override - public void onServiceDisconnected(int profile) { - // Clear Bluetooth profile proxies - switch (profile) { - case BluetoothProfile.A2DP: - mA2dp = null; - break; - case BluetoothProfile.HEARING_AID: - mHearingAid = null; - break; - case BluetoothProfile.LE_AUDIO: - mLeAudio = null; - break; - default: - break; - } - } - }; - - @VisibleForTesting - public boolean isMediaProfileConnected() { - return isA2dpConnected() || isHearingAidConnected() || isLeAudioConnected(); - } - - @VisibleForTesting - public boolean isBluetoothOn() { - final BluetoothAdapter adapter = mAdapter; - if (adapter == null) { - return false; - } - return adapter.getLeState() == BluetoothAdapter.STATE_ON; - } - - @VisibleForTesting - public boolean isAirplaneModeOn() { - return Settings.Global.getInt(mContext.getContentResolver(), - Settings.Global.AIRPLANE_MODE_ON, 0) == 1; - } - - @VisibleForTesting - @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) - public void onAirplaneModeChanged(BluetoothManagerService managerService) { - managerService.onAirplaneModeChanged(); - } - - @VisibleForTesting - public int getSettingsInt(String name) { - return Settings.Global.getInt(mContext.getContentResolver(), - name, 0); - } - - @VisibleForTesting - public void setSettingsInt(String name, int value) { - Settings.Global.putInt(mContext.getContentResolver(), - name, value); - } - - @VisibleForTesting - public void showToastMessage() { - Resources r = mContext.getResources(); - final CharSequence text = r.getString( - R.string.bluetooth_airplane_mode_toast, 0); - Toast.makeText(mContext, text, Toast.LENGTH_LONG).show(); - } - - private boolean isA2dpConnected() { - final BluetoothA2dp a2dp = mA2dp; - if (a2dp == null) { - return false; - } - return a2dp.getConnectedDevices().size() > 0; - } - - private boolean isHearingAidConnected() { - final BluetoothHearingAid hearingAid = mHearingAid; - if (hearingAid == null) { - return false; - } - return hearingAid.getConnectedDevices().size() > 0; - } - - private boolean isLeAudioConnected() { - final BluetoothLeAudio leAudio = mLeAudio; - if (leAudio == null) { - return false; - } - return leAudio.getConnectedDevices().size() > 0; - } -} diff --git a/services/core/java/com/android/server/BluetoothService.java b/services/core/java/com/android/server/BluetoothService.java deleted file mode 100644 index 1a1eecd0f4399c76a9d661900d5399ca09e456e2..0000000000000000000000000000000000000000 --- a/services/core/java/com/android/server/BluetoothService.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * 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 com.android.server; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.bluetooth.BluetoothAdapter; -import android.content.Context; -import android.os.UserManager; - -import com.android.server.SystemService.TargetUser; - -class BluetoothService extends SystemService { - private BluetoothManagerService mBluetoothManagerService; - private boolean mInitialized = false; - - public BluetoothService(Context context) { - super(context); - mBluetoothManagerService = new BluetoothManagerService(context); - } - - private void initialize() { - if (!mInitialized) { - mBluetoothManagerService.handleOnBootPhase(); - mInitialized = true; - } - } - - @Override - public void onStart() { - } - - @Override - public void onBootPhase(int phase) { - if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) { - publishBinderService(BluetoothAdapter.BLUETOOTH_MANAGER_SERVICE, - mBluetoothManagerService); - } else if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY && - !UserManager.isHeadlessSystemUserMode()) { - initialize(); - } - } - - @Override - public void onUserSwitching(@Nullable TargetUser from, @NonNull TargetUser to) { - if (!mInitialized) { - initialize(); - } else { - mBluetoothManagerService.handleOnSwitchUser(to.getUserIdentifier()); - } - } - - @Override - public void onUserUnlocking(@NonNull TargetUser user) { - mBluetoothManagerService.handleOnUnlockUser(user.getUserIdentifier()); - } -} diff --git a/services/tests/servicestests/Android.bp b/services/tests/servicestests/Android.bp index f182b66b910f30d21c9f7c00b3baa14a85cc4f19..428327c007282bcfe59f5543adc422378c6d33cc 100644 --- a/services/tests/servicestests/Android.bp +++ b/services/tests/servicestests/Android.bp @@ -25,6 +25,7 @@ android_test { "test-apps/JobTestApp/src/**/*.java", "test-apps/SuspendTestApp/src/**/*.java", + ":service-bluetooth-tests-sources", // TODO(b/214988855) : Remove once framework-bluetooth jar is ready ], static_libs: [ "frameworks-base-testutils", diff --git a/services/tests/servicestests/src/com/android/server/BluetoothAirplaneModeListenerTest.java b/services/tests/servicestests/src/com/android/server/BluetoothAirplaneModeListenerTest.java deleted file mode 100644 index a1d4c203de186a63a6d47cc3c7a3c31e3449e10d..0000000000000000000000000000000000000000 --- a/services/tests/servicestests/src/com/android/server/BluetoothAirplaneModeListenerTest.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright 2019 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.android.server; - -import static org.mockito.Mockito.*; - -import android.bluetooth.BluetoothAdapter; -import android.content.Context; -import android.os.Looper; -import android.provider.Settings; - -import androidx.test.InstrumentationRegistry; -import androidx.test.filters.MediumTest; -import androidx.test.runner.AndroidJUnit4; - -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; - -@MediumTest -@RunWith(AndroidJUnit4.class) -public class BluetoothAirplaneModeListenerTest { - private Context mContext; - private BluetoothAirplaneModeListener mBluetoothAirplaneModeListener; - private BluetoothAdapter mBluetoothAdapter; - private BluetoothModeChangeHelper mHelper; - - @Mock BluetoothManagerService mBluetoothManagerService; - - @Before - public void setUp() throws Exception { - mContext = InstrumentationRegistry.getTargetContext(); - - mHelper = mock(BluetoothModeChangeHelper.class); - when(mHelper.getSettingsInt(BluetoothAirplaneModeListener.TOAST_COUNT)) - .thenReturn(BluetoothAirplaneModeListener.MAX_TOAST_COUNT); - doNothing().when(mHelper).setSettingsInt(anyString(), anyInt()); - doNothing().when(mHelper).showToastMessage(); - doNothing().when(mHelper).onAirplaneModeChanged(any(BluetoothManagerService.class)); - - mBluetoothAirplaneModeListener = new BluetoothAirplaneModeListener( - mBluetoothManagerService, Looper.getMainLooper(), mContext); - mBluetoothAirplaneModeListener.start(mHelper); - } - - @Test - public void testIgnoreOnAirplanModeChange() { - Assert.assertFalse(mBluetoothAirplaneModeListener.shouldSkipAirplaneModeChange()); - - when(mHelper.isBluetoothOn()).thenReturn(true); - Assert.assertFalse(mBluetoothAirplaneModeListener.shouldSkipAirplaneModeChange()); - - when(mHelper.isMediaProfileConnected()).thenReturn(true); - Assert.assertFalse(mBluetoothAirplaneModeListener.shouldSkipAirplaneModeChange()); - - when(mHelper.isAirplaneModeOn()).thenReturn(true); - Assert.assertTrue(mBluetoothAirplaneModeListener.shouldSkipAirplaneModeChange()); - } - - @Test - public void testHandleAirplaneModeChange_InvokeAirplaneModeChanged() { - mBluetoothAirplaneModeListener.handleAirplaneModeChange(); - verify(mHelper).onAirplaneModeChanged(mBluetoothManagerService); - } - - @Test - public void testHandleAirplaneModeChange_NotInvokeAirplaneModeChanged_NotPopToast() { - mBluetoothAirplaneModeListener.mToastCount = BluetoothAirplaneModeListener.MAX_TOAST_COUNT; - when(mHelper.isBluetoothOn()).thenReturn(true); - when(mHelper.isMediaProfileConnected()).thenReturn(true); - when(mHelper.isAirplaneModeOn()).thenReturn(true); - mBluetoothAirplaneModeListener.handleAirplaneModeChange(); - - verify(mHelper).setSettingsInt(Settings.Global.BLUETOOTH_ON, - BluetoothManagerService.BLUETOOTH_ON_AIRPLANE); - verify(mHelper, times(0)).showToastMessage(); - verify(mHelper, times(0)).onAirplaneModeChanged(mBluetoothManagerService); - } - - @Test - public void testHandleAirplaneModeChange_NotInvokeAirplaneModeChanged_PopToast() { - mBluetoothAirplaneModeListener.mToastCount = 0; - when(mHelper.isBluetoothOn()).thenReturn(true); - when(mHelper.isMediaProfileConnected()).thenReturn(true); - when(mHelper.isAirplaneModeOn()).thenReturn(true); - mBluetoothAirplaneModeListener.handleAirplaneModeChange(); - - verify(mHelper).setSettingsInt(Settings.Global.BLUETOOTH_ON, - BluetoothManagerService.BLUETOOTH_ON_AIRPLANE); - verify(mHelper).showToastMessage(); - verify(mHelper, times(0)).onAirplaneModeChanged(mBluetoothManagerService); - } - - @Test - public void testIsPopToast_PopToast() { - mBluetoothAirplaneModeListener.mToastCount = 0; - Assert.assertTrue(mBluetoothAirplaneModeListener.shouldPopToast()); - verify(mHelper).setSettingsInt(BluetoothAirplaneModeListener.TOAST_COUNT, 1); - } - - @Test - public void testIsPopToast_NotPopToast() { - mBluetoothAirplaneModeListener.mToastCount = BluetoothAirplaneModeListener.MAX_TOAST_COUNT; - Assert.assertFalse(mBluetoothAirplaneModeListener.shouldPopToast()); - verify(mHelper, times(0)).setSettingsInt(anyString(), anyInt()); - } -}