19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2008 The Android Open Source Project
39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License.
69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at
79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and
149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License.
159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage android.bluetooth;
189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pellyimport android.annotation.SdkConstant;
20005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pellyimport android.annotation.SdkConstant.SdkConstantType;
219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.ComponentName;
229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Context;
23e8b98925d08f720c4d22b626d0650de536840a9aBenjamin Franzimport android.os.Handler;
249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.IBinder;
25e8b98925d08f720c4d22b626d0650de536840a9aBenjamin Franzimport android.os.Looper;
26e8b98925d08f720c4d22b626d0650de536840a9aBenjamin Franzimport android.os.Message;
2703cd78cf5e51c3adb78d2e3d314838dcf3e36b26Jaikumar Ganeshimport android.os.RemoteException;
289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.Log;
299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3003cd78cf5e51c3adb78d2e3d314838dcf3e36b26Jaikumar Ganeshimport java.util.ArrayList;
3103cd78cf5e51c3adb78d2e3d314838dcf3e36b26Jaikumar Ganeshimport java.util.List;
3262c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh
339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/**
349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Public API for controlling the Bluetooth Headset Service. This includes both
3562c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh * Bluetooth Headset and Handsfree (v1.5) profiles.
369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
3762c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh * <p>BluetoothHeadset is a proxy object for controlling the Bluetooth Headset
389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Service via IPC.
399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
4062c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh * <p> Use {@link BluetoothAdapter#getProfileProxy} to get
4162c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh * the BluetoothHeadset proxy object. Use
4262c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh * {@link BluetoothAdapter#closeProfileProxy} to close the service connection.
439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
4462c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh * <p> Android only supports one connected Bluetooth Headset at a time.
4562c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh * Each method is protected with its appropriate permission.
469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
4762c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganeshpublic final class BluetoothHeadset implements BluetoothProfile {
489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String TAG = "BluetoothHeadset";
490f42037eb7b5118015c2caca635538324ccf0ccffredc    private static final boolean DBG = true;
50563e414784eb81e4ea4051667d5c8855b17f7534Matthew Xie    private static final boolean VDBG = false;
519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5262c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh    /**
5362c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh     * Intent used to broadcast the change in connection state of the Headset
5462c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh     * profile.
5562c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh     *
5662c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh     * <p>This intent will have 3 extras:
57c8fa4ff838a0c3d2c67db65540fa751e5abe27edJaikumar Ganesh     * <ul>
58c8fa4ff838a0c3d2c67db65540fa751e5abe27edJaikumar Ganesh     *   <li> {@link #EXTRA_STATE} - The current state of the profile. </li>
59c8fa4ff838a0c3d2c67db65540fa751e5abe27edJaikumar Ganesh     *   <li> {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile. </li>
60c8fa4ff838a0c3d2c67db65540fa751e5abe27edJaikumar Ganesh     *   <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li>
61c8fa4ff838a0c3d2c67db65540fa751e5abe27edJaikumar Ganesh     * </ul>
620706fed52075f7f2b25101a40287519ac18d3184Jaikumar Ganesh     * <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of
6362c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh     * {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING},
6462c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh     * {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}.
6562c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh     *
66c8fa4ff838a0c3d2c67db65540fa751e5abe27edJaikumar Ganesh     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
67c8fa4ff838a0c3d2c67db65540fa751e5abe27edJaikumar Ganesh     * receive.
6862c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh     */
69005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
7062c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh    public static final String ACTION_CONNECTION_STATE_CHANGED =
7162c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh        "android.bluetooth.headset.profile.action.CONNECTION_STATE_CHANGED";
7262c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh
73005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly    /**
7462c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh     * Intent used to broadcast the change in the Audio Connection state of the
7562c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh     * A2DP profile.
7662c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh     *
7762c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh     * <p>This intent will have 3 extras:
78c8fa4ff838a0c3d2c67db65540fa751e5abe27edJaikumar Ganesh     * <ul>
79c8fa4ff838a0c3d2c67db65540fa751e5abe27edJaikumar Ganesh     *   <li> {@link #EXTRA_STATE} - The current state of the profile. </li>
80c8fa4ff838a0c3d2c67db65540fa751e5abe27edJaikumar Ganesh     *   <li> {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile. </li>
81c8fa4ff838a0c3d2c67db65540fa751e5abe27edJaikumar Ganesh     *   <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li>
82c8fa4ff838a0c3d2c67db65540fa751e5abe27edJaikumar Ganesh     * </ul>
830706fed52075f7f2b25101a40287519ac18d3184Jaikumar Ganesh     * <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of
8462c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh     * {@link #STATE_AUDIO_CONNECTED}, {@link #STATE_AUDIO_DISCONNECTED},
8562c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh     *
86c8fa4ff838a0c3d2c67db65540fa751e5abe27edJaikumar Ganesh     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission
87c8fa4ff838a0c3d2c67db65540fa751e5abe27edJaikumar Ganesh     * to receive.
88005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly     */
89005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
90005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly    public static final String ACTION_AUDIO_STATE_CHANGED =
9162c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh        "android.bluetooth.headset.profile.action.AUDIO_STATE_CHANGED";
9262c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh
93c24dbdb57b30f9e8fa6b0c5b48372017b5ae46b0Jaikumar Ganesh
94005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly    /**
95e775b3daab9766bce9ec2d01fe7d652c4a782b6bJaikumar Ganesh     * Intent used to broadcast that the headset has posted a
96e775b3daab9766bce9ec2d01fe7d652c4a782b6bJaikumar Ganesh     * vendor-specific event.
97e775b3daab9766bce9ec2d01fe7d652c4a782b6bJaikumar Ganesh     *
98e775b3daab9766bce9ec2d01fe7d652c4a782b6bJaikumar Ganesh     * <p>This intent will have 4 extras and 1 category.
99c8fa4ff838a0c3d2c67db65540fa751e5abe27edJaikumar Ganesh     * <ul>
100c8fa4ff838a0c3d2c67db65540fa751e5abe27edJaikumar Ganesh     *  <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote Bluetooth Device
101c8fa4ff838a0c3d2c67db65540fa751e5abe27edJaikumar Ganesh     *       </li>
102c8fa4ff838a0c3d2c67db65540fa751e5abe27edJaikumar Ganesh     *  <li> {@link #EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_CMD} - The vendor
103c8fa4ff838a0c3d2c67db65540fa751e5abe27edJaikumar Ganesh     *       specific command </li>
104c8fa4ff838a0c3d2c67db65540fa751e5abe27edJaikumar Ganesh     *  <li> {@link #EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_CMD_TYPE} - The AT
105c8fa4ff838a0c3d2c67db65540fa751e5abe27edJaikumar Ganesh     *       command type which can be one of  {@link #AT_CMD_TYPE_READ},
106c8fa4ff838a0c3d2c67db65540fa751e5abe27edJaikumar Ganesh     *       {@link #AT_CMD_TYPE_TEST}, or {@link #AT_CMD_TYPE_SET},
1070706fed52075f7f2b25101a40287519ac18d3184Jaikumar Ganesh     *       {@link #AT_CMD_TYPE_BASIC},{@link #AT_CMD_TYPE_ACTION}. </li>
108c8fa4ff838a0c3d2c67db65540fa751e5abe27edJaikumar Ganesh     *  <li> {@link #EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_ARGS} - Command
109c8fa4ff838a0c3d2c67db65540fa751e5abe27edJaikumar Ganesh     *       arguments. </li>
110c8fa4ff838a0c3d2c67db65540fa751e5abe27edJaikumar Ganesh     * </ul>
111e775b3daab9766bce9ec2d01fe7d652c4a782b6bJaikumar Ganesh     *
1120706fed52075f7f2b25101a40287519ac18d3184Jaikumar Ganesh     *<p> The category is the Company ID of the vendor defining the
113e775b3daab9766bce9ec2d01fe7d652c4a782b6bJaikumar Ganesh     * vendor-specific command. {@link BluetoothAssignedNumbers}
114e775b3daab9766bce9ec2d01fe7d652c4a782b6bJaikumar Ganesh     *
115e775b3daab9766bce9ec2d01fe7d652c4a782b6bJaikumar Ganesh     * For example, for Plantronics specific events
116e775b3daab9766bce9ec2d01fe7d652c4a782b6bJaikumar Ganesh     * Category will be {@link #VENDOR_SPECIFIC_HEADSET_EVENT_COMPANY_ID_CATEGORY}.55
117e775b3daab9766bce9ec2d01fe7d652c4a782b6bJaikumar Ganesh     *
118e775b3daab9766bce9ec2d01fe7d652c4a782b6bJaikumar Ganesh     * <p> For example, an AT+XEVENT=foo,3 will get translated into
119c8fa4ff838a0c3d2c67db65540fa751e5abe27edJaikumar Ganesh     * <ul>
120c8fa4ff838a0c3d2c67db65540fa751e5abe27edJaikumar Ganesh     *   <li> EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_CMD = +XEVENT </li>
121c8fa4ff838a0c3d2c67db65540fa751e5abe27edJaikumar Ganesh     *   <li> EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_CMD_TYPE = AT_CMD_TYPE_SET </li>
1220706fed52075f7f2b25101a40287519ac18d3184Jaikumar Ganesh     *   <li> EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_ARGS = foo, 3 </li>
123c8fa4ff838a0c3d2c67db65540fa751e5abe27edJaikumar Ganesh     * </ul>
124c8fa4ff838a0c3d2c67db65540fa751e5abe27edJaikumar Ganesh     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission
125c8fa4ff838a0c3d2c67db65540fa751e5abe27edJaikumar Ganesh     * to receive.
126a4733941839abd672b1e37edd7f61c8932d4aa48Herb Jellinek     */
127a4733941839abd672b1e37edd7f61c8932d4aa48Herb Jellinek    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
128a4733941839abd672b1e37edd7f61c8932d4aa48Herb Jellinek    public static final String ACTION_VENDOR_SPECIFIC_HEADSET_EVENT =
129a4733941839abd672b1e37edd7f61c8932d4aa48Herb Jellinek            "android.bluetooth.headset.action.VENDOR_SPECIFIC_HEADSET_EVENT";
130a4733941839abd672b1e37edd7f61c8932d4aa48Herb Jellinek
131a4733941839abd672b1e37edd7f61c8932d4aa48Herb Jellinek    /**
132a4733941839abd672b1e37edd7f61c8932d4aa48Herb Jellinek     * A String extra field in {@link #ACTION_VENDOR_SPECIFIC_HEADSET_EVENT}
133a4733941839abd672b1e37edd7f61c8932d4aa48Herb Jellinek     * intents that contains the name of the vendor-specific command.
134a4733941839abd672b1e37edd7f61c8932d4aa48Herb Jellinek     */
135a4733941839abd672b1e37edd7f61c8932d4aa48Herb Jellinek    public static final String EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_CMD =
136a4733941839abd672b1e37edd7f61c8932d4aa48Herb Jellinek            "android.bluetooth.headset.extra.VENDOR_SPECIFIC_HEADSET_EVENT_CMD";
137a4733941839abd672b1e37edd7f61c8932d4aa48Herb Jellinek
138a4733941839abd672b1e37edd7f61c8932d4aa48Herb Jellinek    /**
139a4733941839abd672b1e37edd7f61c8932d4aa48Herb Jellinek     * An int extra field in {@link #ACTION_VENDOR_SPECIFIC_HEADSET_EVENT}
140e775b3daab9766bce9ec2d01fe7d652c4a782b6bJaikumar Ganesh     * intents that contains the AT command type of the vendor-specific command.
141e775b3daab9766bce9ec2d01fe7d652c4a782b6bJaikumar Ganesh     */
142e775b3daab9766bce9ec2d01fe7d652c4a782b6bJaikumar Ganesh    public static final String EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_CMD_TYPE =
143e775b3daab9766bce9ec2d01fe7d652c4a782b6bJaikumar Ganesh            "android.bluetooth.headset.extra.VENDOR_SPECIFIC_HEADSET_EVENT_CMD_TYPE";
144e775b3daab9766bce9ec2d01fe7d652c4a782b6bJaikumar Ganesh
145e775b3daab9766bce9ec2d01fe7d652c4a782b6bJaikumar Ganesh    /**
146e775b3daab9766bce9ec2d01fe7d652c4a782b6bJaikumar Ganesh     * AT command type READ used with
147e775b3daab9766bce9ec2d01fe7d652c4a782b6bJaikumar Ganesh     * {@link #EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_CMD_TYPE}
148e775b3daab9766bce9ec2d01fe7d652c4a782b6bJaikumar Ganesh     * For example, AT+VGM?. There are no arguments for this command type.
149e775b3daab9766bce9ec2d01fe7d652c4a782b6bJaikumar Ganesh     */
150e775b3daab9766bce9ec2d01fe7d652c4a782b6bJaikumar Ganesh    public static final int AT_CMD_TYPE_READ = 0;
151e775b3daab9766bce9ec2d01fe7d652c4a782b6bJaikumar Ganesh
152e775b3daab9766bce9ec2d01fe7d652c4a782b6bJaikumar Ganesh    /**
153e775b3daab9766bce9ec2d01fe7d652c4a782b6bJaikumar Ganesh     * AT command type TEST used with
154e775b3daab9766bce9ec2d01fe7d652c4a782b6bJaikumar Ganesh     * {@link #EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_CMD_TYPE}
155e775b3daab9766bce9ec2d01fe7d652c4a782b6bJaikumar Ganesh     * For example, AT+VGM=?. There are no arguments for this command type.
156e775b3daab9766bce9ec2d01fe7d652c4a782b6bJaikumar Ganesh     */
157e775b3daab9766bce9ec2d01fe7d652c4a782b6bJaikumar Ganesh    public static final int AT_CMD_TYPE_TEST = 1;
158e775b3daab9766bce9ec2d01fe7d652c4a782b6bJaikumar Ganesh
159e775b3daab9766bce9ec2d01fe7d652c4a782b6bJaikumar Ganesh    /**
160e775b3daab9766bce9ec2d01fe7d652c4a782b6bJaikumar Ganesh     * AT command type SET used with
161e775b3daab9766bce9ec2d01fe7d652c4a782b6bJaikumar Ganesh     * {@link #EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_CMD_TYPE}
162e775b3daab9766bce9ec2d01fe7d652c4a782b6bJaikumar Ganesh     * For example, AT+VGM=<args>.
163e775b3daab9766bce9ec2d01fe7d652c4a782b6bJaikumar Ganesh     */
164e775b3daab9766bce9ec2d01fe7d652c4a782b6bJaikumar Ganesh    public static final int AT_CMD_TYPE_SET = 2;
165e775b3daab9766bce9ec2d01fe7d652c4a782b6bJaikumar Ganesh
166e775b3daab9766bce9ec2d01fe7d652c4a782b6bJaikumar Ganesh    /**
167e775b3daab9766bce9ec2d01fe7d652c4a782b6bJaikumar Ganesh     * AT command type BASIC used with
168e775b3daab9766bce9ec2d01fe7d652c4a782b6bJaikumar Ganesh     * {@link #EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_CMD_TYPE}
169e775b3daab9766bce9ec2d01fe7d652c4a782b6bJaikumar Ganesh     * For example, ATD. Single character commands and everything following the
170e775b3daab9766bce9ec2d01fe7d652c4a782b6bJaikumar Ganesh     * character are arguments.
171e775b3daab9766bce9ec2d01fe7d652c4a782b6bJaikumar Ganesh     */
172e775b3daab9766bce9ec2d01fe7d652c4a782b6bJaikumar Ganesh    public static final int AT_CMD_TYPE_BASIC = 3;
173e775b3daab9766bce9ec2d01fe7d652c4a782b6bJaikumar Ganesh
174e775b3daab9766bce9ec2d01fe7d652c4a782b6bJaikumar Ganesh    /**
175e775b3daab9766bce9ec2d01fe7d652c4a782b6bJaikumar Ganesh     * AT command type ACTION used with
176e775b3daab9766bce9ec2d01fe7d652c4a782b6bJaikumar Ganesh     * {@link #EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_CMD_TYPE}
177e775b3daab9766bce9ec2d01fe7d652c4a782b6bJaikumar Ganesh     * For example, AT+CHUP. There are no arguments for action commands.
178a4733941839abd672b1e37edd7f61c8932d4aa48Herb Jellinek     */
179e775b3daab9766bce9ec2d01fe7d652c4a782b6bJaikumar Ganesh    public static final int AT_CMD_TYPE_ACTION = 4;
180a4733941839abd672b1e37edd7f61c8932d4aa48Herb Jellinek
181a4733941839abd672b1e37edd7f61c8932d4aa48Herb Jellinek    /**
182a4733941839abd672b1e37edd7f61c8932d4aa48Herb Jellinek     * A Parcelable String array extra field in
183a4733941839abd672b1e37edd7f61c8932d4aa48Herb Jellinek     * {@link #ACTION_VENDOR_SPECIFIC_HEADSET_EVENT} intents that contains
184a4733941839abd672b1e37edd7f61c8932d4aa48Herb Jellinek     * the arguments to the vendor-specific command.
185a4733941839abd672b1e37edd7f61c8932d4aa48Herb Jellinek     */
186a4733941839abd672b1e37edd7f61c8932d4aa48Herb Jellinek    public static final String EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_ARGS =
187a4733941839abd672b1e37edd7f61c8932d4aa48Herb Jellinek            "android.bluetooth.headset.extra.VENDOR_SPECIFIC_HEADSET_EVENT_ARGS";
188a4733941839abd672b1e37edd7f61c8932d4aa48Herb Jellinek
189e775b3daab9766bce9ec2d01fe7d652c4a782b6bJaikumar Ganesh    /**
190e775b3daab9766bce9ec2d01fe7d652c4a782b6bJaikumar Ganesh     * The intent category to be used with {@link #ACTION_VENDOR_SPECIFIC_HEADSET_EVENT}
191e775b3daab9766bce9ec2d01fe7d652c4a782b6bJaikumar Ganesh     * for the companyId
192e775b3daab9766bce9ec2d01fe7d652c4a782b6bJaikumar Ganesh     */
193e775b3daab9766bce9ec2d01fe7d652c4a782b6bJaikumar Ganesh    public static final String VENDOR_SPECIFIC_HEADSET_EVENT_COMPANY_ID_CATEGORY  =
194e775b3daab9766bce9ec2d01fe7d652c4a782b6bJaikumar Ganesh            "android.bluetooth.headset.intent.category.companyid";
195e775b3daab9766bce9ec2d01fe7d652c4a782b6bJaikumar Ganesh
19630d181690e48b26cdfae3b144d23f1e16c75da37Jaikumar Ganesh    /**
197922d41b6ef202eac65991d27c43d74c828256f0dEdward Jee     * A vendor-specific command for unsolicited result code.
198922d41b6ef202eac65991d27c43d74c828256f0dEdward Jee     */
199922d41b6ef202eac65991d27c43d74c828256f0dEdward Jee    public static final String VENDOR_RESULT_CODE_COMMAND_ANDROID = "+ANDROID";
200922d41b6ef202eac65991d27c43d74c828256f0dEdward Jee
201922d41b6ef202eac65991d27c43d74c828256f0dEdward Jee    /**
202c8fa4ff838a0c3d2c67db65540fa751e5abe27edJaikumar Ganesh     * Headset state when SCO audio is not connected.
20362c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh     * This state can be one of
20462c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh     * {@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} of
20562c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh     * {@link #ACTION_AUDIO_STATE_CHANGED} intent.
206005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly     */
207b0a1d01b4c044a0779cfe006e204bac468459802Jaikumar Ganesh    public static final int STATE_AUDIO_DISCONNECTED = 10;
2089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
210c8fa4ff838a0c3d2c67db65540fa751e5abe27edJaikumar Ganesh     * Headset state when SCO audio is connecting.
21162c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh     * This state can be one of
21262c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh     * {@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} of
21362c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh     * {@link #ACTION_AUDIO_STATE_CHANGED} intent.
2149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
215b0a1d01b4c044a0779cfe006e204bac468459802Jaikumar Ganesh    public static final int STATE_AUDIO_CONNECTING = 11;
21662c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh
21730d181690e48b26cdfae3b144d23f1e16c75da37Jaikumar Ganesh    /**
218c8fa4ff838a0c3d2c67db65540fa751e5abe27edJaikumar Ganesh     * Headset state when SCO audio is connected.
21930d181690e48b26cdfae3b144d23f1e16c75da37Jaikumar Ganesh     * This state can be one of
22030d181690e48b26cdfae3b144d23f1e16c75da37Jaikumar Ganesh     * {@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} of
22130d181690e48b26cdfae3b144d23f1e16c75da37Jaikumar Ganesh     * {@link #ACTION_AUDIO_STATE_CHANGED} intent.
22230d181690e48b26cdfae3b144d23f1e16c75da37Jaikumar Ganesh     */
223b0a1d01b4c044a0779cfe006e204bac468459802Jaikumar Ganesh    public static final int STATE_AUDIO_CONNECTED = 12;
224b0a1d01b4c044a0779cfe006e204bac468459802Jaikumar Ganesh
225e8b98925d08f720c4d22b626d0650de536840a9aBenjamin Franz    private static final int MESSAGE_HEADSET_SERVICE_CONNECTED = 100;
226e8b98925d08f720c4d22b626d0650de536840a9aBenjamin Franz    private static final int MESSAGE_HEADSET_SERVICE_DISCONNECTED = 101;
22762c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh
22862c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh    private Context mContext;
22962c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh    private ServiceListener mServiceListener;
23062c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh    private IBluetoothHeadset mService;
231bf246ef0abb6ea354fe412b139dec1adb4e5791dMatthew Xie    private BluetoothAdapter mAdapter;
2329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2330f42037eb7b5118015c2caca635538324ccf0ccffredc    final private IBluetoothStateChangeCallback mBluetoothStateChangeCallback =
2340f42037eb7b5118015c2caca635538324ccf0ccffredc            new IBluetoothStateChangeCallback.Stub() {
2350f42037eb7b5118015c2caca635538324ccf0ccffredc                public void onBluetoothStateChange(boolean up) {
2360f42037eb7b5118015c2caca635538324ccf0ccffredc                    if (DBG) Log.d(TAG, "onBluetoothStateChange: up=" + up);
2370f42037eb7b5118015c2caca635538324ccf0ccffredc                    if (!up) {
238563e414784eb81e4ea4051667d5c8855b17f7534Matthew Xie                        if (VDBG) Log.d(TAG,"Unbinding service...");
239e8b98925d08f720c4d22b626d0650de536840a9aBenjamin Franz                        doUnbind();
2400f42037eb7b5118015c2caca635538324ccf0ccffredc                    } else {
2410f42037eb7b5118015c2caca635538324ccf0ccffredc                        synchronized (mConnection) {
2420f42037eb7b5118015c2caca635538324ccf0ccffredc                            try {
2430f42037eb7b5118015c2caca635538324ccf0ccffredc                                if (mService == null) {
244563e414784eb81e4ea4051667d5c8855b17f7534Matthew Xie                                    if (VDBG) Log.d(TAG,"Binding service...");
245221ea892dcc661bd07d6f36ff012edca2c48aed4Dianne Hackborn                                    doBind();
2460f42037eb7b5118015c2caca635538324ccf0ccffredc                                }
2470f42037eb7b5118015c2caca635538324ccf0ccffredc                            } catch (Exception re) {
2480f42037eb7b5118015c2caca635538324ccf0ccffredc                                Log.e(TAG,"",re);
2490f42037eb7b5118015c2caca635538324ccf0ccffredc                            }
2500f42037eb7b5118015c2caca635538324ccf0ccffredc                        }
2510f42037eb7b5118015c2caca635538324ccf0ccffredc                    }
2520f42037eb7b5118015c2caca635538324ccf0ccffredc                }
2530f42037eb7b5118015c2caca635538324ccf0ccffredc        };
2540f42037eb7b5118015c2caca635538324ccf0ccffredc
2559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Create a BluetoothHeadset proxy object.
2579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
25862c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh    /*package*/ BluetoothHeadset(Context context, ServiceListener l) {
2599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext = context;
2609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mServiceListener = l;
26162c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh        mAdapter = BluetoothAdapter.getDefaultAdapter();
2620f42037eb7b5118015c2caca635538324ccf0ccffredc
2630f42037eb7b5118015c2caca635538324ccf0ccffredc        IBluetoothManager mgr = mAdapter.getBluetoothManager();
2640f42037eb7b5118015c2caca635538324ccf0ccffredc        if (mgr != null) {
2650f42037eb7b5118015c2caca635538324ccf0ccffredc            try {
2660f42037eb7b5118015c2caca635538324ccf0ccffredc                mgr.registerStateChangeCallback(mBluetoothStateChangeCallback);
2670f42037eb7b5118015c2caca635538324ccf0ccffredc            } catch (RemoteException e) {
2680f42037eb7b5118015c2caca635538324ccf0ccffredc                Log.e(TAG,"",e);
2690f42037eb7b5118015c2caca635538324ccf0ccffredc            }
2700f42037eb7b5118015c2caca635538324ccf0ccffredc        }
2710f42037eb7b5118015c2caca635538324ccf0ccffredc
272221ea892dcc661bd07d6f36ff012edca2c48aed4Dianne Hackborn        doBind();
273221ea892dcc661bd07d6f36ff012edca2c48aed4Dianne Hackborn    }
274221ea892dcc661bd07d6f36ff012edca2c48aed4Dianne Hackborn
275221ea892dcc661bd07d6f36ff012edca2c48aed4Dianne Hackborn    boolean doBind() {
276e8b98925d08f720c4d22b626d0650de536840a9aBenjamin Franz        try {
277e8b98925d08f720c4d22b626d0650de536840a9aBenjamin Franz            return mAdapter.getBluetoothManager().bindBluetoothProfileService(
278e8b98925d08f720c4d22b626d0650de536840a9aBenjamin Franz                    BluetoothProfile.HEADSET, mConnection);
279e8b98925d08f720c4d22b626d0650de536840a9aBenjamin Franz        } catch (RemoteException e) {
280e8b98925d08f720c4d22b626d0650de536840a9aBenjamin Franz            Log.e(TAG, "Unable to bind HeadsetService", e);
281e8b98925d08f720c4d22b626d0650de536840a9aBenjamin Franz        }
282e8b98925d08f720c4d22b626d0650de536840a9aBenjamin Franz        return false;
283e8b98925d08f720c4d22b626d0650de536840a9aBenjamin Franz    }
284e8b98925d08f720c4d22b626d0650de536840a9aBenjamin Franz
285e8b98925d08f720c4d22b626d0650de536840a9aBenjamin Franz    void doUnbind() {
286e8b98925d08f720c4d22b626d0650de536840a9aBenjamin Franz        synchronized (mConnection) {
287e8b98925d08f720c4d22b626d0650de536840a9aBenjamin Franz            if (mService != null) {
288e8b98925d08f720c4d22b626d0650de536840a9aBenjamin Franz                try {
289e8b98925d08f720c4d22b626d0650de536840a9aBenjamin Franz                    mAdapter.getBluetoothManager().unbindBluetoothProfileService(
290e8b98925d08f720c4d22b626d0650de536840a9aBenjamin Franz                            BluetoothProfile.HEADSET, mConnection);
291e8b98925d08f720c4d22b626d0650de536840a9aBenjamin Franz                } catch (RemoteException e) {
292e8b98925d08f720c4d22b626d0650de536840a9aBenjamin Franz                    Log.e(TAG,"Unable to unbind HeadsetService", e);
293e8b98925d08f720c4d22b626d0650de536840a9aBenjamin Franz                }
294e8b98925d08f720c4d22b626d0650de536840a9aBenjamin Franz            }
2959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Close the connection to the backing service.
3009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Other public functions of BluetoothHeadset will return default error
3019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * results once close() has been called. Multiple invocations of close()
3029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * are ok.
3039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
30413450df2b9264ef2220418f308037c19cec739a9Matthew Xie    /*package*/ void close() {
305563e414784eb81e4ea4051667d5c8855b17f7534Matthew Xie        if (VDBG) log("close()");
3060f42037eb7b5118015c2caca635538324ccf0ccffredc
3070f42037eb7b5118015c2caca635538324ccf0ccffredc        IBluetoothManager mgr = mAdapter.getBluetoothManager();
3080f42037eb7b5118015c2caca635538324ccf0ccffredc        if (mgr != null) {
3090f42037eb7b5118015c2caca635538324ccf0ccffredc            try {
3100f42037eb7b5118015c2caca635538324ccf0ccffredc                mgr.unregisterStateChangeCallback(mBluetoothStateChangeCallback);
3110f42037eb7b5118015c2caca635538324ccf0ccffredc            } catch (Exception e) {
3120f42037eb7b5118015c2caca635538324ccf0ccffredc                Log.e(TAG,"",e);
3130f42037eb7b5118015c2caca635538324ccf0ccffredc            }
3140f42037eb7b5118015c2caca635538324ccf0ccffredc        }
315c88b6bdcfada95447269b41d388fd7028dba574bBenjamin Franz        mServiceListener = null;
316e8b98925d08f720c4d22b626d0650de536840a9aBenjamin Franz        doUnbind();
3179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
320f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * Initiate connection to a profile of the remote bluetooth device.
321f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     *
322f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * <p> Currently, the system supports only 1 connection to the
323f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * headset/handsfree profile. The API will automatically disconnect connected
324f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * devices before connecting.
325f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     *
326f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * <p> This API returns false in scenarios like the profile on the
327f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * device is already connected or Bluetooth is not turned on.
328f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * When this API returns true, it is guaranteed that
329f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * connection state intent for the profile will be broadcasted with
330f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * the state. Users can get the connection state of the profile
331f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * from this intent.
332f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     *
333f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
334f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * permission.
335f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     *
336f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * @param device Remote Bluetooth Device
337f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * @return false on immediate error,
338f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     *               true otherwise
33962c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh     * @hide
3409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
34162c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh    public boolean connect(BluetoothDevice device) {
34262c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh        if (DBG) log("connect(" + device + ")");
34362c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh        if (mService != null && isEnabled() &&
34462c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh            isValidDevice(device)) {
3459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            try {
34662c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh                return mService.connect(device);
34762c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh            } catch (RemoteException e) {
34862c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh                Log.e(TAG, Log.getStackTraceString(new Throwable()));
34962c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh                return false;
35062c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh            }
3519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
35262c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh        if (mService == null) Log.w(TAG, "Proxy not attached to service");
35362c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh        return false;
3549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
357f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * Initiate disconnection from a profile
358f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     *
359f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * <p> This API will return false in scenarios like the profile on the
360f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * Bluetooth device is not in connected state etc. When this API returns,
361f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * true, it is guaranteed that the connection state change
362f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * intent will be broadcasted with the state. Users can get the
363f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * disconnection state of the profile from this intent.
364f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     *
365f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * <p> If the disconnection is initiated by a remote device, the state
366f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * will transition from {@link #STATE_CONNECTED} to
367f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * {@link #STATE_DISCONNECTED}. If the disconnect is initiated by the
368f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * host (local) device the state will transition from
369f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * {@link #STATE_CONNECTED} to state {@link #STATE_DISCONNECTING} to
370f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * state {@link #STATE_DISCONNECTED}. The transition to
371f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * {@link #STATE_DISCONNECTING} can be used to distinguish between the
372f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * two scenarios.
373f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     *
374f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
375f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * permission.
376f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     *
377f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * @param device Remote Bluetooth Device
378f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * @return false on immediate error,
379f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     *               true otherwise
38062c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh     * @hide
3819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
38262c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh    public boolean disconnect(BluetoothDevice device) {
38362c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh        if (DBG) log("disconnect(" + device + ")");
38462c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh        if (mService != null && isEnabled() &&
38562c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh            isValidDevice(device)) {
3869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            try {
38762c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh                return mService.disconnect(device);
38862c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh            } catch (RemoteException e) {
38962c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh              Log.e(TAG, Log.getStackTraceString(new Throwable()));
39062c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh              return false;
39162c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh            }
3929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
39362c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh        if (mService == null) Log.w(TAG, "Proxy not attached to service");
39462c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh        return false;
3959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
39862c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh     * {@inheritDoc}
3999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
40003cd78cf5e51c3adb78d2e3d314838dcf3e36b26Jaikumar Ganesh    public List<BluetoothDevice> getConnectedDevices() {
401563e414784eb81e4ea4051667d5c8855b17f7534Matthew Xie        if (VDBG) log("getConnectedDevices()");
40262c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh        if (mService != null && isEnabled()) {
4039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            try {
40403cd78cf5e51c3adb78d2e3d314838dcf3e36b26Jaikumar Ganesh                return mService.getConnectedDevices();
40562c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh            } catch (RemoteException e) {
40662c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh                Log.e(TAG, Log.getStackTraceString(new Throwable()));
40703cd78cf5e51c3adb78d2e3d314838dcf3e36b26Jaikumar Ganesh                return new ArrayList<BluetoothDevice>();
40862c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh            }
4099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
41062c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh        if (mService == null) Log.w(TAG, "Proxy not attached to service");
41103cd78cf5e51c3adb78d2e3d314838dcf3e36b26Jaikumar Ganesh        return new ArrayList<BluetoothDevice>();
4129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
41562c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh     * {@inheritDoc}
4169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
41703cd78cf5e51c3adb78d2e3d314838dcf3e36b26Jaikumar Ganesh    public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
418563e414784eb81e4ea4051667d5c8855b17f7534Matthew Xie        if (VDBG) log("getDevicesMatchingStates()");
41962c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh        if (mService != null && isEnabled()) {
4209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            try {
42103cd78cf5e51c3adb78d2e3d314838dcf3e36b26Jaikumar Ganesh                return mService.getDevicesMatchingConnectionStates(states);
42262c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh            } catch (RemoteException e) {
42362c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh                Log.e(TAG, Log.getStackTraceString(new Throwable()));
42403cd78cf5e51c3adb78d2e3d314838dcf3e36b26Jaikumar Ganesh                return new ArrayList<BluetoothDevice>();
42562c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh            }
4269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
42762c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh        if (mService == null) Log.w(TAG, "Proxy not attached to service");
42803cd78cf5e51c3adb78d2e3d314838dcf3e36b26Jaikumar Ganesh        return new ArrayList<BluetoothDevice>();
4299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
43262c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh     * {@inheritDoc}
4339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
43462c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh    public int getConnectionState(BluetoothDevice device) {
435563e414784eb81e4ea4051667d5c8855b17f7534Matthew Xie        if (VDBG) log("getConnectionState(" + device + ")");
43662c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh        if (mService != null && isEnabled() &&
43762c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh            isValidDevice(device)) {
4389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            try {
43962c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh                return mService.getConnectionState(device);
44062c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh            } catch (RemoteException e) {
44162c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh                Log.e(TAG, Log.getStackTraceString(new Throwable()));
44262c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh                return BluetoothProfile.STATE_DISCONNECTED;
44362c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh            }
4449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
44562c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh        if (mService == null) Log.w(TAG, "Proxy not attached to service");
44662c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh        return BluetoothProfile.STATE_DISCONNECTED;
4479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
450f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * Set priority of the profile
451f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     *
452f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * <p> The device should already be paired.
453f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     *  Priority can be one of {@link #PRIORITY_ON} or
454f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * {@link #PRIORITY_OFF},
455f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     *
456f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
457f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * permission.
458f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     *
459f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * @param device Paired bluetooth device
460f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * @param priority
461f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * @return true if priority is set, false on error
46262c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh     * @hide
4639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
46462c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh    public boolean setPriority(BluetoothDevice device, int priority) {
46562c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh        if (DBG) log("setPriority(" + device + ", " + priority + ")");
46662c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh        if (mService != null && isEnabled() &&
46762c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh            isValidDevice(device)) {
46862c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh            if (priority != BluetoothProfile.PRIORITY_OFF &&
4696f6c54519a9b15379bb79e195655b6bd4fc5967aGanesh Ganapathi Batta                priority != BluetoothProfile.PRIORITY_ON) {
47062c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh              return false;
47162c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh            }
4729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            try {
47362c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh                return mService.setPriority(device, priority);
47462c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh            } catch (RemoteException e) {
47562c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh                Log.e(TAG, Log.getStackTraceString(new Throwable()));
47662c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh                return false;
47762c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh            }
4789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
47962c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh        if (mService == null) Log.w(TAG, "Proxy not attached to service");
4809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return false;
4819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
484f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * Get the priority of the profile.
485f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     *
486f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * <p> The priority can be any of:
487f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * {@link #PRIORITY_AUTO_CONNECT}, {@link #PRIORITY_OFF},
488f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * {@link #PRIORITY_ON}, {@link #PRIORITY_UNDEFINED}
489f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     *
490f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
491f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     *
492f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * @param device Bluetooth device
493f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * @return priority of the device
49462c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh     * @hide
4959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
49662c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh    public int getPriority(BluetoothDevice device) {
497563e414784eb81e4ea4051667d5c8855b17f7534Matthew Xie        if (VDBG) log("getPriority(" + device + ")");
49862c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh        if (mService != null && isEnabled() &&
49962c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh            isValidDevice(device)) {
5009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            try {
50162c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh                return mService.getPriority(device);
50262c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh            } catch (RemoteException e) {
50362c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh                Log.e(TAG, Log.getStackTraceString(new Throwable()));
50462c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh                return PRIORITY_OFF;
50562c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh            }
5069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
50762c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh        if (mService == null) Log.w(TAG, "Proxy not attached to service");
50862c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh        return PRIORITY_OFF;
50962c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh    }
51062c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh
51162c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh    /**
51262c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh     * Start Bluetooth voice recognition. This methods sends the voice
51362c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh     * recognition AT command to the headset and establishes the
51462c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh     * audio connection.
51562c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh     *
51662c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh     * <p> Users can listen to {@link #ACTION_AUDIO_STATE_CHANGED}.
517b0a1d01b4c044a0779cfe006e204bac468459802Jaikumar Ganesh     * If this function returns true, this intent will be broadcasted with
518b0a1d01b4c044a0779cfe006e204bac468459802Jaikumar Ganesh     * {@link #EXTRA_STATE} set to {@link #STATE_AUDIO_CONNECTING}.
519b0a1d01b4c044a0779cfe006e204bac468459802Jaikumar Ganesh     *
520b0a1d01b4c044a0779cfe006e204bac468459802Jaikumar Ganesh     * <p> {@link #EXTRA_STATE} will transition from
521b0a1d01b4c044a0779cfe006e204bac468459802Jaikumar Ganesh     * {@link #STATE_AUDIO_CONNECTING} to {@link #STATE_AUDIO_CONNECTED} when
522b0a1d01b4c044a0779cfe006e204bac468459802Jaikumar Ganesh     * audio connection is established and to {@link #STATE_AUDIO_DISCONNECTED}
523b0a1d01b4c044a0779cfe006e204bac468459802Jaikumar Ganesh     * in case of failure to establish the audio connection.
52462c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh     *
525b0a1d01b4c044a0779cfe006e204bac468459802Jaikumar Ganesh     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
52662c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh     *
52762c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh     * @param device Bluetooth headset
52862c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh     * @return false if there is no headset connected of if the
52962c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh     *               connected headset doesn't support voice recognition
53062c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh     *               or on error, true otherwise
53162c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh     */
53262c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh    public boolean startVoiceRecognition(BluetoothDevice device) {
53362c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh        if (DBG) log("startVoiceRecognition()");
53462c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh        if (mService != null && isEnabled() &&
53562c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh            isValidDevice(device)) {
53662c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh            try {
53762c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh                return mService.startVoiceRecognition(device);
53862c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh            } catch (RemoteException e) {
53962c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh                Log.e(TAG,  Log.getStackTraceString(new Throwable()));
54062c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh            }
54162c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh        }
54262c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh        if (mService == null) Log.w(TAG, "Proxy not attached to service");
5439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return false;
5449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
54762c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh     * Stop Bluetooth Voice Recognition mode, and shut down the
54862c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh     * Bluetooth audio path.
54962c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh     *
550c8fa4ff838a0c3d2c67db65540fa751e5abe27edJaikumar Ganesh     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
55162c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh     *
55262c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh     * @param device Bluetooth headset
55362c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh     * @return false if there is no headset connected
55462c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh     *               or on error, true otherwise
5559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
55662c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh    public boolean stopVoiceRecognition(BluetoothDevice device) {
55762c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh        if (DBG) log("stopVoiceRecognition()");
55862c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh        if (mService != null && isEnabled() &&
55962c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh            isValidDevice(device)) {
5609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            try {
56162c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh                return mService.stopVoiceRecognition(device);
56262c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh            } catch (RemoteException e) {
56362c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh                Log.e(TAG,  Log.getStackTraceString(new Throwable()));
56462c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh            }
5659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
56662c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh        if (mService == null) Log.w(TAG, "Proxy not attached to service");
5679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return false;
5689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
57162c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh     * Check if Bluetooth SCO audio is connected.
57262c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh     *
573c8fa4ff838a0c3d2c67db65540fa751e5abe27edJaikumar Ganesh     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
57462c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh     *
57562c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh     * @param device Bluetooth headset
57662c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh     * @return true if SCO is connected,
57762c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh     *         false otherwise or on error
5789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
57962c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh    public boolean isAudioConnected(BluetoothDevice device) {
580563e414784eb81e4ea4051667d5c8855b17f7534Matthew Xie        if (VDBG) log("isAudioConnected()");
58162c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh        if (mService != null && isEnabled() &&
58262c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh            isValidDevice(device)) {
5839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            try {
58462c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh              return mService.isAudioConnected(device);
58562c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh            } catch (RemoteException e) {
58662c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh              Log.e(TAG,  Log.getStackTraceString(new Throwable()));
58762c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh            }
5886c901db72dbaf57d8fdf26adae6721de14ecae22Nick Pelly        }
58962c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh        if (mService == null) Log.w(TAG, "Proxy not attached to service");
59062c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh        return false;
5916c901db72dbaf57d8fdf26adae6721de14ecae22Nick Pelly    }
5926c901db72dbaf57d8fdf26adae6721de14ecae22Nick Pelly
5936c901db72dbaf57d8fdf26adae6721de14ecae22Nick Pelly    /**
5946c901db72dbaf57d8fdf26adae6721de14ecae22Nick Pelly     * Get battery usage hint for Bluetooth Headset service.
5956c901db72dbaf57d8fdf26adae6721de14ecae22Nick Pelly     * This is a monotonically increasing integer. Wraps to 0 at
5966c901db72dbaf57d8fdf26adae6721de14ecae22Nick Pelly     * Integer.MAX_INT, and at boot.
5976c901db72dbaf57d8fdf26adae6721de14ecae22Nick Pelly     * Current implementation returns the number of AT commands handled since
5986c901db72dbaf57d8fdf26adae6721de14ecae22Nick Pelly     * boot. This is a good indicator for spammy headset/handsfree units that
5996c901db72dbaf57d8fdf26adae6721de14ecae22Nick Pelly     * can keep the device awake by polling for cellular status updates. As a
6006c901db72dbaf57d8fdf26adae6721de14ecae22Nick Pelly     * rule of thumb, each AT command prevents the CPU from sleeping for 500 ms
60162c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh     *
60262c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh     * @param device the bluetooth headset.
6036c901db72dbaf57d8fdf26adae6721de14ecae22Nick Pelly     * @return monotonically increasing battery usage hint, or a negative error
6046c901db72dbaf57d8fdf26adae6721de14ecae22Nick Pelly     *         code on error
6056c901db72dbaf57d8fdf26adae6721de14ecae22Nick Pelly     * @hide
6066c901db72dbaf57d8fdf26adae6721de14ecae22Nick Pelly     */
60762c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh    public int getBatteryUsageHint(BluetoothDevice device) {
608563e414784eb81e4ea4051667d5c8855b17f7534Matthew Xie        if (VDBG) log("getBatteryUsageHint()");
60962c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh        if (mService != null && isEnabled() &&
61062c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh            isValidDevice(device)) {
6116c901db72dbaf57d8fdf26adae6721de14ecae22Nick Pelly            try {
61262c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh                return mService.getBatteryUsageHint(device);
61362c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh            } catch (RemoteException e) {
61462c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh                Log.e(TAG,  Log.getStackTraceString(new Throwable()));
61562c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh            }
6169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
61762c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh        if (mService == null) Log.w(TAG, "Proxy not attached to service");
6189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return -1;
6199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
62062c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh
621d726b35ebd8660022dcea706ee6d3ca51886b04eEric Laurent    /**
622d726b35ebd8660022dcea706ee6d3ca51886b04eEric Laurent     * Indicates if current platform supports voice dialing over bluetooth SCO.
62362c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh     *
624d726b35ebd8660022dcea706ee6d3ca51886b04eEric Laurent     * @return true if voice dialing over bluetooth is supported, false otherwise.
625d726b35ebd8660022dcea706ee6d3ca51886b04eEric Laurent     * @hide
626d726b35ebd8660022dcea706ee6d3ca51886b04eEric Laurent     */
627d726b35ebd8660022dcea706ee6d3ca51886b04eEric Laurent    public static boolean isBluetoothVoiceDialingEnabled(Context context) {
628d726b35ebd8660022dcea706ee6d3ca51886b04eEric Laurent        return context.getResources().getBoolean(
629d726b35ebd8660022dcea706ee6d3ca51886b04eEric Laurent                com.android.internal.R.bool.config_bluetooth_sco_off_call);
630d726b35ebd8660022dcea706ee6d3ca51886b04eEric Laurent    }
631d726b35ebd8660022dcea706ee6d3ca51886b04eEric Laurent
6329b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    /**
6339b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh     * Accept the incoming connection.
63462c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh     * Note: This is an internal function and shouldn't be exposed
63562c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh     *
6369b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh     * @hide
6379b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh     */
6389b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    public boolean acceptIncomingConnect(BluetoothDevice device) {
6399b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        if (DBG) log("acceptIncomingConnect");
64062c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh        if (mService != null && isEnabled()) {
6419b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            try {
6429b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                return mService.acceptIncomingConnect(device);
6439b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            } catch (RemoteException e) {Log.e(TAG, e.toString());}
6449b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        } else {
6459b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            Log.w(TAG, "Proxy not attached to service");
6469b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
6479b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        }
6489b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        return false;
6499b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    }
6509b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
6519b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    /**
652a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie     * Reject the incoming connection.
653a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie     * @hide
654a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie     */
655a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie    public boolean rejectIncomingConnect(BluetoothDevice device) {
656a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie        if (DBG) log("rejectIncomingConnect");
657a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie        if (mService != null) {
658a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie            try {
659a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie                return mService.rejectIncomingConnect(device);
660a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie            } catch (RemoteException e) {Log.e(TAG, e.toString());}
661a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie        } else {
662a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie            Log.w(TAG, "Proxy not attached to service");
663a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie            if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
664a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie        }
665a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie        return false;
666a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie    }
667a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie
668a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie    /**
6693e8c82edb1feafc796aa52efafedc13f794c4dcdMatthew Xie     * Get the current audio state of the Headset.
6709b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh     * Note: This is an internal function and shouldn't be exposed
67162c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh     *
6729b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh     * @hide
6739b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh     */
6743e8c82edb1feafc796aa52efafedc13f794c4dcdMatthew Xie    public int getAudioState(BluetoothDevice device) {
675563e414784eb81e4ea4051667d5c8855b17f7534Matthew Xie        if (VDBG) log("getAudioState");
6763e8c82edb1feafc796aa52efafedc13f794c4dcdMatthew Xie        if (mService != null && !isDisabled()) {
6779b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            try {
6783e8c82edb1feafc796aa52efafedc13f794c4dcdMatthew Xie                return mService.getAudioState(device);
6799b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            } catch (RemoteException e) {Log.e(TAG, e.toString());}
6809b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        } else {
6819b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            Log.w(TAG, "Proxy not attached to service");
6829b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
6839b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        }
6843e8c82edb1feafc796aa52efafedc13f794c4dcdMatthew Xie        return BluetoothHeadset.STATE_AUDIO_DISCONNECTED;
6859b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    }
6869b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
6879b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    /**
6883e8c82edb1feafc796aa52efafedc13f794c4dcdMatthew Xie     * Check if Bluetooth SCO audio is connected.
6893e8c82edb1feafc796aa52efafedc13f794c4dcdMatthew Xie     *
6903e8c82edb1feafc796aa52efafedc13f794c4dcdMatthew Xie     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
69162c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh     *
6923e8c82edb1feafc796aa52efafedc13f794c4dcdMatthew Xie     * @return true if SCO is connected,
6933e8c82edb1feafc796aa52efafedc13f794c4dcdMatthew Xie     *         false otherwise or on error
6949b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh     * @hide
6959b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh     */
6963e8c82edb1feafc796aa52efafedc13f794c4dcdMatthew Xie    public boolean isAudioOn() {
697563e414784eb81e4ea4051667d5c8855b17f7534Matthew Xie        if (VDBG) log("isAudioOn()");
6983e8c82edb1feafc796aa52efafedc13f794c4dcdMatthew Xie        if (mService != null && isEnabled()) {
6999b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            try {
7003e8c82edb1feafc796aa52efafedc13f794c4dcdMatthew Xie              return mService.isAudioOn();
7013e8c82edb1feafc796aa52efafedc13f794c4dcdMatthew Xie            } catch (RemoteException e) {
7023e8c82edb1feafc796aa52efafedc13f794c4dcdMatthew Xie              Log.e(TAG,  Log.getStackTraceString(new Throwable()));
7033e8c82edb1feafc796aa52efafedc13f794c4dcdMatthew Xie            }
7049b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        }
7053e8c82edb1feafc796aa52efafedc13f794c4dcdMatthew Xie        if (mService == null) Log.w(TAG, "Proxy not attached to service");
7069b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        return false;
7073e8c82edb1feafc796aa52efafedc13f794c4dcdMatthew Xie
7089b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    }
70962c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh
71062c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh    /**
7113e8c82edb1feafc796aa52efafedc13f794c4dcdMatthew Xie     * Initiates a connection of headset audio.
7123e8c82edb1feafc796aa52efafedc13f794c4dcdMatthew Xie     * It setup SCO channel with remote connected headset device.
71362c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh     *
7143e8c82edb1feafc796aa52efafedc13f794c4dcdMatthew Xie     * @return true if successful
7153e8c82edb1feafc796aa52efafedc13f794c4dcdMatthew Xie     *         false if there was some error such as
7163e8c82edb1feafc796aa52efafedc13f794c4dcdMatthew Xie     *               there is no connected headset
71762c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh     * @hide
71862c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh     */
7193e8c82edb1feafc796aa52efafedc13f794c4dcdMatthew Xie    public boolean connectAudio() {
7203e8c82edb1feafc796aa52efafedc13f794c4dcdMatthew Xie        if (mService != null && isEnabled()) {
72162c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh            try {
7223e8c82edb1feafc796aa52efafedc13f794c4dcdMatthew Xie                return mService.connectAudio();
7233e8c82edb1feafc796aa52efafedc13f794c4dcdMatthew Xie            } catch (RemoteException e) {
7243e8c82edb1feafc796aa52efafedc13f794c4dcdMatthew Xie                Log.e(TAG, e.toString());
7253e8c82edb1feafc796aa52efafedc13f794c4dcdMatthew Xie            }
72662c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh        } else {
72762c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh            Log.w(TAG, "Proxy not attached to service");
72862c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh            if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
72962c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh        }
73062c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh        return false;
73162c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh    }
73262c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh
73330d181690e48b26cdfae3b144d23f1e16c75da37Jaikumar Ganesh    /**
7343e8c82edb1feafc796aa52efafedc13f794c4dcdMatthew Xie     * Initiates a disconnection of headset audio.
7353e8c82edb1feafc796aa52efafedc13f794c4dcdMatthew Xie     * It tears down the SCO channel from remote headset device.
73630d181690e48b26cdfae3b144d23f1e16c75da37Jaikumar Ganesh     *
7373e8c82edb1feafc796aa52efafedc13f794c4dcdMatthew Xie     * @return true if successful
7383e8c82edb1feafc796aa52efafedc13f794c4dcdMatthew Xie     *         false if there was some error such as
7393e8c82edb1feafc796aa52efafedc13f794c4dcdMatthew Xie     *               there is no connected SCO channel
74030d181690e48b26cdfae3b144d23f1e16c75da37Jaikumar Ganesh     * @hide
74130d181690e48b26cdfae3b144d23f1e16c75da37Jaikumar Ganesh     */
7423e8c82edb1feafc796aa52efafedc13f794c4dcdMatthew Xie    public boolean disconnectAudio() {
7433e8c82edb1feafc796aa52efafedc13f794c4dcdMatthew Xie        if (mService != null && isEnabled()) {
74430d181690e48b26cdfae3b144d23f1e16c75da37Jaikumar Ganesh            try {
7453e8c82edb1feafc796aa52efafedc13f794c4dcdMatthew Xie                return mService.disconnectAudio();
7463e8c82edb1feafc796aa52efafedc13f794c4dcdMatthew Xie            } catch (RemoteException e) {
7473e8c82edb1feafc796aa52efafedc13f794c4dcdMatthew Xie                Log.e(TAG, e.toString());
7483e8c82edb1feafc796aa52efafedc13f794c4dcdMatthew Xie            }
74930d181690e48b26cdfae3b144d23f1e16c75da37Jaikumar Ganesh        } else {
75030d181690e48b26cdfae3b144d23f1e16c75da37Jaikumar Ganesh            Log.w(TAG, "Proxy not attached to service");
75130d181690e48b26cdfae3b144d23f1e16c75da37Jaikumar Ganesh            if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
75230d181690e48b26cdfae3b144d23f1e16c75da37Jaikumar Ganesh        }
7533e8c82edb1feafc796aa52efafedc13f794c4dcdMatthew Xie        return false;
75430d181690e48b26cdfae3b144d23f1e16c75da37Jaikumar Ganesh    }
75530d181690e48b26cdfae3b144d23f1e16c75da37Jaikumar Ganesh
756f2e6b13620f3ebbb94166834abaaabcc08a403b7Jaikumar Ganesh    /**
757dde68c64fd8e97a592633ec4c09283ec928e5697Jaikumar Ganesh     * Initiates a SCO channel connection with the headset (if connected).
758dde68c64fd8e97a592633ec4c09283ec928e5697Jaikumar Ganesh     * Also initiates a virtual voice call for Handsfree devices as many devices
759dde68c64fd8e97a592633ec4c09283ec928e5697Jaikumar Ganesh     * do not accept SCO audio without a call.
760dde68c64fd8e97a592633ec4c09283ec928e5697Jaikumar Ganesh     * This API allows the handsfree device to be used for routing non-cellular
761dde68c64fd8e97a592633ec4c09283ec928e5697Jaikumar Ganesh     * call audio.
762f2e6b13620f3ebbb94166834abaaabcc08a403b7Jaikumar Ganesh     *
763f2e6b13620f3ebbb94166834abaaabcc08a403b7Jaikumar Ganesh     * @param device Remote Bluetooth Device
764f2e6b13620f3ebbb94166834abaaabcc08a403b7Jaikumar Ganesh     * @return true if successful, false if there was some error.
765f2e6b13620f3ebbb94166834abaaabcc08a403b7Jaikumar Ganesh     * @hide
766f2e6b13620f3ebbb94166834abaaabcc08a403b7Jaikumar Ganesh     */
767dde68c64fd8e97a592633ec4c09283ec928e5697Jaikumar Ganesh    public boolean startScoUsingVirtualVoiceCall(BluetoothDevice device) {
768dde68c64fd8e97a592633ec4c09283ec928e5697Jaikumar Ganesh        if (DBG) log("startScoUsingVirtualVoiceCall()");
769f2e6b13620f3ebbb94166834abaaabcc08a403b7Jaikumar Ganesh        if (mService != null && isEnabled() && isValidDevice(device)) {
770f2e6b13620f3ebbb94166834abaaabcc08a403b7Jaikumar Ganesh            try {
771dde68c64fd8e97a592633ec4c09283ec928e5697Jaikumar Ganesh                return mService.startScoUsingVirtualVoiceCall(device);
772f2e6b13620f3ebbb94166834abaaabcc08a403b7Jaikumar Ganesh            } catch (RemoteException e) {
773f2e6b13620f3ebbb94166834abaaabcc08a403b7Jaikumar Ganesh                Log.e(TAG, e.toString());
774f2e6b13620f3ebbb94166834abaaabcc08a403b7Jaikumar Ganesh            }
775f2e6b13620f3ebbb94166834abaaabcc08a403b7Jaikumar Ganesh        } else {
776f2e6b13620f3ebbb94166834abaaabcc08a403b7Jaikumar Ganesh            Log.w(TAG, "Proxy not attached to service");
777f2e6b13620f3ebbb94166834abaaabcc08a403b7Jaikumar Ganesh            if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
778f2e6b13620f3ebbb94166834abaaabcc08a403b7Jaikumar Ganesh        }
779f2e6b13620f3ebbb94166834abaaabcc08a403b7Jaikumar Ganesh        return false;
780f2e6b13620f3ebbb94166834abaaabcc08a403b7Jaikumar Ganesh    }
781f2e6b13620f3ebbb94166834abaaabcc08a403b7Jaikumar Ganesh
782f2e6b13620f3ebbb94166834abaaabcc08a403b7Jaikumar Ganesh    /**
783dde68c64fd8e97a592633ec4c09283ec928e5697Jaikumar Ganesh     * Terminates an ongoing SCO connection and the associated virtual
784dde68c64fd8e97a592633ec4c09283ec928e5697Jaikumar Ganesh     * call.
785f2e6b13620f3ebbb94166834abaaabcc08a403b7Jaikumar Ganesh     *
786f2e6b13620f3ebbb94166834abaaabcc08a403b7Jaikumar Ganesh     * @param device Remote Bluetooth Device
787f2e6b13620f3ebbb94166834abaaabcc08a403b7Jaikumar Ganesh     * @return true if successful, false if there was some error.
788f2e6b13620f3ebbb94166834abaaabcc08a403b7Jaikumar Ganesh     * @hide
789f2e6b13620f3ebbb94166834abaaabcc08a403b7Jaikumar Ganesh     */
790dde68c64fd8e97a592633ec4c09283ec928e5697Jaikumar Ganesh    public boolean stopScoUsingVirtualVoiceCall(BluetoothDevice device) {
791dde68c64fd8e97a592633ec4c09283ec928e5697Jaikumar Ganesh        if (DBG) log("stopScoUsingVirtualVoiceCall()");
792f2e6b13620f3ebbb94166834abaaabcc08a403b7Jaikumar Ganesh        if (mService != null && isEnabled() && isValidDevice(device)) {
793f2e6b13620f3ebbb94166834abaaabcc08a403b7Jaikumar Ganesh            try {
794dde68c64fd8e97a592633ec4c09283ec928e5697Jaikumar Ganesh                return mService.stopScoUsingVirtualVoiceCall(device);
795f2e6b13620f3ebbb94166834abaaabcc08a403b7Jaikumar Ganesh            } catch (RemoteException e) {
796f2e6b13620f3ebbb94166834abaaabcc08a403b7Jaikumar Ganesh                Log.e(TAG, e.toString());
797f2e6b13620f3ebbb94166834abaaabcc08a403b7Jaikumar Ganesh            }
798f2e6b13620f3ebbb94166834abaaabcc08a403b7Jaikumar Ganesh        } else {
799f2e6b13620f3ebbb94166834abaaabcc08a403b7Jaikumar Ganesh            Log.w(TAG, "Proxy not attached to service");
800f2e6b13620f3ebbb94166834abaaabcc08a403b7Jaikumar Ganesh            if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
801f2e6b13620f3ebbb94166834abaaabcc08a403b7Jaikumar Ganesh        }
802f2e6b13620f3ebbb94166834abaaabcc08a403b7Jaikumar Ganesh        return false;
803f2e6b13620f3ebbb94166834abaaabcc08a403b7Jaikumar Ganesh    }
804f2e6b13620f3ebbb94166834abaaabcc08a403b7Jaikumar Ganesh
8053e8c82edb1feafc796aa52efafedc13f794c4dcdMatthew Xie    /**
8063e8c82edb1feafc796aa52efafedc13f794c4dcdMatthew Xie     * Notify Headset of phone state change.
8073e8c82edb1feafc796aa52efafedc13f794c4dcdMatthew Xie     * This is a backdoor for phone app to call BluetoothHeadset since
8083e8c82edb1feafc796aa52efafedc13f794c4dcdMatthew Xie     * there is currently not a good way to get precise call state change outside
8093e8c82edb1feafc796aa52efafedc13f794c4dcdMatthew Xie     * of phone app.
8103e8c82edb1feafc796aa52efafedc13f794c4dcdMatthew Xie     *
8113e8c82edb1feafc796aa52efafedc13f794c4dcdMatthew Xie     * @hide
8123e8c82edb1feafc796aa52efafedc13f794c4dcdMatthew Xie     */
8133e8c82edb1feafc796aa52efafedc13f794c4dcdMatthew Xie    public void phoneStateChanged(int numActive, int numHeld, int callState, String number,
8143e8c82edb1feafc796aa52efafedc13f794c4dcdMatthew Xie                                  int type) {
8153e8c82edb1feafc796aa52efafedc13f794c4dcdMatthew Xie        if (mService != null && isEnabled()) {
8163e8c82edb1feafc796aa52efafedc13f794c4dcdMatthew Xie            try {
8173e8c82edb1feafc796aa52efafedc13f794c4dcdMatthew Xie                mService.phoneStateChanged(numActive, numHeld, callState, number, type);
8183e8c82edb1feafc796aa52efafedc13f794c4dcdMatthew Xie            } catch (RemoteException e) {
8193e8c82edb1feafc796aa52efafedc13f794c4dcdMatthew Xie                Log.e(TAG, e.toString());
8203e8c82edb1feafc796aa52efafedc13f794c4dcdMatthew Xie            }
8213e8c82edb1feafc796aa52efafedc13f794c4dcdMatthew Xie        } else {
8223e8c82edb1feafc796aa52efafedc13f794c4dcdMatthew Xie            Log.w(TAG, "Proxy not attached to service");
8233e8c82edb1feafc796aa52efafedc13f794c4dcdMatthew Xie            if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
8243e8c82edb1feafc796aa52efafedc13f794c4dcdMatthew Xie        }
8253e8c82edb1feafc796aa52efafedc13f794c4dcdMatthew Xie    }
8263e8c82edb1feafc796aa52efafedc13f794c4dcdMatthew Xie
8273e8c82edb1feafc796aa52efafedc13f794c4dcdMatthew Xie    /**
8283e8c82edb1feafc796aa52efafedc13f794c4dcdMatthew Xie     * Send Headset of CLCC response
8293e8c82edb1feafc796aa52efafedc13f794c4dcdMatthew Xie     *
8303e8c82edb1feafc796aa52efafedc13f794c4dcdMatthew Xie     * @hide
8313e8c82edb1feafc796aa52efafedc13f794c4dcdMatthew Xie     */
8323e8c82edb1feafc796aa52efafedc13f794c4dcdMatthew Xie    public void clccResponse(int index, int direction, int status, int mode, boolean mpty,
8333e8c82edb1feafc796aa52efafedc13f794c4dcdMatthew Xie                             String number, int type) {
8343e8c82edb1feafc796aa52efafedc13f794c4dcdMatthew Xie        if (mService != null && isEnabled()) {
8353e8c82edb1feafc796aa52efafedc13f794c4dcdMatthew Xie            try {
8363e8c82edb1feafc796aa52efafedc13f794c4dcdMatthew Xie                mService.clccResponse(index, direction, status, mode, mpty, number, type);
8373e8c82edb1feafc796aa52efafedc13f794c4dcdMatthew Xie            } catch (RemoteException e) {
8383e8c82edb1feafc796aa52efafedc13f794c4dcdMatthew Xie                Log.e(TAG, e.toString());
8393e8c82edb1feafc796aa52efafedc13f794c4dcdMatthew Xie            }
8403e8c82edb1feafc796aa52efafedc13f794c4dcdMatthew Xie        } else {
8413e8c82edb1feafc796aa52efafedc13f794c4dcdMatthew Xie            Log.w(TAG, "Proxy not attached to service");
8423e8c82edb1feafc796aa52efafedc13f794c4dcdMatthew Xie            if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
8433e8c82edb1feafc796aa52efafedc13f794c4dcdMatthew Xie        }
8443e8c82edb1feafc796aa52efafedc13f794c4dcdMatthew Xie    }
8453e8c82edb1feafc796aa52efafedc13f794c4dcdMatthew Xie
846922d41b6ef202eac65991d27c43d74c828256f0dEdward Jee    /**
847922d41b6ef202eac65991d27c43d74c828256f0dEdward Jee     * Sends a vendor-specific unsolicited result code to the headset.
848922d41b6ef202eac65991d27c43d74c828256f0dEdward Jee     *
849922d41b6ef202eac65991d27c43d74c828256f0dEdward Jee     * <p>The actual string to be sent is <code>command + ": " + arg</code>.
850b240578f0333f5b35472cb11d6d7b5bb1da431ccYing Wang     * For example, if {@code command} is {@link #VENDOR_RESULT_CODE_COMMAND_ANDROID} and {@code arg}
851922d41b6ef202eac65991d27c43d74c828256f0dEdward Jee     * is {@code "0"}, the string <code>"+ANDROID: 0"</code> will be sent.
852922d41b6ef202eac65991d27c43d74c828256f0dEdward Jee     *
853b240578f0333f5b35472cb11d6d7b5bb1da431ccYing Wang     * <p>Currently only {@link #VENDOR_RESULT_CODE_COMMAND_ANDROID} is allowed as {@code command}.
854922d41b6ef202eac65991d27c43d74c828256f0dEdward Jee     *
855922d41b6ef202eac65991d27c43d74c828256f0dEdward Jee     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
856922d41b6ef202eac65991d27c43d74c828256f0dEdward Jee     *
857922d41b6ef202eac65991d27c43d74c828256f0dEdward Jee     * @param device Bluetooth headset.
858922d41b6ef202eac65991d27c43d74c828256f0dEdward Jee     * @param command A vendor-specific command.
859922d41b6ef202eac65991d27c43d74c828256f0dEdward Jee     * @param arg The argument that will be attached to the command.
860922d41b6ef202eac65991d27c43d74c828256f0dEdward Jee     * @return {@code false} if there is no headset connected, or if the command is not an allowed
861922d41b6ef202eac65991d27c43d74c828256f0dEdward Jee     *         vendor-specific unsolicited result code, or on error. {@code true} otherwise.
862922d41b6ef202eac65991d27c43d74c828256f0dEdward Jee     * @throws IllegalArgumentException if {@code command} is {@code null}.
863922d41b6ef202eac65991d27c43d74c828256f0dEdward Jee     */
864922d41b6ef202eac65991d27c43d74c828256f0dEdward Jee    public boolean sendVendorSpecificResultCode(BluetoothDevice device, String command,
865922d41b6ef202eac65991d27c43d74c828256f0dEdward Jee            String arg) {
866922d41b6ef202eac65991d27c43d74c828256f0dEdward Jee        if (DBG) {
867922d41b6ef202eac65991d27c43d74c828256f0dEdward Jee            log("sendVendorSpecificResultCode()");
868922d41b6ef202eac65991d27c43d74c828256f0dEdward Jee        }
869922d41b6ef202eac65991d27c43d74c828256f0dEdward Jee        if (command == null) {
870922d41b6ef202eac65991d27c43d74c828256f0dEdward Jee            throw new IllegalArgumentException("command is null");
871922d41b6ef202eac65991d27c43d74c828256f0dEdward Jee        }
872922d41b6ef202eac65991d27c43d74c828256f0dEdward Jee        if (mService != null && isEnabled() &&
873922d41b6ef202eac65991d27c43d74c828256f0dEdward Jee                isValidDevice(device)) {
874922d41b6ef202eac65991d27c43d74c828256f0dEdward Jee            try {
875922d41b6ef202eac65991d27c43d74c828256f0dEdward Jee                return mService.sendVendorSpecificResultCode(device, command, arg);
876922d41b6ef202eac65991d27c43d74c828256f0dEdward Jee            } catch (RemoteException e) {
877922d41b6ef202eac65991d27c43d74c828256f0dEdward Jee                Log.e(TAG, Log.getStackTraceString(new Throwable()));
878922d41b6ef202eac65991d27c43d74c828256f0dEdward Jee            }
879922d41b6ef202eac65991d27c43d74c828256f0dEdward Jee        }
880922d41b6ef202eac65991d27c43d74c828256f0dEdward Jee        if (mService == null) {
881922d41b6ef202eac65991d27c43d74c828256f0dEdward Jee            Log.w(TAG, "Proxy not attached to service");
882922d41b6ef202eac65991d27c43d74c828256f0dEdward Jee        }
883922d41b6ef202eac65991d27c43d74c828256f0dEdward Jee        return false;
884922d41b6ef202eac65991d27c43d74c828256f0dEdward Jee    }
885922d41b6ef202eac65991d27c43d74c828256f0dEdward Jee
886177d078d90f9659cfc7f091d1fdeb5712b357123Mudumba Ananth    /**
887177d078d90f9659cfc7f091d1fdeb5712b357123Mudumba Ananth     * enable WBS codec setting.
888177d078d90f9659cfc7f091d1fdeb5712b357123Mudumba Ananth     *
889177d078d90f9659cfc7f091d1fdeb5712b357123Mudumba Ananth     * @return true if successful
890177d078d90f9659cfc7f091d1fdeb5712b357123Mudumba Ananth     *         false if there was some error such as
891177d078d90f9659cfc7f091d1fdeb5712b357123Mudumba Ananth     *               there is no connected headset
892177d078d90f9659cfc7f091d1fdeb5712b357123Mudumba Ananth     * @hide
893177d078d90f9659cfc7f091d1fdeb5712b357123Mudumba Ananth     */
894177d078d90f9659cfc7f091d1fdeb5712b357123Mudumba Ananth    public boolean enableWBS() {
895177d078d90f9659cfc7f091d1fdeb5712b357123Mudumba Ananth        if (mService != null && isEnabled()) {
896177d078d90f9659cfc7f091d1fdeb5712b357123Mudumba Ananth            try {
897177d078d90f9659cfc7f091d1fdeb5712b357123Mudumba Ananth                return mService.enableWBS();
898177d078d90f9659cfc7f091d1fdeb5712b357123Mudumba Ananth            } catch (RemoteException e) {
899177d078d90f9659cfc7f091d1fdeb5712b357123Mudumba Ananth                Log.e(TAG, e.toString());
900177d078d90f9659cfc7f091d1fdeb5712b357123Mudumba Ananth            }
901177d078d90f9659cfc7f091d1fdeb5712b357123Mudumba Ananth        } else {
902177d078d90f9659cfc7f091d1fdeb5712b357123Mudumba Ananth            Log.w(TAG, "Proxy not attached to service");
903177d078d90f9659cfc7f091d1fdeb5712b357123Mudumba Ananth            if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
904177d078d90f9659cfc7f091d1fdeb5712b357123Mudumba Ananth        }
905177d078d90f9659cfc7f091d1fdeb5712b357123Mudumba Ananth        return false;
906177d078d90f9659cfc7f091d1fdeb5712b357123Mudumba Ananth    }
907177d078d90f9659cfc7f091d1fdeb5712b357123Mudumba Ananth
908177d078d90f9659cfc7f091d1fdeb5712b357123Mudumba Ananth    /**
909177d078d90f9659cfc7f091d1fdeb5712b357123Mudumba Ananth     * disable WBS codec settting. It set NBS codec.
910177d078d90f9659cfc7f091d1fdeb5712b357123Mudumba Ananth     *
911177d078d90f9659cfc7f091d1fdeb5712b357123Mudumba Ananth     * @return true if successful
912177d078d90f9659cfc7f091d1fdeb5712b357123Mudumba Ananth     *         false if there was some error such as
913177d078d90f9659cfc7f091d1fdeb5712b357123Mudumba Ananth     *               there is no connected headset
914177d078d90f9659cfc7f091d1fdeb5712b357123Mudumba Ananth     * @hide
915177d078d90f9659cfc7f091d1fdeb5712b357123Mudumba Ananth     */
916177d078d90f9659cfc7f091d1fdeb5712b357123Mudumba Ananth    public boolean disableWBS() {
917177d078d90f9659cfc7f091d1fdeb5712b357123Mudumba Ananth        if (mService != null && isEnabled()) {
918177d078d90f9659cfc7f091d1fdeb5712b357123Mudumba Ananth            try {
919177d078d90f9659cfc7f091d1fdeb5712b357123Mudumba Ananth                return mService.disableWBS();
920177d078d90f9659cfc7f091d1fdeb5712b357123Mudumba Ananth            } catch (RemoteException e) {
921177d078d90f9659cfc7f091d1fdeb5712b357123Mudumba Ananth                Log.e(TAG, e.toString());
922177d078d90f9659cfc7f091d1fdeb5712b357123Mudumba Ananth            }
923177d078d90f9659cfc7f091d1fdeb5712b357123Mudumba Ananth        } else {
924177d078d90f9659cfc7f091d1fdeb5712b357123Mudumba Ananth            Log.w(TAG, "Proxy not attached to service");
925177d078d90f9659cfc7f091d1fdeb5712b357123Mudumba Ananth            if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
926177d078d90f9659cfc7f091d1fdeb5712b357123Mudumba Ananth        }
927177d078d90f9659cfc7f091d1fdeb5712b357123Mudumba Ananth        return false;
928177d078d90f9659cfc7f091d1fdeb5712b357123Mudumba Ananth    }
929177d078d90f9659cfc7f091d1fdeb5712b357123Mudumba Ananth
930e8b98925d08f720c4d22b626d0650de536840a9aBenjamin Franz    private final IBluetoothProfileServiceConnection mConnection
931e8b98925d08f720c4d22b626d0650de536840a9aBenjamin Franz            = new IBluetoothProfileServiceConnection.Stub()  {
932e8b98925d08f720c4d22b626d0650de536840a9aBenjamin Franz        @Override
9339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void onServiceConnected(ComponentName className, IBinder service) {
9349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (DBG) Log.d(TAG, "Proxy object connected");
9359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mService = IBluetoothHeadset.Stub.asInterface(service);
936e8b98925d08f720c4d22b626d0650de536840a9aBenjamin Franz            mHandler.sendMessage(mHandler.obtainMessage(
937e8b98925d08f720c4d22b626d0650de536840a9aBenjamin Franz                    MESSAGE_HEADSET_SERVICE_CONNECTED));
9389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
939e8b98925d08f720c4d22b626d0650de536840a9aBenjamin Franz        @Override
9409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void onServiceDisconnected(ComponentName className) {
9419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (DBG) Log.d(TAG, "Proxy object disconnected");
9429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mService = null;
943e8b98925d08f720c4d22b626d0650de536840a9aBenjamin Franz            mHandler.sendMessage(mHandler.obtainMessage(
944e8b98925d08f720c4d22b626d0650de536840a9aBenjamin Franz                    MESSAGE_HEADSET_SERVICE_DISCONNECTED));
9459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    };
947f5b4b98fada53d91c4c2ebeb5a1d33ccc95c94d2The Android Open Source Project
94862c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh    private boolean isEnabled() {
94962c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh       if (mAdapter.getState() == BluetoothAdapter.STATE_ON) return true;
95062c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh       return false;
95162c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh    }
95262c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh
9536f7a9736602ba1f1dc5a16542aa947861a520ec5Jaikumar Ganesh    private boolean isDisabled() {
9546f7a9736602ba1f1dc5a16542aa947861a520ec5Jaikumar Ganesh       if (mAdapter.getState() == BluetoothAdapter.STATE_OFF) return true;
9556f7a9736602ba1f1dc5a16542aa947861a520ec5Jaikumar Ganesh       return false;
9566f7a9736602ba1f1dc5a16542aa947861a520ec5Jaikumar Ganesh    }
9576f7a9736602ba1f1dc5a16542aa947861a520ec5Jaikumar Ganesh
95862c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh    private boolean isValidDevice(BluetoothDevice device) {
95962c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh       if (device == null) return false;
96062c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh
96162c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh       if (BluetoothAdapter.checkBluetoothAddress(device.getAddress())) return true;
96262c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh       return false;
96362c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh    }
96462c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh
965f5b4b98fada53d91c4c2ebeb5a1d33ccc95c94d2The Android Open Source Project    private static void log(String msg) {
966f5b4b98fada53d91c4c2ebeb5a1d33ccc95c94d2The Android Open Source Project        Log.d(TAG, msg);
967f5b4b98fada53d91c4c2ebeb5a1d33ccc95c94d2The Android Open Source Project    }
968e8b98925d08f720c4d22b626d0650de536840a9aBenjamin Franz
969e8b98925d08f720c4d22b626d0650de536840a9aBenjamin Franz    private final Handler mHandler = new Handler(Looper.getMainLooper()) {
970e8b98925d08f720c4d22b626d0650de536840a9aBenjamin Franz        @Override
971e8b98925d08f720c4d22b626d0650de536840a9aBenjamin Franz        public void handleMessage(Message msg) {
972e8b98925d08f720c4d22b626d0650de536840a9aBenjamin Franz            switch (msg.what) {
973e8b98925d08f720c4d22b626d0650de536840a9aBenjamin Franz                case MESSAGE_HEADSET_SERVICE_CONNECTED: {
974e8b98925d08f720c4d22b626d0650de536840a9aBenjamin Franz                    if (mServiceListener != null) {
975e8b98925d08f720c4d22b626d0650de536840a9aBenjamin Franz                        mServiceListener.onServiceConnected(BluetoothProfile.HEADSET,
976e8b98925d08f720c4d22b626d0650de536840a9aBenjamin Franz                                BluetoothHeadset.this);
977e8b98925d08f720c4d22b626d0650de536840a9aBenjamin Franz                    }
978e8b98925d08f720c4d22b626d0650de536840a9aBenjamin Franz                    break;
979e8b98925d08f720c4d22b626d0650de536840a9aBenjamin Franz                }
980e8b98925d08f720c4d22b626d0650de536840a9aBenjamin Franz                case MESSAGE_HEADSET_SERVICE_DISCONNECTED: {
981e8b98925d08f720c4d22b626d0650de536840a9aBenjamin Franz                    if (mServiceListener != null) {
982e8b98925d08f720c4d22b626d0650de536840a9aBenjamin Franz                        mServiceListener.onServiceDisconnected(BluetoothProfile.HEADSET);
983e8b98925d08f720c4d22b626d0650de536840a9aBenjamin Franz                    }
984e8b98925d08f720c4d22b626d0650de536840a9aBenjamin Franz                    break;
985e8b98925d08f720c4d22b626d0650de536840a9aBenjamin Franz                }
986e8b98925d08f720c4d22b626d0650de536840a9aBenjamin Franz            }
987e8b98925d08f720c4d22b626d0650de536840a9aBenjamin Franz        }
988e8b98925d08f720c4d22b626d0650de536840a9aBenjamin Franz    };
9899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
990