blob: 3aea418e475141c1e1fdaf4aae073e32893a5c27 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.bluetooth;
18
Nick Pelly005b2282009-09-10 10:21:56 -070019import android.annotation.SdkConstant;
20import android.annotation.SdkConstant.SdkConstantType;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080021import android.content.ComponentName;
22import android.content.Context;
23import android.content.Intent;
24import android.content.ServiceConnection;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080025import android.os.IBinder;
Jaikumar Ganesh03cd78c2010-10-18 16:41:53 -070026import android.os.RemoteException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080027import android.util.Log;
28
Jaikumar Ganesh03cd78c2010-10-18 16:41:53 -070029import java.util.ArrayList;
30import java.util.List;
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -070031
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080032/**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080033 * Public API for controlling the Bluetooth Headset Service. This includes both
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -070034 * Bluetooth Headset and Handsfree (v1.5) profiles.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080035 *
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -070036 * <p>BluetoothHeadset is a proxy object for controlling the Bluetooth Headset
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080037 * Service via IPC.
38 *
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -070039 * <p> Use {@link BluetoothAdapter#getProfileProxy} to get
40 * the BluetoothHeadset proxy object. Use
41 * {@link BluetoothAdapter#closeProfileProxy} to close the service connection.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080042 *
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -070043 * <p> Android only supports one connected Bluetooth Headset at a time.
44 * Each method is protected with its appropriate permission.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080045 */
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -070046public final class BluetoothHeadset implements BluetoothProfile {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080047 private static final String TAG = "BluetoothHeadset";
48 private static final boolean DBG = false;
49
Nick Pelly005b2282009-09-10 10:21:56 -070050 /**
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -070051 * Intent used to broadcast the change in connection state of the Headset
52 * profile.
53 *
54 * <p>This intent will have 3 extras:
55 * {@link #EXTRA_STATE} - The current state of the profile.
56 * {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile
57 * {@link BluetoothDevice#EXTRA_DEVICE} - The remote device.
58 *
59 * {@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of
60 * {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING},
61 * {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}.
62 *
63 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
64 */
65 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
66 public static final String ACTION_CONNECTION_STATE_CHANGED =
67 "android.bluetooth.headset.profile.action.CONNECTION_STATE_CHANGED";
68
69 /**
70 * Intent used to broadcast the change in the Audio Connection state of the
71 * A2DP profile.
72 *
73 * <p>This intent will have 3 extras:
74 * {@link #EXTRA_STATE} - The current state of the profile.
75 * {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile
76 * {@link BluetoothDevice#EXTRA_DEVICE} - The remote device.
77 *
78 * {@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of
79 * {@link #STATE_AUDIO_CONNECTED}, {@link #STATE_AUDIO_DISCONNECTED},
80 *
81 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
Nick Pelly005b2282009-09-10 10:21:56 -070082 */
83 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
84 public static final String ACTION_AUDIO_STATE_CHANGED =
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -070085 "android.bluetooth.headset.profile.action.AUDIO_STATE_CHANGED";
Nick Pelly005b2282009-09-10 10:21:56 -070086
Jaikumar Ganeshc24dbdb2010-04-02 14:44:43 -070087
Nick Pelly005b2282009-09-10 10:21:56 -070088 /**
Jaikumar Ganeshe775b3d2010-09-29 11:34:59 -070089 * Intent used to broadcast that the headset has posted a
90 * vendor-specific event.
91 *
92 * <p>This intent will have 4 extras and 1 category.
93 * {@link BluetoothDevice#EXTRA_DEVICE} - The remote Bluetooth Device
94 * {@link #EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_CMD} - The vendor specific
95 * command
96 * {@link #EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_CMD_TYPE} - The AT command
97 * type.
98 * Can be one of {@link #AT_CMD_TYPE_READ}, {@link #AT_CMD_TYPE_TEST},
99 * or {@link #AT_CMD_TYPE_SET}, {@link #AT_CMD_TYPE_BASIC},
100 * {@link #AT_CMD_TYPE_ACTION}.
101 *
102 * {@link #EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_ARGS} - Command arguments.
103 *
104 * The category is the Company ID of the vendor defining the
105 * vendor-specific command. {@link BluetoothAssignedNumbers}
106 * @see <a href="https://www.bluetooth.org/Technical/AssignedNumbers/identifiers.htm">
107 * Bluetooth SIG Assigned Numbers - Company Identifiers</a>
108 *
109 * For example, for Plantronics specific events
110 * Category will be {@link #VENDOR_SPECIFIC_HEADSET_EVENT_COMPANY_ID_CATEGORY}.55
111 *
112 * <p> For example, an AT+XEVENT=foo,3 will get translated into
113 * EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_CMD = +XEVENT
114 * EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_CMD_TYPE = AT_CMD_TYPE_SET
115 * EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_ARGS = foo, 3
116 *
Herb Jellineka4733942010-08-10 13:17:43 -0700117 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
118 */
119 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
120 public static final String ACTION_VENDOR_SPECIFIC_HEADSET_EVENT =
121 "android.bluetooth.headset.action.VENDOR_SPECIFIC_HEADSET_EVENT";
122
123 /**
124 * A String extra field in {@link #ACTION_VENDOR_SPECIFIC_HEADSET_EVENT}
125 * intents that contains the name of the vendor-specific command.
126 */
127 public static final String EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_CMD =
128 "android.bluetooth.headset.extra.VENDOR_SPECIFIC_HEADSET_EVENT_CMD";
129
130 /**
131 * An int extra field in {@link #ACTION_VENDOR_SPECIFIC_HEADSET_EVENT}
Jaikumar Ganeshe775b3d2010-09-29 11:34:59 -0700132 * intents that contains the AT command type of the vendor-specific command.
Herb Jellineka4733942010-08-10 13:17:43 -0700133 */
Jaikumar Ganeshe775b3d2010-09-29 11:34:59 -0700134 public static final String EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_CMD_TYPE =
135 "android.bluetooth.headset.extra.VENDOR_SPECIFIC_HEADSET_EVENT_CMD_TYPE";
136
137 /**
138 * AT command type READ used with
139 * {@link #EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_CMD_TYPE}
140 * For example, AT+VGM?. There are no arguments for this command type.
141 */
142 public static final int AT_CMD_TYPE_READ = 0;
143
144 /**
145 * AT command type TEST used with
146 * {@link #EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_CMD_TYPE}
147 * For example, AT+VGM=?. There are no arguments for this command type.
148 */
149 public static final int AT_CMD_TYPE_TEST = 1;
150
151 /**
152 * AT command type SET used with
153 * {@link #EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_CMD_TYPE}
154 * For example, AT+VGM=<args>.
155 */
156 public static final int AT_CMD_TYPE_SET = 2;
157
158 /**
159 * AT command type BASIC used with
160 * {@link #EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_CMD_TYPE}
161 * For example, ATD. Single character commands and everything following the
162 * character are arguments.
163 */
164 public static final int AT_CMD_TYPE_BASIC = 3;
165
166 /**
167 * AT command type ACTION used with
168 * {@link #EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_CMD_TYPE}
169 * For example, AT+CHUP. There are no arguments for action commands.
170 */
171 public static final int AT_CMD_TYPE_ACTION = 4;
Herb Jellineka4733942010-08-10 13:17:43 -0700172
173 /**
174 * A Parcelable String array extra field in
175 * {@link #ACTION_VENDOR_SPECIFIC_HEADSET_EVENT} intents that contains
176 * the arguments to the vendor-specific command.
177 */
178 public static final String EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_ARGS =
179 "android.bluetooth.headset.extra.VENDOR_SPECIFIC_HEADSET_EVENT_ARGS";
180
Jaikumar Ganeshe775b3d2010-09-29 11:34:59 -0700181 /**
182 * The intent category to be used with {@link #ACTION_VENDOR_SPECIFIC_HEADSET_EVENT}
183 * for the companyId
184 */
185 public static final String VENDOR_SPECIFIC_HEADSET_EVENT_COMPANY_ID_CATEGORY =
186 "android.bluetooth.headset.intent.category.companyid";
187
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700188 /*
189 * Headset state when SCO audio is connected
190 * This state can be one of
191 * {@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} of
192 * {@link #ACTION_AUDIO_STATE_CHANGED} intent.
193 */
194 public static final int STATE_AUDIO_CONNECTED = 10;
Herb Jellineka4733942010-08-10 13:17:43 -0700195
196 /**
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700197 * Headset state when SCO audio is NOT connected
198 * This state can be one of
199 * {@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} of
200 * {@link #ACTION_AUDIO_STATE_CHANGED} intent.
Nick Pelly005b2282009-09-10 10:21:56 -0700201 */
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700202 public static final int STATE_AUDIO_DISCONNECTED = 11;
203
204
205 private Context mContext;
206 private ServiceListener mServiceListener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800207 private IBluetoothHeadset mService;
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700208 BluetoothAdapter mAdapter;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800209
210 /**
211 * Create a BluetoothHeadset proxy object.
212 */
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700213 /*package*/ BluetoothHeadset(Context context, ServiceListener l) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800214 mContext = context;
215 mServiceListener = l;
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700216 mAdapter = BluetoothAdapter.getDefaultAdapter();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800217 if (!context.bindService(new Intent(IBluetoothHeadset.class.getName()), mConnection, 0)) {
218 Log.e(TAG, "Could not bind to Bluetooth Headset Service");
219 }
220 }
221
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800222 /**
223 * Close the connection to the backing service.
224 * Other public functions of BluetoothHeadset will return default error
225 * results once close() has been called. Multiple invocations of close()
226 * are ok.
227 */
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700228 /*package*/ synchronized void close() {
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -0800229 if (DBG) log("close()");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800230 if (mConnection != null) {
231 mContext.unbindService(mConnection);
232 mConnection = null;
233 }
234 }
235
236 /**
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700237 * {@inheritDoc}
238 * @hide
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800239 */
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700240 public boolean connect(BluetoothDevice device) {
241 if (DBG) log("connect(" + device + ")");
242 if (mService != null && isEnabled() &&
243 isValidDevice(device)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800244 try {
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700245 return mService.connect(device);
246 } catch (RemoteException e) {
247 Log.e(TAG, Log.getStackTraceString(new Throwable()));
248 return false;
249 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800250 }
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700251 if (mService == null) Log.w(TAG, "Proxy not attached to service");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800252 return false;
253 }
254
255 /**
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700256 * {@inheritDoc}
257 * @hide
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800258 */
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700259 public boolean disconnect(BluetoothDevice device) {
260 if (DBG) log("disconnect(" + device + ")");
261 if (mService != null && isEnabled() &&
262 isValidDevice(device)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800263 try {
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700264 return mService.disconnect(device);
265 } catch (RemoteException e) {
266 Log.e(TAG, Log.getStackTraceString(new Throwable()));
267 return false;
268 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800269 }
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700270 if (mService == null) Log.w(TAG, "Proxy not attached to service");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800271 return false;
272 }
273
274 /**
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700275 * {@inheritDoc}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800276 */
Jaikumar Ganesh03cd78c2010-10-18 16:41:53 -0700277 public List<BluetoothDevice> getConnectedDevices() {
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700278 if (DBG) log("getConnectedDevices()");
279 if (mService != null && isEnabled()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800280 try {
Jaikumar Ganesh03cd78c2010-10-18 16:41:53 -0700281 return mService.getConnectedDevices();
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700282 } catch (RemoteException e) {
283 Log.e(TAG, Log.getStackTraceString(new Throwable()));
Jaikumar Ganesh03cd78c2010-10-18 16:41:53 -0700284 return new ArrayList<BluetoothDevice>();
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700285 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800286 }
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700287 if (mService == null) Log.w(TAG, "Proxy not attached to service");
Jaikumar Ganesh03cd78c2010-10-18 16:41:53 -0700288 return new ArrayList<BluetoothDevice>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800289 }
290
291 /**
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700292 * {@inheritDoc}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800293 */
Jaikumar Ganesh03cd78c2010-10-18 16:41:53 -0700294 public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700295 if (DBG) log("getDevicesMatchingStates()");
296 if (mService != null && isEnabled()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800297 try {
Jaikumar Ganesh03cd78c2010-10-18 16:41:53 -0700298 return mService.getDevicesMatchingConnectionStates(states);
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700299 } catch (RemoteException e) {
300 Log.e(TAG, Log.getStackTraceString(new Throwable()));
Jaikumar Ganesh03cd78c2010-10-18 16:41:53 -0700301 return new ArrayList<BluetoothDevice>();
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700302 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800303 }
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700304 if (mService == null) Log.w(TAG, "Proxy not attached to service");
Jaikumar Ganesh03cd78c2010-10-18 16:41:53 -0700305 return new ArrayList<BluetoothDevice>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800306 }
307
308 /**
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700309 * {@inheritDoc}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800310 */
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700311 public int getConnectionState(BluetoothDevice device) {
312 if (DBG) log("getConnectionState(" + device + ")");
313 if (mService != null && isEnabled() &&
314 isValidDevice(device)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800315 try {
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700316 return mService.getConnectionState(device);
317 } catch (RemoteException e) {
318 Log.e(TAG, Log.getStackTraceString(new Throwable()));
319 return BluetoothProfile.STATE_DISCONNECTED;
320 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800321 }
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700322 if (mService == null) Log.w(TAG, "Proxy not attached to service");
323 return BluetoothProfile.STATE_DISCONNECTED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800324 }
325
326 /**
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700327 * {@inheritDoc}
328 * @hide
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800329 */
Nick Pellybd022f42009-08-14 18:33:38 -0700330 public boolean setPriority(BluetoothDevice device, int priority) {
331 if (DBG) log("setPriority(" + device + ", " + priority + ")");
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700332 if (mService != null && isEnabled() &&
333 isValidDevice(device)) {
334 if (priority != BluetoothProfile.PRIORITY_OFF &&
335 priority != BluetoothProfile.PRIORITY_ON) {
336 return false;
337 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800338 try {
Nick Pellybd022f42009-08-14 18:33:38 -0700339 return mService.setPriority(device, priority);
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700340 } catch (RemoteException e) {
341 Log.e(TAG, Log.getStackTraceString(new Throwable()));
342 return false;
343 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800344 }
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700345 if (mService == null) Log.w(TAG, "Proxy not attached to service");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800346 return false;
347 }
348
349 /**
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700350 * {@inheritDoc}
351 * @hide
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800352 */
Nick Pellybd022f42009-08-14 18:33:38 -0700353 public int getPriority(BluetoothDevice device) {
354 if (DBG) log("getPriority(" + device + ")");
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700355 if (mService != null && isEnabled() &&
356 isValidDevice(device)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800357 try {
Nick Pellybd022f42009-08-14 18:33:38 -0700358 return mService.getPriority(device);
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700359 } catch (RemoteException e) {
360 Log.e(TAG, Log.getStackTraceString(new Throwable()));
361 return PRIORITY_OFF;
362 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800363 }
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700364 if (mService == null) Log.w(TAG, "Proxy not attached to service");
365 return PRIORITY_OFF;
366 }
367
368 /**
369 * Start Bluetooth voice recognition. This methods sends the voice
370 * recognition AT command to the headset and establishes the
371 * audio connection.
372 *
373 * <p> Users can listen to {@link #ACTION_AUDIO_STATE_CHANGED}.
374 * {@link #EXTRA_STATE} will be set to {@link #STATE_AUDIO_CONNECTED}
375 * when the audio connection is established.
376 *
377 * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
378 *
379 * @param device Bluetooth headset
380 * @return false if there is no headset connected of if the
381 * connected headset doesn't support voice recognition
382 * or on error, true otherwise
383 */
384 public boolean startVoiceRecognition(BluetoothDevice device) {
385 if (DBG) log("startVoiceRecognition()");
386 if (mService != null && isEnabled() &&
387 isValidDevice(device)) {
388 try {
389 return mService.startVoiceRecognition(device);
390 } catch (RemoteException e) {
391 Log.e(TAG, Log.getStackTraceString(new Throwable()));
392 }
393 }
394 if (mService == null) Log.w(TAG, "Proxy not attached to service");
395 return false;
396 }
397
398 /**
399 * Stop Bluetooth Voice Recognition mode, and shut down the
400 * Bluetooth audio path.
401 *
402 * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
403 *
404 * @param device Bluetooth headset
405 * @return false if there is no headset connected
406 * or on error, true otherwise
407 */
408 public boolean stopVoiceRecognition(BluetoothDevice device) {
409 if (DBG) log("stopVoiceRecognition()");
410 if (mService != null && isEnabled() &&
411 isValidDevice(device)) {
412 try {
413 return mService.stopVoiceRecognition(device);
414 } catch (RemoteException e) {
415 Log.e(TAG, Log.getStackTraceString(new Throwable()));
416 }
417 }
418 if (mService == null) Log.w(TAG, "Proxy not attached to service");
419 return false;
420 }
421
422 /**
423 * Check if Bluetooth SCO audio is connected.
424 *
425 * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
426 *
427 * @param device Bluetooth headset
428 * @return true if SCO is connected,
429 * false otherwise or on error
430 */
431 public boolean isAudioConnected(BluetoothDevice device) {
432 if (DBG) log("isAudioConnected()");
433 if (mService != null && isEnabled() &&
434 isValidDevice(device)) {
435 try {
436 return mService.isAudioConnected(device);
437 } catch (RemoteException e) {
438 Log.e(TAG, Log.getStackTraceString(new Throwable()));
439 }
440 }
441 if (mService == null) Log.w(TAG, "Proxy not attached to service");
442 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800443 }
444
445 /**
Nick Pelly6c901db2009-06-19 10:08:09 -0700446 * Get battery usage hint for Bluetooth Headset service.
447 * This is a monotonically increasing integer. Wraps to 0 at
448 * Integer.MAX_INT, and at boot.
449 * Current implementation returns the number of AT commands handled since
450 * boot. This is a good indicator for spammy headset/handsfree units that
451 * can keep the device awake by polling for cellular status updates. As a
452 * rule of thumb, each AT command prevents the CPU from sleeping for 500 ms
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700453 *
454 * @param device the bluetooth headset.
Nick Pelly6c901db2009-06-19 10:08:09 -0700455 * @return monotonically increasing battery usage hint, or a negative error
456 * code on error
457 * @hide
458 */
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700459 public int getBatteryUsageHint(BluetoothDevice device) {
Nick Pelly6c901db2009-06-19 10:08:09 -0700460 if (DBG) log("getBatteryUsageHint()");
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700461 if (mService != null && isEnabled() &&
462 isValidDevice(device)) {
Nick Pelly6c901db2009-06-19 10:08:09 -0700463 try {
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700464 return mService.getBatteryUsageHint(device);
465 } catch (RemoteException e) {
466 Log.e(TAG, Log.getStackTraceString(new Throwable()));
467 }
Nick Pelly6c901db2009-06-19 10:08:09 -0700468 }
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700469 if (mService == null) Log.w(TAG, "Proxy not attached to service");
Nick Pelly6c901db2009-06-19 10:08:09 -0700470 return -1;
471 }
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700472
Eric Laurentd726b352010-03-17 14:59:27 -0700473 /**
474 * Indicates if current platform supports voice dialing over bluetooth SCO.
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700475 *
Eric Laurentd726b352010-03-17 14:59:27 -0700476 * @return true if voice dialing over bluetooth is supported, false otherwise.
477 * @hide
478 */
479 public static boolean isBluetoothVoiceDialingEnabled(Context context) {
480 return context.getResources().getBoolean(
481 com.android.internal.R.bool.config_bluetooth_sco_off_call);
482 }
483
Jaikumar Ganesh9b637e52010-06-02 14:36:14 -0700484 /**
485 * Cancel the outgoing connection.
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700486 * Note: This is an internal function and shouldn't be exposed
487 *
Jaikumar Ganesh9b637e52010-06-02 14:36:14 -0700488 * @hide
489 */
490 public boolean cancelConnectThread() {
491 if (DBG) log("cancelConnectThread");
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700492 if (mService != null && isEnabled()) {
Jaikumar Ganesh9b637e52010-06-02 14:36:14 -0700493 try {
494 return mService.cancelConnectThread();
495 } catch (RemoteException e) {Log.e(TAG, e.toString());}
496 } else {
497 Log.w(TAG, "Proxy not attached to service");
498 if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
499 }
500 return false;
501 }
502
503 /**
504 * Accept the incoming connection.
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700505 * Note: This is an internal function and shouldn't be exposed
506 *
Jaikumar Ganesh9b637e52010-06-02 14:36:14 -0700507 * @hide
508 */
509 public boolean acceptIncomingConnect(BluetoothDevice device) {
510 if (DBG) log("acceptIncomingConnect");
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700511 if (mService != null && isEnabled()) {
Jaikumar Ganesh9b637e52010-06-02 14:36:14 -0700512 try {
513 return mService.acceptIncomingConnect(device);
514 } catch (RemoteException e) {Log.e(TAG, e.toString());}
515 } else {
516 Log.w(TAG, "Proxy not attached to service");
517 if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
518 }
519 return false;
520 }
521
522 /**
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700523 * Create the connect thread for the incoming connection.
524 * Note: This is an internal function and shouldn't be exposed
525 *
Jaikumar Ganesh9b637e52010-06-02 14:36:14 -0700526 * @hide
527 */
528 public boolean createIncomingConnect(BluetoothDevice device) {
529 if (DBG) log("createIncomingConnect");
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700530 if (mService != null && isEnabled()) {
Jaikumar Ganesh9b637e52010-06-02 14:36:14 -0700531 try {
532 return mService.createIncomingConnect(device);
533 } catch (RemoteException e) {Log.e(TAG, e.toString());}
534 } else {
535 Log.w(TAG, "Proxy not attached to service");
536 if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
537 }
538 return false;
539 }
540
541 /**
542 * Connect to a Bluetooth Headset.
543 * Note: This is an internal function and shouldn't be exposed
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700544 *
Jaikumar Ganesh9b637e52010-06-02 14:36:14 -0700545 * @hide
546 */
547 public boolean connectHeadsetInternal(BluetoothDevice device) {
548 if (DBG) log("connectHeadsetInternal");
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700549 if (mService != null && isEnabled()) {
Jaikumar Ganesh9b637e52010-06-02 14:36:14 -0700550 try {
551 return mService.connectHeadsetInternal(device);
552 } catch (RemoteException e) {Log.e(TAG, e.toString());}
553 } else {
554 Log.w(TAG, "Proxy not attached to service");
555 if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
556 }
557 return false;
558 }
559
560 /**
561 * Disconnect a Bluetooth Headset.
562 * Note: This is an internal function and shouldn't be exposed
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700563 *
Jaikumar Ganesh9b637e52010-06-02 14:36:14 -0700564 * @hide
565 */
566 public boolean disconnectHeadsetInternal(BluetoothDevice device) {
567 if (DBG) log("disconnectHeadsetInternal");
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700568 if (mService != null && isEnabled()) {
Jaikumar Ganesh9b637e52010-06-02 14:36:14 -0700569 try {
570 return mService.disconnectHeadsetInternal(device);
571 } catch (RemoteException e) {Log.e(TAG, e.toString());}
572 } else {
573 Log.w(TAG, "Proxy not attached to service");
574 if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
575 }
576 return false;
577 }
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700578
579 /**
580 * Set the audio state of the Headset.
581 * Note: This is an internal function and shouldn't be exposed
582 *
583 * @hide
584 */
585 public boolean setAudioState(BluetoothDevice device, int state) {
586 if (DBG) log("setAudioState");
587 if (mService != null && isEnabled()) {
588 try {
589 return mService.setAudioState(device, state);
590 } catch (RemoteException e) {Log.e(TAG, e.toString());}
591 } else {
592 Log.w(TAG, "Proxy not attached to service");
593 if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
594 }
595 return false;
596 }
597
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800598 private ServiceConnection mConnection = new ServiceConnection() {
599 public void onServiceConnected(ComponentName className, IBinder service) {
600 if (DBG) Log.d(TAG, "Proxy object connected");
601 mService = IBluetoothHeadset.Stub.asInterface(service);
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700602
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800603 if (mServiceListener != null) {
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700604 mServiceListener.onServiceConnected(BluetoothProfile.HEADSET, BluetoothHeadset.this);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800605 }
606 }
607 public void onServiceDisconnected(ComponentName className) {
608 if (DBG) Log.d(TAG, "Proxy object disconnected");
609 mService = null;
610 if (mServiceListener != null) {
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700611 mServiceListener.onServiceDisconnected(BluetoothProfile.HEADSET);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800612 }
613 }
614 };
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -0800615
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700616 private boolean isEnabled() {
617 if (mAdapter.getState() == BluetoothAdapter.STATE_ON) return true;
618 return false;
619 }
620
621 private boolean isValidDevice(BluetoothDevice device) {
622 if (device == null) return false;
623
624 if (BluetoothAdapter.checkBluetoothAddress(device.getAddress())) return true;
625 return false;
626 }
627
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -0800628 private static void log(String msg) {
629 Log.d(TAG, msg);
630 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800631}