/* * 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.Nullable; import android.annotation.RequiresPermission; import android.annotation.SdkConstant; import android.annotation.SuppressLint; import android.annotation.SdkConstant.SdkConstantType; import android.bluetooth.annotations.RequiresBluetoothConnectPermission; import android.bluetooth.annotations.RequiresLegacyBluetoothAdminPermission; import android.bluetooth.annotations.RequiresLegacyBluetoothPermission; import android.annotation.SystemApi; import android.compat.annotation.UnsupportedAppUsage; import android.content.Attributable; import android.content.AttributionSource; import android.content.ComponentName; import android.content.Context; import android.content.pm.PackageManager; import android.os.Binder; 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.internal.annotations.GuardedBy; import java.util.ArrayList; import java.util.List; import java.util.concurrent.locks.ReentrantReadWriteLock; /** * 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} 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} 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: *

* * @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. *

* *

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 *

*/ @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 disconnecting. * * @hide */ public static final int STATE_AUDIO_DISCONNECTING = 13; /** * 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 Battery status of TWS+ devices * *

This intent will have 2 extras: *