Merge "New public APIs for BluetoothA2dp and BluetoothHeadset profiles."
This commit is contained in:
committed by
Android (Google) Code Review
commit
c9cc487b7b
514
api/current.xml
514
api/current.xml
@@ -38675,6 +38675,111 @@
|
||||
</package>
|
||||
<package name="android.bluetooth"
|
||||
>
|
||||
<class name="BluetoothA2dp"
|
||||
extends="java.lang.Object"
|
||||
abstract="false"
|
||||
static="false"
|
||||
final="true"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
<implements name="android.bluetooth.BluetoothProfile">
|
||||
</implements>
|
||||
<method name="getConnectedDevices"
|
||||
return="java.util.Set<android.bluetooth.BluetoothDevice>"
|
||||
abstract="false"
|
||||
native="false"
|
||||
synchronized="false"
|
||||
static="false"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
</method>
|
||||
<method name="getConnectionState"
|
||||
return="int"
|
||||
abstract="false"
|
||||
native="false"
|
||||
synchronized="false"
|
||||
static="false"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
<parameter name="device" type="android.bluetooth.BluetoothDevice">
|
||||
</parameter>
|
||||
</method>
|
||||
<method name="getDevicesMatchingConnectionStates"
|
||||
return="java.util.Set<android.bluetooth.BluetoothDevice>"
|
||||
abstract="false"
|
||||
native="false"
|
||||
synchronized="false"
|
||||
static="false"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
<parameter name="states" type="int[]">
|
||||
</parameter>
|
||||
</method>
|
||||
<method name="isA2dpPlaying"
|
||||
return="boolean"
|
||||
abstract="false"
|
||||
native="false"
|
||||
synchronized="false"
|
||||
static="false"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
<parameter name="device" type="android.bluetooth.BluetoothDevice">
|
||||
</parameter>
|
||||
</method>
|
||||
<field name="ACTION_CONNECTION_STATE_CHANGED"
|
||||
type="java.lang.String"
|
||||
transient="false"
|
||||
volatile="false"
|
||||
value=""android.bluetooth.a2dp.profile.action.CONNECTION_STATE_CHANGED""
|
||||
static="true"
|
||||
final="true"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
</field>
|
||||
<field name="ACTION_PLAYING_STATE_CHANGED"
|
||||
type="java.lang.String"
|
||||
transient="false"
|
||||
volatile="false"
|
||||
value=""android.bluetooth.a2dp.profile.action.PLAYING_STATE_CHANGED""
|
||||
static="true"
|
||||
final="true"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
</field>
|
||||
<field name="STATE_NOT_PLAYING"
|
||||
type="int"
|
||||
transient="false"
|
||||
volatile="false"
|
||||
value="11"
|
||||
static="true"
|
||||
final="true"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
</field>
|
||||
<field name="STATE_PLAYING"
|
||||
type="int"
|
||||
transient="false"
|
||||
volatile="false"
|
||||
value="10"
|
||||
static="true"
|
||||
final="true"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
</field>
|
||||
</class>
|
||||
<class name="BluetoothAdapter"
|
||||
extends="java.lang.Object"
|
||||
abstract="false"
|
||||
@@ -38707,6 +38812,21 @@
|
||||
<parameter name="address" type="java.lang.String">
|
||||
</parameter>
|
||||
</method>
|
||||
<method name="closeProfileProxy"
|
||||
return="void"
|
||||
abstract="false"
|
||||
native="false"
|
||||
synchronized="false"
|
||||
static="false"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
<parameter name="profile" type="int">
|
||||
</parameter>
|
||||
<parameter name="proxy" type="android.bluetooth.BluetoothProfile">
|
||||
</parameter>
|
||||
</method>
|
||||
<method name="disable"
|
||||
return="boolean"
|
||||
abstract="false"
|
||||
@@ -38773,6 +38893,23 @@
|
||||
visibility="public"
|
||||
>
|
||||
</method>
|
||||
<method name="getProfileProxy"
|
||||
return="boolean"
|
||||
abstract="false"
|
||||
native="false"
|
||||
synchronized="false"
|
||||
static="false"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
<parameter name="context" type="android.content.Context">
|
||||
</parameter>
|
||||
<parameter name="listener" type="android.bluetooth.BluetoothProfile.ServiceListener">
|
||||
</parameter>
|
||||
<parameter name="profile" type="int">
|
||||
</parameter>
|
||||
</method>
|
||||
<method name="getRemoteDevice"
|
||||
return="android.bluetooth.BluetoothDevice"
|
||||
abstract="false"
|
||||
@@ -38871,6 +39008,17 @@
|
||||
visibility="public"
|
||||
>
|
||||
</method>
|
||||
<field name="ACTION_CONNECTION_STATE_CHANGED"
|
||||
type="java.lang.String"
|
||||
transient="false"
|
||||
volatile="false"
|
||||
value=""android.bluetooth.adapter.action.CONNECTION_STATE_CHANGED""
|
||||
static="true"
|
||||
final="true"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
</field>
|
||||
<field name="ACTION_DISCOVERY_FINISHED"
|
||||
type="java.lang.String"
|
||||
transient="false"
|
||||
@@ -38959,6 +39107,17 @@
|
||||
visibility="public"
|
||||
>
|
||||
</field>
|
||||
<field name="EXTRA_CONNECTION_STATE"
|
||||
type="java.lang.String"
|
||||
transient="false"
|
||||
volatile="false"
|
||||
value=""android.bluetooth.adapter.extra.CONNECTION_STATE""
|
||||
static="true"
|
||||
final="true"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
</field>
|
||||
<field name="EXTRA_DISCOVERABLE_DURATION"
|
||||
type="java.lang.String"
|
||||
transient="false"
|
||||
@@ -38981,6 +39140,17 @@
|
||||
visibility="public"
|
||||
>
|
||||
</field>
|
||||
<field name="EXTRA_PREVIOUS_CONNECTION_STATE"
|
||||
type="java.lang.String"
|
||||
transient="false"
|
||||
volatile="false"
|
||||
value=""android.bluetooth.adapter.extra.PREVIOUS_CONNECTION_STATE""
|
||||
static="true"
|
||||
final="true"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
</field>
|
||||
<field name="EXTRA_PREVIOUS_SCAN_MODE"
|
||||
type="java.lang.String"
|
||||
transient="false"
|
||||
@@ -39058,6 +39228,50 @@
|
||||
visibility="public"
|
||||
>
|
||||
</field>
|
||||
<field name="STATE_CONNECTED"
|
||||
type="int"
|
||||
transient="false"
|
||||
volatile="false"
|
||||
value="2"
|
||||
static="true"
|
||||
final="true"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
</field>
|
||||
<field name="STATE_CONNECTING"
|
||||
type="int"
|
||||
transient="false"
|
||||
volatile="false"
|
||||
value="1"
|
||||
static="true"
|
||||
final="true"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
</field>
|
||||
<field name="STATE_DISCONNECTED"
|
||||
type="int"
|
||||
transient="false"
|
||||
volatile="false"
|
||||
value="0"
|
||||
static="true"
|
||||
final="true"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
</field>
|
||||
<field name="STATE_DISCONNECTING"
|
||||
type="int"
|
||||
transient="false"
|
||||
volatile="false"
|
||||
value="3"
|
||||
static="true"
|
||||
final="true"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
</field>
|
||||
<field name="STATE_OFF"
|
||||
type="int"
|
||||
transient="false"
|
||||
@@ -40299,6 +40513,306 @@
|
||||
>
|
||||
</field>
|
||||
</class>
|
||||
<class name="BluetoothHeadset"
|
||||
extends="java.lang.Object"
|
||||
abstract="false"
|
||||
static="false"
|
||||
final="true"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
<implements name="android.bluetooth.BluetoothProfile">
|
||||
</implements>
|
||||
<method name="getConnectedDevices"
|
||||
return="java.util.Set<android.bluetooth.BluetoothDevice>"
|
||||
abstract="false"
|
||||
native="false"
|
||||
synchronized="false"
|
||||
static="false"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
</method>
|
||||
<method name="getConnectionState"
|
||||
return="int"
|
||||
abstract="false"
|
||||
native="false"
|
||||
synchronized="false"
|
||||
static="false"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
<parameter name="device" type="android.bluetooth.BluetoothDevice">
|
||||
</parameter>
|
||||
</method>
|
||||
<method name="getDevicesMatchingConnectionStates"
|
||||
return="java.util.Set<android.bluetooth.BluetoothDevice>"
|
||||
abstract="false"
|
||||
native="false"
|
||||
synchronized="false"
|
||||
static="false"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
<parameter name="states" type="int[]">
|
||||
</parameter>
|
||||
</method>
|
||||
<method name="isAudioConnected"
|
||||
return="boolean"
|
||||
abstract="false"
|
||||
native="false"
|
||||
synchronized="false"
|
||||
static="false"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
<parameter name="device" type="android.bluetooth.BluetoothDevice">
|
||||
</parameter>
|
||||
</method>
|
||||
<method name="startVoiceRecognition"
|
||||
return="boolean"
|
||||
abstract="false"
|
||||
native="false"
|
||||
synchronized="false"
|
||||
static="false"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
<parameter name="device" type="android.bluetooth.BluetoothDevice">
|
||||
</parameter>
|
||||
</method>
|
||||
<method name="stopVoiceRecognition"
|
||||
return="boolean"
|
||||
abstract="false"
|
||||
native="false"
|
||||
synchronized="false"
|
||||
static="false"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
<parameter name="device" type="android.bluetooth.BluetoothDevice">
|
||||
</parameter>
|
||||
</method>
|
||||
<field name="ACTION_AUDIO_STATE_CHANGED"
|
||||
type="java.lang.String"
|
||||
transient="false"
|
||||
volatile="false"
|
||||
value=""android.bluetooth.headset.profile.action.AUDIO_STATE_CHANGED""
|
||||
static="true"
|
||||
final="true"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
</field>
|
||||
<field name="ACTION_CONNECTION_STATE_CHANGED"
|
||||
type="java.lang.String"
|
||||
transient="false"
|
||||
volatile="false"
|
||||
value=""android.bluetooth.headset.profile.action.CONNECTION_STATE_CHANGED""
|
||||
static="true"
|
||||
final="true"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
</field>
|
||||
<field name="STATE_AUDIO_CONNECTED"
|
||||
type="int"
|
||||
transient="false"
|
||||
volatile="false"
|
||||
value="10"
|
||||
static="true"
|
||||
final="true"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
</field>
|
||||
<field name="STATE_AUDIO_DISCONNECTED"
|
||||
type="int"
|
||||
transient="false"
|
||||
volatile="false"
|
||||
value="11"
|
||||
static="true"
|
||||
final="true"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
</field>
|
||||
</class>
|
||||
<interface name="BluetoothProfile"
|
||||
abstract="true"
|
||||
static="false"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
<method name="getConnectedDevices"
|
||||
return="java.util.Set<android.bluetooth.BluetoothDevice>"
|
||||
abstract="true"
|
||||
native="false"
|
||||
synchronized="false"
|
||||
static="false"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
</method>
|
||||
<method name="getConnectionState"
|
||||
return="int"
|
||||
abstract="true"
|
||||
native="false"
|
||||
synchronized="false"
|
||||
static="false"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
<parameter name="device" type="android.bluetooth.BluetoothDevice">
|
||||
</parameter>
|
||||
</method>
|
||||
<method name="getDevicesMatchingConnectionStates"
|
||||
return="java.util.Set<android.bluetooth.BluetoothDevice>"
|
||||
abstract="true"
|
||||
native="false"
|
||||
synchronized="false"
|
||||
static="false"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
<parameter name="states" type="int[]">
|
||||
</parameter>
|
||||
</method>
|
||||
<field name="A2DP"
|
||||
type="int"
|
||||
transient="false"
|
||||
volatile="false"
|
||||
value="2"
|
||||
static="true"
|
||||
final="true"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
</field>
|
||||
<field name="EXTRA_PREVIOUS_STATE"
|
||||
type="java.lang.String"
|
||||
transient="false"
|
||||
volatile="false"
|
||||
value=""android.bluetooth.profile.extra.PREVIOUS_STATE""
|
||||
static="true"
|
||||
final="true"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
</field>
|
||||
<field name="EXTRA_STATE"
|
||||
type="java.lang.String"
|
||||
transient="false"
|
||||
volatile="false"
|
||||
value=""android.bluetooth.profile.extra.STATE""
|
||||
static="true"
|
||||
final="true"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
</field>
|
||||
<field name="HEADSET"
|
||||
type="int"
|
||||
transient="false"
|
||||
volatile="false"
|
||||
value="1"
|
||||
static="true"
|
||||
final="true"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
</field>
|
||||
<field name="STATE_CONNECTED"
|
||||
type="int"
|
||||
transient="false"
|
||||
volatile="false"
|
||||
value="2"
|
||||
static="true"
|
||||
final="true"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
</field>
|
||||
<field name="STATE_CONNECTING"
|
||||
type="int"
|
||||
transient="false"
|
||||
volatile="false"
|
||||
value="1"
|
||||
static="true"
|
||||
final="true"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
</field>
|
||||
<field name="STATE_DISCONNECTED"
|
||||
type="int"
|
||||
transient="false"
|
||||
volatile="false"
|
||||
value="0"
|
||||
static="true"
|
||||
final="true"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
</field>
|
||||
<field name="STATE_DISCONNECTING"
|
||||
type="int"
|
||||
transient="false"
|
||||
volatile="false"
|
||||
value="3"
|
||||
static="true"
|
||||
final="true"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
</field>
|
||||
</interface>
|
||||
<interface name="BluetoothProfile.ServiceListener"
|
||||
abstract="true"
|
||||
static="true"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
<method name="onServiceConnected"
|
||||
return="void"
|
||||
abstract="true"
|
||||
native="false"
|
||||
synchronized="false"
|
||||
static="false"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
<parameter name="profile" type="int">
|
||||
</parameter>
|
||||
<parameter name="proxy" type="android.bluetooth.BluetoothProfile">
|
||||
</parameter>
|
||||
</method>
|
||||
<method name="onServiceDisconnected"
|
||||
return="void"
|
||||
abstract="true"
|
||||
native="false"
|
||||
synchronized="false"
|
||||
static="false"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
<parameter name="profile" type="int">
|
||||
</parameter>
|
||||
</method>
|
||||
</interface>
|
||||
<class name="BluetoothServerSocket"
|
||||
extends="java.lang.Object"
|
||||
abstract="false"
|
||||
|
||||
@@ -18,88 +18,104 @@ package android.bluetooth;
|
||||
|
||||
import android.annotation.SdkConstant;
|
||||
import android.annotation.SdkConstant.SdkConstantType;
|
||||
import android.server.BluetoothA2dpService;
|
||||
import android.content.Context;
|
||||
import android.os.ServiceManager;
|
||||
import android.os.RemoteException;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ServiceManager;
|
||||
import android.server.BluetoothA2dpService;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
|
||||
/**
|
||||
* Public API for controlling the Bluetooth A2DP Profile Service.
|
||||
* 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.
|
||||
*<p>BluetoothA2dp is a proxy object for controlling the Bluetooth A2DP
|
||||
* Service via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get
|
||||
* the BluetoothA2dp proxy object.
|
||||
*
|
||||
* Creating a BluetoothA2dp object will initiate a binding with the
|
||||
* BluetoothHeadset service. Users of this object should call close() when they
|
||||
* are finished, so that this proxy object can unbind from the service.
|
||||
*
|
||||
* Currently the BluetoothA2dp service runs in the system server and this
|
||||
* proxy object will be immediately bound to the service on construction.
|
||||
*
|
||||
* Currently this class provides methods to connect to A2DP audio sinks.
|
||||
*
|
||||
* @hide
|
||||
* <p> Android only supports one connected Bluetooth A2dp device at a time.
|
||||
* Each method is protected with its appropriate permission.
|
||||
*/
|
||||
public final class BluetoothA2dp {
|
||||
public final class BluetoothA2dp implements BluetoothProfile {
|
||||
private static final String TAG = "BluetoothA2dp";
|
||||
private static final boolean DBG = false;
|
||||
|
||||
/** int extra for ACTION_SINK_STATE_CHANGED */
|
||||
public static final String EXTRA_SINK_STATE =
|
||||
"android.bluetooth.a2dp.extra.SINK_STATE";
|
||||
/** int extra for ACTION_SINK_STATE_CHANGED */
|
||||
public static final String EXTRA_PREVIOUS_SINK_STATE =
|
||||
"android.bluetooth.a2dp.extra.PREVIOUS_SINK_STATE";
|
||||
|
||||
/** Indicates the state of an A2DP audio sink has changed.
|
||||
* This intent will always contain EXTRA_SINK_STATE,
|
||||
* EXTRA_PREVIOUS_SINK_STATE and BluetoothDevice.EXTRA_DEVICE
|
||||
* extras.
|
||||
/**
|
||||
* Intent used to broadcast the change in connection state of the A2DP
|
||||
* profile.
|
||||
*
|
||||
* <p>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}.
|
||||
*
|
||||
* <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
|
||||
*/
|
||||
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
|
||||
public static final String ACTION_SINK_STATE_CHANGED =
|
||||
"android.bluetooth.a2dp.action.SINK_STATE_CHANGED";
|
||||
public static final String ACTION_CONNECTION_STATE_CHANGED =
|
||||
"android.bluetooth.a2dp.profile.action.CONNECTION_STATE_CHANGED";
|
||||
|
||||
public static final int STATE_DISCONNECTED = 0;
|
||||
public static final int STATE_CONNECTING = 1;
|
||||
public static final int STATE_CONNECTED = 2;
|
||||
public static final int STATE_DISCONNECTING = 3;
|
||||
/** Playing implies connected */
|
||||
public static final int STATE_PLAYING = 4;
|
||||
/**
|
||||
* Intent used to broadcast the change in the Playing state of the A2DP
|
||||
* profile.
|
||||
*
|
||||
* <p>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},
|
||||
*
|
||||
* <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
|
||||
*/
|
||||
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
|
||||
public static final String ACTION_PLAYING_STATE_CHANGED =
|
||||
"android.bluetooth.a2dp.profile.action.PLAYING_STATE_CHANGED";
|
||||
|
||||
/** Default priority for a2dp devices that we try to auto-connect
|
||||
* and allow incoming connections */
|
||||
public static final int PRIORITY_AUTO_CONNECT = 1000;
|
||||
/** Default priority for a2dp devices that should allow incoming
|
||||
* connections */
|
||||
public static final int PRIORITY_ON = 100;
|
||||
/** Default priority for a2dp devices that should not allow incoming
|
||||
* connections */
|
||||
public static final int PRIORITY_OFF = 0;
|
||||
/** Default priority when not set or when the device is unpaired */
|
||||
public static final int PRIORITY_UNDEFINED = -1;
|
||||
/**
|
||||
* 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;
|
||||
|
||||
private final IBluetoothA2dp mService;
|
||||
private final Context mContext;
|
||||
/**
|
||||
* 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;
|
||||
|
||||
private ServiceListener mServiceListener;
|
||||
private IBluetoothA2dp mService;
|
||||
private BluetoothAdapter mAdapter;
|
||||
|
||||
/**
|
||||
* Create a BluetoothA2dp proxy object for interacting with the local
|
||||
* Bluetooth A2DP service.
|
||||
* @param c Context
|
||||
*
|
||||
*/
|
||||
public BluetoothA2dp(Context c) {
|
||||
mContext = c;
|
||||
|
||||
/*package*/ BluetoothA2dp(Context mContext, ServiceListener l) {
|
||||
IBinder b = ServiceManager.getService(BluetoothA2dpService.BLUETOOTH_A2DP_SERVICE);
|
||||
mServiceListener = l;
|
||||
mAdapter = BluetoothAdapter.getDefaultAdapter();
|
||||
if (b != null) {
|
||||
mService = IBluetoothA2dp.Stub.asInterface(b);
|
||||
if (mServiceListener != null) {
|
||||
mServiceListener.onServiceConnected(BluetoothProfile.A2DP, this);
|
||||
}
|
||||
} else {
|
||||
Log.w(TAG, "Bluetooth A2DP service not available!");
|
||||
|
||||
@@ -109,167 +125,222 @@ public final class BluetoothA2dp {
|
||||
}
|
||||
}
|
||||
|
||||
/** Initiate a connection to an A2DP sink.
|
||||
* Listen for SINK_STATE_CHANGED_ACTION to find out when the
|
||||
* connection is completed.
|
||||
* @param device Remote BT device.
|
||||
* @return false on immediate error, true otherwise
|
||||
* @hide
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @hide
|
||||
*/
|
||||
public boolean connectSink(BluetoothDevice device) {
|
||||
if (DBG) log("connectSink(" + device + ")");
|
||||
try {
|
||||
return mService.connectSink(device);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "", e);
|
||||
return false;
|
||||
public boolean connect(BluetoothDevice device) {
|
||||
if (DBG) log("connect(" + device + ")");
|
||||
if (mService != null && isEnabled() &&
|
||||
isValidDevice(device)) {
|
||||
try {
|
||||
return mService.connect(device);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (mService == null) Log.w(TAG, "Proxy not attached to service");
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Initiate disconnect from an A2DP sink.
|
||||
* Listen for SINK_STATE_CHANGED_ACTION to find out when
|
||||
* disconnect is completed.
|
||||
* @param device Remote BT device.
|
||||
* @return false on immediate error, true otherwise
|
||||
* @hide
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @hide
|
||||
*/
|
||||
public boolean disconnectSink(BluetoothDevice device) {
|
||||
if (DBG) log("disconnectSink(" + device + ")");
|
||||
try {
|
||||
return mService.disconnectSink(device);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "", e);
|
||||
return false;
|
||||
public boolean disconnect(BluetoothDevice device) {
|
||||
if (DBG) log("disconnect(" + device + ")");
|
||||
if (mService != null && isEnabled() &&
|
||||
isValidDevice(device)) {
|
||||
try {
|
||||
return mService.disconnect(device);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (mService == null) Log.w(TAG, "Proxy not attached to service");
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Initiate suspend from an A2DP sink.
|
||||
* Listen for SINK_STATE_CHANGED_ACTION to find out when
|
||||
* suspend is completed.
|
||||
* @param device Remote BT device.
|
||||
* @return false on immediate error, true otherwise
|
||||
* @hide
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public Set<BluetoothDevice> getConnectedDevices() {
|
||||
if (DBG) log("getConnectedDevices()");
|
||||
if (mService != null && isEnabled()) {
|
||||
try {
|
||||
return toDeviceSet(mService.getConnectedDevices());
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
|
||||
return toDeviceSet(new BluetoothDevice[0]);
|
||||
}
|
||||
}
|
||||
if (mService == null) Log.w(TAG, "Proxy not attached to service");
|
||||
return toDeviceSet(new BluetoothDevice[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public Set<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
|
||||
if (DBG) log("getDevicesMatchingStates()");
|
||||
if (mService != null && isEnabled()) {
|
||||
try {
|
||||
return toDeviceSet(mService.getDevicesMatchingConnectionStates(states));
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
|
||||
return toDeviceSet(new BluetoothDevice[0]);
|
||||
}
|
||||
}
|
||||
if (mService == null) Log.w(TAG, "Proxy not attached to service");
|
||||
return toDeviceSet(new BluetoothDevice[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public int getConnectionState(BluetoothDevice device) {
|
||||
if (DBG) log("getState(" + device + ")");
|
||||
if (mService != null && isEnabled()
|
||||
&& isValidDevice(device)) {
|
||||
try {
|
||||
return mService.getConnectionState(device);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
|
||||
return BluetoothProfile.STATE_DISCONNECTED;
|
||||
}
|
||||
}
|
||||
if (mService == null) Log.w(TAG, "Proxy not attached to service");
|
||||
return BluetoothProfile.STATE_DISCONNECTED;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @hide
|
||||
*/
|
||||
public boolean setPriority(BluetoothDevice device, int priority) {
|
||||
if (DBG) log("setPriority(" + device + ", " + priority + ")");
|
||||
if (mService != null && isEnabled()
|
||||
&& isValidDevice(device)) {
|
||||
if (priority != BluetoothProfile.PRIORITY_OFF &&
|
||||
priority != BluetoothProfile.PRIORITY_ON) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
return mService.setPriority(device, priority);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (mService == null) Log.w(TAG, "Proxy not attached to service");
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @hide
|
||||
*/
|
||||
public int getPriority(BluetoothDevice device) {
|
||||
if (DBG) log("getPriority(" + device + ")");
|
||||
if (mService != null && isEnabled()
|
||||
&& isValidDevice(device)) {
|
||||
try {
|
||||
return mService.getPriority(device);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
|
||||
return BluetoothProfile.PRIORITY_OFF;
|
||||
}
|
||||
}
|
||||
if (mService == null) Log.w(TAG, "Proxy not attached to service");
|
||||
return BluetoothProfile.PRIORITY_OFF;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if A2DP profile is streaming music.
|
||||
*
|
||||
* <p>Requires {@link android.Manifest.permission#BLUETOOTH}
|
||||
*
|
||||
* @param device BluetoothDevice device
|
||||
*/
|
||||
public boolean isA2dpPlaying(BluetoothDevice device) {
|
||||
if (mService != null && isEnabled()
|
||||
&& isValidDevice(device)) {
|
||||
try {
|
||||
return mService.isA2dpPlaying(device);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (mService == null) Log.w(TAG, "Proxy not attached to service");
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initiate suspend from an A2DP sink.
|
||||
*
|
||||
* <p> This API will return false in scenarios like the A2DP
|
||||
* device is not in connected state etc. When this API returns,
|
||||
* true, it is guaranteed that {@link #ACTION_SINK_STATE_CHANGED}
|
||||
* intent will be broadcasted with the state. Users can get the
|
||||
* state of the A2DP device from this intent.
|
||||
*
|
||||
* <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
|
||||
*
|
||||
* @param device Remote A2DP sink
|
||||
* @return false on immediate error,
|
||||
* true otherwise
|
||||
* @hide
|
||||
*/
|
||||
public boolean suspendSink(BluetoothDevice device) {
|
||||
try {
|
||||
return mService.suspendSink(device);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "", e);
|
||||
return false;
|
||||
if (mService != null && isEnabled()
|
||||
&& isValidDevice(device)) {
|
||||
try {
|
||||
return mService.suspendSink(device);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (mService == null) Log.w(TAG, "Proxy not attached to service");
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Initiate resume from an suspended A2DP sink.
|
||||
* Listen for SINK_STATE_CHANGED_ACTION to find out when
|
||||
* resume is completed.
|
||||
* @param device Remote BT device.
|
||||
* @return false on immediate error, true otherwise
|
||||
* @hide
|
||||
/**
|
||||
* Initiate resume from a suspended A2DP sink.
|
||||
*
|
||||
* <p> This API will return false in scenarios like the A2DP
|
||||
* device is not in suspended state etc. When this API returns,
|
||||
* true, it is guaranteed that {@link #ACTION_SINK_STATE_CHANGED}
|
||||
* intent will be broadcasted with the state. Users can get the
|
||||
* state of the A2DP device from this intent.
|
||||
*
|
||||
* <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
|
||||
*
|
||||
* @param device Remote A2DP sink
|
||||
* @return false on immediate error,
|
||||
* true otherwise
|
||||
* @hide
|
||||
*/
|
||||
public boolean resumeSink(BluetoothDevice device) {
|
||||
try {
|
||||
return mService.resumeSink(device);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "", e);
|
||||
return false;
|
||||
if (mService != null && isEnabled()
|
||||
&& isValidDevice(device)) {
|
||||
try {
|
||||
return mService.resumeSink(device);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (mService == null) Log.w(TAG, "Proxy not attached to service");
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Check if a specified A2DP sink is connected.
|
||||
* @param device Remote BT device.
|
||||
* @return True if connected (or playing), false otherwise and on error.
|
||||
* @hide
|
||||
*/
|
||||
public boolean isSinkConnected(BluetoothDevice device) {
|
||||
if (DBG) log("isSinkConnected(" + device + ")");
|
||||
int state = getSinkState(device);
|
||||
return state == STATE_CONNECTED || state == STATE_PLAYING;
|
||||
}
|
||||
|
||||
/** Check if any A2DP sink is connected.
|
||||
* @return a unmodifiable set of connected A2DP sinks, or null on error.
|
||||
* @hide
|
||||
*/
|
||||
public Set<BluetoothDevice> getConnectedSinks() {
|
||||
if (DBG) log("getConnectedSinks()");
|
||||
try {
|
||||
return Collections.unmodifiableSet(
|
||||
new HashSet<BluetoothDevice>(Arrays.asList(mService.getConnectedSinks())));
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/** Check if any A2DP sink is in Non Disconnected state
|
||||
* i.e playing, connected, connecting, disconnecting.
|
||||
* @return a unmodifiable set of connected A2DP sinks, or null on error.
|
||||
* @hide
|
||||
*/
|
||||
public Set<BluetoothDevice> getNonDisconnectedSinks() {
|
||||
if (DBG) log("getNonDisconnectedSinks()");
|
||||
try {
|
||||
return Collections.unmodifiableSet(
|
||||
new HashSet<BluetoothDevice>(Arrays.asList(mService.getNonDisconnectedSinks())));
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/** Get the state of an A2DP sink
|
||||
* @param device Remote BT device.
|
||||
* @return State code, one of STATE_
|
||||
* @hide
|
||||
*/
|
||||
public int getSinkState(BluetoothDevice device) {
|
||||
if (DBG) log("getSinkState(" + device + ")");
|
||||
try {
|
||||
return mService.getSinkState(device);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "", e);
|
||||
return BluetoothA2dp.STATE_DISCONNECTED;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set priority of a2dp sink.
|
||||
* Priority is a non-negative integer. By default paired sinks will have
|
||||
* a priority of PRIORITY_AUTO, and unpaired headset PRIORITY_NONE (0).
|
||||
* Sinks with priority greater than zero will accept incoming connections
|
||||
* (if no sink is currently connected).
|
||||
* Priority for unpaired sink must be PRIORITY_NONE.
|
||||
* @param device Paired sink
|
||||
* @param priority Integer priority, for example PRIORITY_AUTO or
|
||||
* PRIORITY_NONE
|
||||
* @return true if priority is set, false on error
|
||||
*/
|
||||
public boolean setSinkPriority(BluetoothDevice device, int priority) {
|
||||
if (DBG) log("setSinkPriority(" + device + ", " + priority + ")");
|
||||
try {
|
||||
return mService.setSinkPriority(device, priority);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get priority of a2dp sink.
|
||||
* @param device Sink
|
||||
* @return non-negative priority, or negative error code on error.
|
||||
*/
|
||||
public int getSinkPriority(BluetoothDevice device) {
|
||||
if (DBG) log("getSinkPriority(" + device + ")");
|
||||
try {
|
||||
return mService.getSinkPriority(device);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "", e);
|
||||
return PRIORITY_OFF;
|
||||
}
|
||||
}
|
||||
|
||||
/** Helper for converting a state to a string.
|
||||
/**
|
||||
* Helper for converting a state to a string.
|
||||
*
|
||||
* For debug use only - strings are not internationalized.
|
||||
* @hide
|
||||
*/
|
||||
@@ -285,12 +356,31 @@ public final class BluetoothA2dp {
|
||||
return "disconnecting";
|
||||
case STATE_PLAYING:
|
||||
return "playing";
|
||||
case STATE_NOT_PLAYING:
|
||||
return "not playing";
|
||||
default:
|
||||
return "<unknown state " + state + ">";
|
||||
}
|
||||
}
|
||||
|
||||
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 Set<BluetoothDevice> toDeviceSet(BluetoothDevice[] devices) {
|
||||
return Collections.unmodifiableSet(
|
||||
new HashSet<BluetoothDevice>(Arrays.asList(devices)));
|
||||
}
|
||||
|
||||
private static void log(String msg) {
|
||||
Log.d(TAG, msg);
|
||||
Log.d(TAG, msg);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ package android.bluetooth;
|
||||
|
||||
import android.annotation.SdkConstant;
|
||||
import android.annotation.SdkConstant.SdkConstantType;
|
||||
import android.content.Context;
|
||||
import android.os.Binder;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
@@ -279,6 +280,61 @@ public final class BluetoothAdapter {
|
||||
*/
|
||||
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 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.
|
||||
*
|
||||
* <p> 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.
|
||||
*
|
||||
* <p>This intent will have 3 extras:
|
||||
* {@link #EXTRA_STATE} - The current state.
|
||||
* {@link #EXTRA_PREVIOUS_STATE}- The previous.
|
||||
* {@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}.
|
||||
*
|
||||
* <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
|
||||
*/
|
||||
@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";
|
||||
|
||||
/** The profile is in disconnected state */
|
||||
public static final int STATE_DISCONNECTED = 0;
|
||||
/** The profile is in connecting state */
|
||||
public static final int STATE_CONNECTING = 1;
|
||||
/** The profile is in connected state */
|
||||
public static final int STATE_CONNECTED = 2;
|
||||
/** The profile is in disconnecting state */
|
||||
public static final int STATE_DISCONNECTING = 3;
|
||||
|
||||
/** @hide */
|
||||
public static final String BLUETOOTH_SERVICE = "bluetooth";
|
||||
|
||||
@@ -896,6 +952,54 @@ public final class BluetoothAdapter {
|
||||
return null;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the profile proxy object associated with the profile.
|
||||
*
|
||||
* <p>Profile can be one of {@link BluetoothProfile.HEADSET} or
|
||||
* {@link BluetoothProfile.A2DP}. Clients must implements
|
||||
* {@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
|
||||
* @return true on success, false on error
|
||||
*/
|
||||
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);
|
||||
return true;
|
||||
} else if (profile == BluetoothProfile.A2DP) {
|
||||
BluetoothA2dp a2dp = new BluetoothA2dp(context, listener);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the connection of the profile proxy to the Service.
|
||||
*
|
||||
* <p> 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
|
||||
*/
|
||||
public void closeProfileProxy(int profile, BluetoothProfile proxy) {
|
||||
if (profile == BluetoothProfile.HEADSET) {
|
||||
BluetoothHeadset headset = (BluetoothHeadset)proxy;
|
||||
if (headset != null) {
|
||||
headset.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Set<BluetoothDevice> toDeviceSet(String[] addresses) {
|
||||
Set<BluetoothDevice> devices = new HashSet<BluetoothDevice>(addresses.length);
|
||||
for (int i = 0; i < addresses.length; i++) {
|
||||
|
||||
@@ -18,6 +18,8 @@ package android.bluetooth;
|
||||
|
||||
import android.annotation.SdkConstant;
|
||||
import android.annotation.SdkConstant.SdkConstantType;
|
||||
import android.bluetooth.BluetoothAdapter;
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
@@ -26,63 +28,66 @@ import android.os.RemoteException;
|
||||
import android.os.IBinder;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* The Android Bluetooth API is not finalized, and *will* change. Use at your
|
||||
* own risk.
|
||||
*
|
||||
* Public API for controlling the Bluetooth Headset Service. This includes both
|
||||
* Bluetooth Headset and Handsfree (v1.5) profiles. The Headset service will
|
||||
* attempt a handsfree connection first, and fall back to headset.
|
||||
* Bluetooth Headset and Handsfree (v1.5) profiles.
|
||||
*
|
||||
* BluetoothHeadset is a proxy object for controlling the Bluetooth Headset
|
||||
* <p>BluetoothHeadset is a proxy object for controlling the Bluetooth Headset
|
||||
* Service via IPC.
|
||||
*
|
||||
* Creating a BluetoothHeadset object will create a binding with the
|
||||
* BluetoothHeadset service. Users of this object should call close() when they
|
||||
* are finished with the BluetoothHeadset, so that this proxy object can unbind
|
||||
* from the service.
|
||||
* <p> Use {@link BluetoothAdapter#getProfileProxy} to get
|
||||
* the BluetoothHeadset proxy object. Use
|
||||
* {@link BluetoothAdapter#closeProfileProxy} to close the service connection.
|
||||
*
|
||||
* This BluetoothHeadset object is not immediately bound to the
|
||||
* BluetoothHeadset 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 BluetoothHeadset after construction.
|
||||
*
|
||||
* Android only supports one connected Bluetooth Headset at a time.
|
||||
*
|
||||
* @hide
|
||||
* <p> Android only supports one connected Bluetooth Headset at a time.
|
||||
* Each method is protected with its appropriate permission.
|
||||
*/
|
||||
public final class BluetoothHeadset {
|
||||
|
||||
public final class BluetoothHeadset implements BluetoothProfile {
|
||||
private static final String TAG = "BluetoothHeadset";
|
||||
private static final boolean DBG = false;
|
||||
|
||||
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
|
||||
public static final String ACTION_STATE_CHANGED =
|
||||
"android.bluetooth.headset.action.STATE_CHANGED";
|
||||
/**
|
||||
* TODO(API release): Consider incorporating as new state in
|
||||
* HEADSET_STATE_CHANGED
|
||||
* Intent used to broadcast the change in connection state of the Headset
|
||||
* profile.
|
||||
*
|
||||
* <p>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}.
|
||||
*
|
||||
* <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
|
||||
*/
|
||||
@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
|
||||
* A2DP profile.
|
||||
*
|
||||
* <p>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},
|
||||
*
|
||||
* <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
|
||||
*/
|
||||
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
|
||||
public static final String ACTION_AUDIO_STATE_CHANGED =
|
||||
"android.bluetooth.headset.action.AUDIO_STATE_CHANGED";
|
||||
public static final String EXTRA_STATE =
|
||||
"android.bluetooth.headset.extra.STATE";
|
||||
public static final String EXTRA_PREVIOUS_STATE =
|
||||
"android.bluetooth.headset.extra.PREVIOUS_STATE";
|
||||
public static final String EXTRA_AUDIO_STATE =
|
||||
"android.bluetooth.headset.extra.AUDIO_STATE";
|
||||
"android.bluetooth.headset.profile.action.AUDIO_STATE_CHANGED";
|
||||
|
||||
/** Extra to be used with the Headset State change intent.
|
||||
* This will be used only when Headset state changes to
|
||||
* {@link #STATE_DISCONNECTED} from any previous state.
|
||||
* This extra field is optional and will be used when
|
||||
* we have deterministic information regarding whether
|
||||
* the disconnect was initiated by the remote device or
|
||||
* by the local adapter.
|
||||
*/
|
||||
public static final String EXTRA_DISCONNECT_INITIATOR =
|
||||
"android.bluetooth.headset.extra.DISCONNECT_INITIATOR";
|
||||
|
||||
/**
|
||||
* Broadcast Action: Indicates a headset has posted a vendor-specific event.
|
||||
@@ -124,100 +129,47 @@ public final class BluetoothHeadset {
|
||||
public static final String EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_ARGS =
|
||||
"android.bluetooth.headset.extra.VENDOR_SPECIFIC_HEADSET_EVENT_ARGS";
|
||||
|
||||
/*
|
||||
* 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 = 10;
|
||||
|
||||
/**
|
||||
* TODO(API release): Consider incorporating as new state in
|
||||
* HEADSET_STATE_CHANGED
|
||||
* 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 = 11;
|
||||
|
||||
|
||||
private Context mContext;
|
||||
private ServiceListener mServiceListener;
|
||||
private IBluetoothHeadset mService;
|
||||
private final Context mContext;
|
||||
private final ServiceListener mServiceListener;
|
||||
|
||||
/** There was an error trying to obtain the state */
|
||||
public static final int STATE_ERROR = -1;
|
||||
/** No headset currently connected */
|
||||
public static final int STATE_DISCONNECTED = 0;
|
||||
/** Connection attempt in progress */
|
||||
public static final int STATE_CONNECTING = 1;
|
||||
/** A headset is currently connected */
|
||||
public static final int STATE_CONNECTED = 2;
|
||||
|
||||
/** A SCO audio channel is not established */
|
||||
public static final int AUDIO_STATE_DISCONNECTED = 0;
|
||||
/** A SCO audio channel is established */
|
||||
public static final int AUDIO_STATE_CONNECTED = 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;
|
||||
|
||||
/** Values for {@link #EXTRA_DISCONNECT_INITIATOR} */
|
||||
public static final int REMOTE_DISCONNECT = 0;
|
||||
public static final int LOCAL_DISCONNECT = 1;
|
||||
|
||||
|
||||
/** Default priority for headsets that for which we will accept
|
||||
* inconing connections and auto-connect */
|
||||
public static final int PRIORITY_AUTO_CONNECT = 1000;
|
||||
/** Default priority for headsets that for which we will accept
|
||||
* inconing connections but not auto-connect */
|
||||
public static final int PRIORITY_ON = 100;
|
||||
/** Default priority for headsets that should not be auto-connected
|
||||
* and not allow incoming connections. */
|
||||
public static final int PRIORITY_OFF = 0;
|
||||
/** Default priority when not set or when the device is unpaired */
|
||||
public static final int PRIORITY_UNDEFINED = -1;
|
||||
|
||||
/**
|
||||
* An interface for notifying BluetoothHeadset IPC clients when they have
|
||||
* been connected to the BluetoothHeadset service.
|
||||
*/
|
||||
public interface ServiceListener {
|
||||
/**
|
||||
* Called to notify the client when this proxy object has been
|
||||
* connected to the BluetoothHeadset service. Clients must wait for
|
||||
* this callback before making IPC calls on the BluetoothHeadset
|
||||
* service.
|
||||
*/
|
||||
public void onServiceConnected();
|
||||
|
||||
/**
|
||||
* Called to notify the client that this proxy object has been
|
||||
* disconnected from the BluetoothHeadset service. Clients must not
|
||||
* make IPC calls on the BluetoothHeadset service after this callback.
|
||||
* This callback will currently only occur if the application hosting
|
||||
* the BluetoothHeadset service, but may be called more often in future.
|
||||
*/
|
||||
public void onServiceDisconnected();
|
||||
}
|
||||
BluetoothAdapter mAdapter;
|
||||
|
||||
/**
|
||||
* Create a BluetoothHeadset proxy object.
|
||||
*/
|
||||
public BluetoothHeadset(Context context, ServiceListener l) {
|
||||
/*package*/ BluetoothHeadset(Context context, ServiceListener l) {
|
||||
mContext = context;
|
||||
mServiceListener = l;
|
||||
mAdapter = BluetoothAdapter.getDefaultAdapter();
|
||||
if (!context.bindService(new Intent(IBluetoothHeadset.class.getName()), mConnection, 0)) {
|
||||
Log.e(TAG, "Could not bind to Bluetooth Headset Service");
|
||||
}
|
||||
}
|
||||
|
||||
protected void finalize() throws Throwable {
|
||||
try {
|
||||
close();
|
||||
} finally {
|
||||
super.finalize();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
public synchronized void close() {
|
||||
/*package*/ synchronized void close() {
|
||||
if (DBG) log("close()");
|
||||
if (mConnection != null) {
|
||||
mContext.unbindService(mConnection);
|
||||
@@ -226,190 +178,212 @@ public final class BluetoothHeadset {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current state of the Bluetooth Headset service.
|
||||
* @return One of the STATE_ return codes, or STATE_ERROR if this proxy
|
||||
* object is currently not connected to the Headset service.
|
||||
* {@inheritDoc}
|
||||
* @hide
|
||||
*/
|
||||
public int getState(BluetoothDevice device) {
|
||||
if (DBG) log("getState()");
|
||||
if (mService != null) {
|
||||
public boolean connect(BluetoothDevice device) {
|
||||
if (DBG) log("connect(" + device + ")");
|
||||
if (mService != null && isEnabled() &&
|
||||
isValidDevice(device)) {
|
||||
try {
|
||||
return mService.getState(device);
|
||||
} catch (RemoteException e) {Log.e(TAG, e.toString());}
|
||||
} else {
|
||||
Log.w(TAG, "Proxy not attached to service");
|
||||
if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
|
||||
}
|
||||
return BluetoothHeadset.STATE_ERROR;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the BluetoothDevice for the current headset.
|
||||
* @return current headset, or null if not in connected or connecting
|
||||
* state, or if this proxy object is not connected to the Headset
|
||||
* service.
|
||||
*/
|
||||
public BluetoothDevice getCurrentHeadset() {
|
||||
if (DBG) log("getCurrentHeadset()");
|
||||
if (mService != null) {
|
||||
try {
|
||||
return mService.getCurrentHeadset();
|
||||
} catch (RemoteException e) {Log.e(TAG, e.toString());}
|
||||
} else {
|
||||
Log.w(TAG, "Proxy not attached to service");
|
||||
if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Request to initiate a connection to a headset.
|
||||
* This call does not block. Fails if a headset is already connecting
|
||||
* or connected.
|
||||
* Initiates auto-connection if device is null. Tries to connect to all
|
||||
* devices with priority greater than PRIORITY_AUTO in descending order.
|
||||
* @param device device to connect to, or null to auto-connect last connected
|
||||
* headset
|
||||
* @return false if there was a problem initiating the connection
|
||||
* procedure, and no further HEADSET_STATE_CHANGED intents
|
||||
* will be expected.
|
||||
*/
|
||||
public boolean connectHeadset(BluetoothDevice device) {
|
||||
if (DBG) log("connectHeadset(" + device + ")");
|
||||
if (mService != null) {
|
||||
try {
|
||||
if (mService.connectHeadset(device)) {
|
||||
return true;
|
||||
}
|
||||
} catch (RemoteException e) {Log.e(TAG, e.toString());}
|
||||
} else {
|
||||
Log.w(TAG, "Proxy not attached to service");
|
||||
if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
|
||||
return mService.connect(device);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, Log.getStackTraceString(new Throwable()));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (mService == null) Log.w(TAG, "Proxy not attached to service");
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the specified headset is connected (does not include
|
||||
* connecting). Returns false if not connected, or if this proxy object
|
||||
* if not currently connected to the headset service.
|
||||
* {@inheritDoc}
|
||||
* @hide
|
||||
*/
|
||||
public boolean isConnected(BluetoothDevice device) {
|
||||
if (DBG) log("isConnected(" + device + ")");
|
||||
if (mService != null) {
|
||||
public boolean disconnect(BluetoothDevice device) {
|
||||
if (DBG) log("disconnect(" + device + ")");
|
||||
if (mService != null && isEnabled() &&
|
||||
isValidDevice(device)) {
|
||||
try {
|
||||
return mService.isConnected(device);
|
||||
} catch (RemoteException e) {Log.e(TAG, e.toString());}
|
||||
} else {
|
||||
Log.w(TAG, "Proxy not attached to service");
|
||||
if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
|
||||
return mService.disconnect(device);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, Log.getStackTraceString(new Throwable()));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (mService == null) Log.w(TAG, "Proxy not attached to service");
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disconnects the current headset. Currently this call blocks, it may soon
|
||||
* be made asynchornous. Returns false if this proxy object is
|
||||
* not currently connected to the Headset service.
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public boolean disconnectHeadset(BluetoothDevice device) {
|
||||
if (DBG) log("disconnectHeadset()");
|
||||
if (mService != null) {
|
||||
public Set<BluetoothDevice> getConnectedDevices() {
|
||||
if (DBG) log("getConnectedDevices()");
|
||||
if (mService != null && isEnabled()) {
|
||||
try {
|
||||
mService.disconnectHeadset(device);
|
||||
return true;
|
||||
} catch (RemoteException e) {Log.e(TAG, e.toString());}
|
||||
} else {
|
||||
Log.w(TAG, "Proxy not attached to service");
|
||||
if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
|
||||
return toDeviceSet(mService.getConnectedDevices());
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, Log.getStackTraceString(new Throwable()));
|
||||
return toDeviceSet(new BluetoothDevice[0]);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
if (mService == null) Log.w(TAG, "Proxy not attached to service");
|
||||
return toDeviceSet(new BluetoothDevice[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Start BT Voice Recognition mode, and set up Bluetooth audio path.
|
||||
* Returns false if there is no headset connected, or if the
|
||||
* connected headset does not support voice recognition, or on
|
||||
* error.
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public boolean startVoiceRecognition() {
|
||||
if (DBG) log("startVoiceRecognition()");
|
||||
if (mService != null) {
|
||||
public Set<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
|
||||
if (DBG) log("getDevicesMatchingStates()");
|
||||
if (mService != null && isEnabled()) {
|
||||
try {
|
||||
return mService.startVoiceRecognition();
|
||||
} catch (RemoteException e) {Log.e(TAG, e.toString());}
|
||||
} else {
|
||||
Log.w(TAG, "Proxy not attached to service");
|
||||
if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
|
||||
return toDeviceSet(mService.getDevicesMatchingConnectionStates(states));
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, Log.getStackTraceString(new Throwable()));
|
||||
return toDeviceSet(new BluetoothDevice[0]);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
if (mService == null) Log.w(TAG, "Proxy not attached to service");
|
||||
return toDeviceSet(new BluetoothDevice[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop BT Voice Recognition mode, and shut down Bluetooth audio path.
|
||||
* Returns false if there is no headset connected, or the connected
|
||||
* headset is not in voice recognition mode, or on error.
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public boolean stopVoiceRecognition() {
|
||||
if (DBG) log("stopVoiceRecognition()");
|
||||
if (mService != null) {
|
||||
public int getConnectionState(BluetoothDevice device) {
|
||||
if (DBG) log("getConnectionState(" + device + ")");
|
||||
if (mService != null && isEnabled() &&
|
||||
isValidDevice(device)) {
|
||||
try {
|
||||
return mService.stopVoiceRecognition();
|
||||
} catch (RemoteException e) {Log.e(TAG, e.toString());}
|
||||
} else {
|
||||
Log.w(TAG, "Proxy not attached to service");
|
||||
if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
|
||||
return mService.getConnectionState(device);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, Log.getStackTraceString(new Throwable()));
|
||||
return BluetoothProfile.STATE_DISCONNECTED;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
if (mService == null) Log.w(TAG, "Proxy not attached to service");
|
||||
return BluetoothProfile.STATE_DISCONNECTED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set priority of headset.
|
||||
* Priority is a non-negative integer. By default paired headsets will have
|
||||
* a priority of PRIORITY_AUTO, and unpaired headset PRIORITY_NONE (0).
|
||||
* Headsets with priority greater than zero will be auto-connected, and
|
||||
* incoming connections will be accepted (if no other headset is
|
||||
* connected).
|
||||
* Auto-connection occurs at the following events: boot, incoming phone
|
||||
* call, outgoing phone call.
|
||||
* Headsets with priority equal to zero, or that are unpaired, are not
|
||||
* auto-connected.
|
||||
* Incoming connections are ignored regardless of priority if there is
|
||||
* already a headset connected.
|
||||
* @param device paired headset
|
||||
* @param priority Integer priority, for example PRIORITY_AUTO or
|
||||
* PRIORITY_NONE
|
||||
* @return true if successful, false if there was some error
|
||||
* {@inheritDoc}
|
||||
* @hide
|
||||
*/
|
||||
public boolean setPriority(BluetoothDevice device, int priority) {
|
||||
if (DBG) log("setPriority(" + device + ", " + priority + ")");
|
||||
if (mService != null) {
|
||||
if (mService != null && isEnabled() &&
|
||||
isValidDevice(device)) {
|
||||
if (priority != BluetoothProfile.PRIORITY_OFF &&
|
||||
priority != BluetoothProfile.PRIORITY_ON) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
return mService.setPriority(device, priority);
|
||||
} catch (RemoteException e) {Log.e(TAG, e.toString());}
|
||||
} else {
|
||||
Log.w(TAG, "Proxy not attached to service");
|
||||
if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, Log.getStackTraceString(new Throwable()));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (mService == null) Log.w(TAG, "Proxy not attached to service");
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get priority of headset.
|
||||
* @param device headset
|
||||
* @return non-negative priority, or negative error code on error
|
||||
* {@inheritDoc}
|
||||
* @hide
|
||||
*/
|
||||
public int getPriority(BluetoothDevice device) {
|
||||
if (DBG) log("getPriority(" + device + ")");
|
||||
if (mService != null) {
|
||||
if (mService != null && isEnabled() &&
|
||||
isValidDevice(device)) {
|
||||
try {
|
||||
return mService.getPriority(device);
|
||||
} catch (RemoteException e) {Log.e(TAG, e.toString());}
|
||||
} else {
|
||||
Log.w(TAG, "Proxy not attached to service");
|
||||
if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, Log.getStackTraceString(new Throwable()));
|
||||
return PRIORITY_OFF;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
if (mService == null) Log.w(TAG, "Proxy not attached to service");
|
||||
return PRIORITY_OFF;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start Bluetooth voice recognition. This methods sends the voice
|
||||
* recognition AT command to the headset and establishes the
|
||||
* audio connection.
|
||||
*
|
||||
* <p> Users can listen to {@link #ACTION_AUDIO_STATE_CHANGED}.
|
||||
* {@link #EXTRA_STATE} will be set to {@link #STATE_AUDIO_CONNECTED}
|
||||
* when the audio connection is established.
|
||||
*
|
||||
* <p>Requires {@link android.Manifest.permission#BLUETOOTH}
|
||||
*
|
||||
* @param device Bluetooth headset
|
||||
* @return false if there is no headset connected of if the
|
||||
* connected headset doesn't support voice recognition
|
||||
* or on error, true otherwise
|
||||
*/
|
||||
public boolean startVoiceRecognition(BluetoothDevice device) {
|
||||
if (DBG) log("startVoiceRecognition()");
|
||||
if (mService != null && isEnabled() &&
|
||||
isValidDevice(device)) {
|
||||
try {
|
||||
return mService.startVoiceRecognition(device);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, Log.getStackTraceString(new Throwable()));
|
||||
}
|
||||
}
|
||||
if (mService == null) Log.w(TAG, "Proxy not attached to service");
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop Bluetooth Voice Recognition mode, and shut down the
|
||||
* Bluetooth audio path.
|
||||
*
|
||||
* <p>Requires {@link android.Manifest.permission#BLUETOOTH}
|
||||
*
|
||||
* @param device Bluetooth headset
|
||||
* @return false if there is no headset connected
|
||||
* or on error, true otherwise
|
||||
*/
|
||||
public boolean stopVoiceRecognition(BluetoothDevice device) {
|
||||
if (DBG) log("stopVoiceRecognition()");
|
||||
if (mService != null && isEnabled() &&
|
||||
isValidDevice(device)) {
|
||||
try {
|
||||
return mService.stopVoiceRecognition(device);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, Log.getStackTraceString(new Throwable()));
|
||||
}
|
||||
}
|
||||
if (mService == null) Log.w(TAG, "Proxy not attached to service");
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if Bluetooth SCO audio is connected.
|
||||
*
|
||||
* <p>Requires {@link android.Manifest.permission#BLUETOOTH}
|
||||
*
|
||||
* @param device Bluetooth headset
|
||||
* @return true if SCO is connected,
|
||||
* false otherwise or on error
|
||||
*/
|
||||
public boolean isAudioConnected(BluetoothDevice device) {
|
||||
if (DBG) log("isAudioConnected()");
|
||||
if (mService != null && isEnabled() &&
|
||||
isValidDevice(device)) {
|
||||
try {
|
||||
return mService.isAudioConnected(device);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, Log.getStackTraceString(new Throwable()));
|
||||
}
|
||||
}
|
||||
if (mService == null) Log.w(TAG, "Proxy not attached to service");
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -420,24 +394,29 @@ public final class BluetoothHeadset {
|
||||
* boot. This is a good indicator for spammy headset/handsfree units that
|
||||
* can keep the device awake by polling for cellular status updates. As a
|
||||
* rule of thumb, each AT command prevents the CPU from sleeping for 500 ms
|
||||
*
|
||||
* @param device the bluetooth headset.
|
||||
* @return monotonically increasing battery usage hint, or a negative error
|
||||
* code on error
|
||||
* @hide
|
||||
*/
|
||||
public int getBatteryUsageHint() {
|
||||
public int getBatteryUsageHint(BluetoothDevice device) {
|
||||
if (DBG) log("getBatteryUsageHint()");
|
||||
if (mService != null) {
|
||||
if (mService != null && isEnabled() &&
|
||||
isValidDevice(device)) {
|
||||
try {
|
||||
return mService.getBatteryUsageHint();
|
||||
} catch (RemoteException e) {Log.e(TAG, e.toString());}
|
||||
} else {
|
||||
Log.w(TAG, "Proxy not attached to service");
|
||||
if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
|
||||
return mService.getBatteryUsageHint(device);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, Log.getStackTraceString(new Throwable()));
|
||||
}
|
||||
}
|
||||
if (mService == null) Log.w(TAG, "Proxy not attached to service");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if current platform supports voice dialing over bluetooth SCO.
|
||||
*
|
||||
* @return true if voice dialing over bluetooth is supported, false otherwise.
|
||||
* @hide
|
||||
*/
|
||||
@@ -448,11 +427,13 @@ public final class BluetoothHeadset {
|
||||
|
||||
/**
|
||||
* Cancel the outgoing connection.
|
||||
* Note: This is an internal function and shouldn't be exposed
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public boolean cancelConnectThread() {
|
||||
if (DBG) log("cancelConnectThread");
|
||||
if (mService != null) {
|
||||
if (mService != null && isEnabled()) {
|
||||
try {
|
||||
return mService.cancelConnectThread();
|
||||
} catch (RemoteException e) {Log.e(TAG, e.toString());}
|
||||
@@ -465,11 +446,13 @@ public final class BluetoothHeadset {
|
||||
|
||||
/**
|
||||
* Accept the incoming connection.
|
||||
* Note: This is an internal function and shouldn't be exposed
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public boolean acceptIncomingConnect(BluetoothDevice device) {
|
||||
if (DBG) log("acceptIncomingConnect");
|
||||
if (mService != null) {
|
||||
if (mService != null && isEnabled()) {
|
||||
try {
|
||||
return mService.acceptIncomingConnect(device);
|
||||
} catch (RemoteException e) {Log.e(TAG, e.toString());}
|
||||
@@ -481,12 +464,14 @@ public final class BluetoothHeadset {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the connect thread the incoming connection.
|
||||
* Create the connect thread for the incoming connection.
|
||||
* Note: This is an internal function and shouldn't be exposed
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public boolean createIncomingConnect(BluetoothDevice device) {
|
||||
if (DBG) log("createIncomingConnect");
|
||||
if (mService != null) {
|
||||
if (mService != null && isEnabled()) {
|
||||
try {
|
||||
return mService.createIncomingConnect(device);
|
||||
} catch (RemoteException e) {Log.e(TAG, e.toString());}
|
||||
@@ -500,11 +485,12 @@ public final class BluetoothHeadset {
|
||||
/**
|
||||
* Connect to a Bluetooth Headset.
|
||||
* Note: This is an internal function and shouldn't be exposed
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public boolean connectHeadsetInternal(BluetoothDevice device) {
|
||||
if (DBG) log("connectHeadsetInternal");
|
||||
if (mService != null) {
|
||||
if (mService != null && isEnabled()) {
|
||||
try {
|
||||
return mService.connectHeadsetInternal(device);
|
||||
} catch (RemoteException e) {Log.e(TAG, e.toString());}
|
||||
@@ -518,11 +504,12 @@ public final class BluetoothHeadset {
|
||||
/**
|
||||
* Disconnect a Bluetooth Headset.
|
||||
* Note: This is an internal function and shouldn't be exposed
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public boolean disconnectHeadsetInternal(BluetoothDevice device) {
|
||||
if (DBG) log("disconnectHeadsetInternal");
|
||||
if (mService != null) {
|
||||
if (mService != null && isEnabled()) {
|
||||
try {
|
||||
return mService.disconnectHeadsetInternal(device);
|
||||
} catch (RemoteException e) {Log.e(TAG, e.toString());}
|
||||
@@ -532,23 +519,61 @@ public final class BluetoothHeadset {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the audio state of the Headset.
|
||||
* Note: This is an internal function and shouldn't be exposed
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public boolean setAudioState(BluetoothDevice device, int state) {
|
||||
if (DBG) log("setAudioState");
|
||||
if (mService != null && isEnabled()) {
|
||||
try {
|
||||
return mService.setAudioState(device, state);
|
||||
} catch (RemoteException e) {Log.e(TAG, e.toString());}
|
||||
} else {
|
||||
Log.w(TAG, "Proxy not attached to service");
|
||||
if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private ServiceConnection mConnection = new ServiceConnection() {
|
||||
public void onServiceConnected(ComponentName className, IBinder service) {
|
||||
if (DBG) Log.d(TAG, "Proxy object connected");
|
||||
mService = IBluetoothHeadset.Stub.asInterface(service);
|
||||
|
||||
if (mServiceListener != null) {
|
||||
mServiceListener.onServiceConnected();
|
||||
mServiceListener.onServiceConnected(BluetoothProfile.HEADSET, BluetoothHeadset.this);
|
||||
}
|
||||
}
|
||||
public void onServiceDisconnected(ComponentName className) {
|
||||
if (DBG) Log.d(TAG, "Proxy object disconnected");
|
||||
mService = null;
|
||||
if (mServiceListener != null) {
|
||||
mServiceListener.onServiceDisconnected();
|
||||
mServiceListener.onServiceDisconnected(BluetoothProfile.HEADSET);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
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 Set<BluetoothDevice> toDeviceSet(BluetoothDevice[] devices) {
|
||||
return Collections.unmodifiableSet(
|
||||
new HashSet<BluetoothDevice>(Arrays.asList(devices)));
|
||||
}
|
||||
|
||||
private static void log(String msg) {
|
||||
Log.d(TAG, msg);
|
||||
}
|
||||
|
||||
239
core/java/android/bluetooth/BluetoothProfile.java
Normal file
239
core/java/android/bluetooth/BluetoothProfile.java
Normal file
@@ -0,0 +1,239 @@
|
||||
/*
|
||||
* 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.annotation.SdkConstant;
|
||||
import android.annotation.SdkConstant.SdkConstantType;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Public APIs for the Bluetooth Profiles.
|
||||
*
|
||||
* <p> 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.
|
||||
*/
|
||||
public static final 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.
|
||||
*/
|
||||
public static final String EXTRA_PREVIOUS_STATE =
|
||||
"android.bluetooth.profile.extra.PREVIOUS_STATE";
|
||||
|
||||
/** The profile is in disconnected state */
|
||||
public static final int STATE_DISCONNECTED = 0;
|
||||
/** The profile is in connecting state */
|
||||
public static final int STATE_CONNECTING = 1;
|
||||
/** The profile is in connected state */
|
||||
public static final int STATE_CONNECTED = 2;
|
||||
/** The profile is in disconnecting state */
|
||||
public static final int STATE_DISCONNECTING = 3;
|
||||
|
||||
/**
|
||||
* Headset and Handsfree profile
|
||||
*/
|
||||
public static final int HEADSET = 1;
|
||||
/**
|
||||
* A2DP profile.
|
||||
*/
|
||||
public static final int A2DP = 2;
|
||||
|
||||
/**
|
||||
* Default priority for devices that we try to auto-connect to and
|
||||
* and allow incoming connections for the profile
|
||||
* @hide
|
||||
**/
|
||||
public static final int PRIORITY_AUTO_CONNECT = 1000;
|
||||
|
||||
/**
|
||||
* Default priority for devices that allow incoming
|
||||
* and outgoing connections for the profile
|
||||
* @hide
|
||||
**/
|
||||
public static final int PRIORITY_ON = 100;
|
||||
|
||||
/**
|
||||
* Default priority for devices that does not allow incoming
|
||||
* connections and outgoing connections for the profile.
|
||||
* @hide
|
||||
**/
|
||||
public static final int PRIORITY_OFF = 0;
|
||||
|
||||
/**
|
||||
* Default priority when not set or when the device is unpaired
|
||||
* @hide
|
||||
* */
|
||||
public static final int PRIORITY_UNDEFINED = -1;
|
||||
|
||||
/**
|
||||
* Initiate connection to a profile of the remote bluetooth device.
|
||||
*
|
||||
* <p> Currently, the system supports only 1 connection to the
|
||||
* A2DP and Headset/Handsfree profile. The API will automatically
|
||||
* disconnect connected devices before connecting.
|
||||
*
|
||||
* <p> 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.
|
||||
*
|
||||
* <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
|
||||
*
|
||||
* @param device Remote Bluetooth Device
|
||||
* @return false on immediate error,
|
||||
* true otherwise
|
||||
* @hide
|
||||
*/
|
||||
public boolean connect(BluetoothDevice device);
|
||||
|
||||
/**
|
||||
* Initiate disconnection from a profile
|
||||
*
|
||||
* <p> 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.
|
||||
*
|
||||
* <p> 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.
|
||||
*
|
||||
* <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
|
||||
*
|
||||
* @param device Remote Bluetooth Device
|
||||
* @return false on immediate error,
|
||||
* true otherwise
|
||||
* @hide
|
||||
*/
|
||||
public boolean disconnect(BluetoothDevice device);
|
||||
|
||||
/**
|
||||
* Get connected devices for this specific profile.
|
||||
*
|
||||
* <p> Return the set of devices which are in state {@link #STATE_CONNECTED}
|
||||
*
|
||||
* <p>Requires {@link android.Manifest.permission#BLUETOOTH}
|
||||
*
|
||||
* @return An unmodifiable set of devices. The set will be empty on error.
|
||||
*/
|
||||
public Set<BluetoothDevice> getConnectedDevices();
|
||||
|
||||
/**
|
||||
* Get a set of devices that match any of the given connection
|
||||
* states.
|
||||
*
|
||||
* <p> If none of devices match any of the given states,
|
||||
* an empty set will be returned.
|
||||
*
|
||||
* <p>Requires {@link android.Manifest.permission#BLUETOOTH}
|
||||
*
|
||||
* @param states Array of states. States can be one of
|
||||
* {@link #STATE_CONNECTED}, {@link #STATE_CONNECTING},
|
||||
* {@link #STATE_DISCONNECTED}, {@link #STATE_DISCONNECTING},
|
||||
* @return An unmodifiable set of devices. The set will be empty on error.
|
||||
*/
|
||||
public Set<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states);
|
||||
|
||||
/**
|
||||
* Get the current connection state of the profile
|
||||
*
|
||||
* <p>Requires {@link android.Manifest.permission#BLUETOOTH}
|
||||
*
|
||||
* @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}
|
||||
*/
|
||||
public int getConnectionState(BluetoothDevice device);
|
||||
|
||||
/**
|
||||
* Set priority of the profile
|
||||
*
|
||||
* <p> The device should already be paired.
|
||||
* Priority can be one of {@link #PRIORITY_ON} or
|
||||
* {@link #PRIORITY_OFF},
|
||||
*
|
||||
* <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
|
||||
*
|
||||
* @param device Paired bluetooth device
|
||||
* @param priority
|
||||
* @return true if priority is set, false on error
|
||||
* @hide
|
||||
*/
|
||||
public boolean setPriority(BluetoothDevice device, int priority);
|
||||
|
||||
/**
|
||||
* Get the priority of the profile.
|
||||
*
|
||||
* <p> The priority can be any of:
|
||||
* {@link #PRIORITY_AUTO_CONNECT}, {@link #PRIORITY_OFF},
|
||||
* {@link #PRIORITY_ON}, {@link #PRIORITY_UNDEFINED}
|
||||
*
|
||||
* <p>Requires {@link android.Manifest.permission#BLUETOOTH}
|
||||
*
|
||||
* @param device Bluetooth device
|
||||
* @return priority of the device
|
||||
* @hide
|
||||
*/
|
||||
public int getPriority(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}
|
||||
*/
|
||||
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}
|
||||
*/
|
||||
public void onServiceDisconnected(int profile);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user