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
192d49752ee050ab7f1cd848933f6c62a73707e2d9Tor Norbyeimport android.Manifest;
202d49752ee050ab7f1cd848933f6c62a73707e2d9Tor Norbyeimport android.annotation.RequiresPermission;
219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.annotation.SdkConstant;
229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.annotation.SdkConstant.SdkConstantType;
233e8c82edb1feafc796aa52efafedc13f794c4dcdMatthew Xieimport android.content.ComponentName;
249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Context;
253e8c82edb1feafc796aa52efafedc13f794c4dcdMatthew Xieimport android.content.Intent;
263e8c82edb1feafc796aa52efafedc13f794c4dcdMatthew Xieimport android.content.ServiceConnection;
274197cb60bc74629fe4c04ab10cb3b1c9a7427d24RoboErikimport android.media.AudioManager;
280a17db1cc5942ea000ca87bb72853de57a15ec64Jeff Sharkeyimport android.os.Binder;
299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.IBinder;
3041d5c805d96aef0aaa9a2aaa86ccc4b77ca75e11Jaikumar Ganeshimport android.os.ParcelUuid;
3162c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganeshimport android.os.RemoteException;
329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.Log;
339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
34d7d16b9f372116da1658f589df213aed33c2ded6Calvin Onimport com.android.internal.annotations.GuardedBy;
35d7d16b9f372116da1658f589df213aed33c2ded6Calvin On
3603cd78cf5e51c3adb78d2e3d314838dcf3e36b26Jaikumar Ganeshimport java.util.ArrayList;
3703cd78cf5e51c3adb78d2e3d314838dcf3e36b26Jaikumar Ganeshimport java.util.List;
38d7d16b9f372116da1658f589df213aed33c2ded6Calvin Onimport java.util.concurrent.locks.ReentrantReadWriteLock;
3962c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh
409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/**
4262c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh * This class provides the public APIs to control the Bluetooth A2DP
4362c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh * profile.
449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
4562c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh *<p>BluetoothA2dp is a proxy object for controlling the Bluetooth A2DP
4662c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh * Service via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get
4762c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh * the BluetoothA2dp proxy object.
489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
4962c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh * <p> Android only supports one connected Bluetooth A2dp device at a time.
5062c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh * Each method is protected with its appropriate permission.
519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
5262c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganeshpublic final class BluetoothA2dp implements BluetoothProfile {
539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String TAG = "BluetoothA2dp";
543e8c82edb1feafc796aa52efafedc13f794c4dcdMatthew Xie    private static final boolean DBG = true;
55563e414784eb81e4ea4051667d5c8855b17f7534Matthew Xie    private static final boolean VDBG = false;
569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5762c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh    /**
5862c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh     * Intent used to broadcast the change in connection state of the A2DP
5962c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh     * profile.
6062c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh     *
6162c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh     * <p>This intent will have 3 extras:
62c8fa4ff838a0c3d2c67db65540fa751e5abe27edJaikumar Ganesh     * <ul>
63c8fa4ff838a0c3d2c67db65540fa751e5abe27edJaikumar Ganesh     *   <li> {@link #EXTRA_STATE} - The current state of the profile. </li>
64c8fa4ff838a0c3d2c67db65540fa751e5abe27edJaikumar Ganesh     *   <li> {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile.</li>
65c8fa4ff838a0c3d2c67db65540fa751e5abe27edJaikumar Ganesh     *   <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li>
66c8fa4ff838a0c3d2c67db65540fa751e5abe27edJaikumar Ganesh     * </ul>
6762c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh     *
680706fed52075f7f2b25101a40287519ac18d3184Jaikumar Ganesh     * <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of
6962c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh     * {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING},
7062c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh     * {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}.
7162c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh     *
72c8fa4ff838a0c3d2c67db65540fa751e5abe27edJaikumar Ganesh     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
73c8fa4ff838a0c3d2c67db65540fa751e5abe27edJaikumar Ganesh     * receive.
7462c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh     */
7562c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
7662c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh    public static final String ACTION_CONNECTION_STATE_CHANGED =
7762c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh        "android.bluetooth.a2dp.profile.action.CONNECTION_STATE_CHANGED";
789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7962c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh    /**
8062c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh     * Intent used to broadcast the change in the Playing state of the A2DP
8162c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh     * profile.
8262c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh     *
8362c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh     * <p>This intent will have 3 extras:
84c8fa4ff838a0c3d2c67db65540fa751e5abe27edJaikumar Ganesh     * <ul>
85c8fa4ff838a0c3d2c67db65540fa751e5abe27edJaikumar Ganesh     *   <li> {@link #EXTRA_STATE} - The current state of the profile. </li>
86c8fa4ff838a0c3d2c67db65540fa751e5abe27edJaikumar Ganesh     *   <li> {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile. </li>
870706fed52075f7f2b25101a40287519ac18d3184Jaikumar Ganesh     *   <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li>
88c8fa4ff838a0c3d2c67db65540fa751e5abe27edJaikumar Ganesh     * </ul>
8962c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh     *
900706fed52075f7f2b25101a40287519ac18d3184Jaikumar Ganesh     * <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of
9162c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh     * {@link #STATE_PLAYING}, {@link #STATE_NOT_PLAYING},
9262c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh     *
93c8fa4ff838a0c3d2c67db65540fa751e5abe27edJaikumar Ganesh     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
94c8fa4ff838a0c3d2c67db65540fa751e5abe27edJaikumar Ganesh     * receive.
959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
9762c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh    public static final String ACTION_PLAYING_STATE_CHANGED =
9862c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh        "android.bluetooth.a2dp.profile.action.PLAYING_STATE_CHANGED";
999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1003b76a4b2b62e9539e2629dc569d7e9a934e65dfbHemant Gupta    /** @hide */
1013b76a4b2b62e9539e2629dc569d7e9a934e65dfbHemant Gupta    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
1023b76a4b2b62e9539e2629dc569d7e9a934e65dfbHemant Gupta    public static final String ACTION_AVRCP_CONNECTION_STATE_CHANGED =
1033b76a4b2b62e9539e2629dc569d7e9a934e65dfbHemant Gupta        "android.bluetooth.a2dp.profile.action.AVRCP_CONNECTION_STATE_CHANGED";
1043b76a4b2b62e9539e2629dc569d7e9a934e65dfbHemant Gupta
10562c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh    /**
10644a4ef0aa93ebb2912f36d65af42ffbb1bcdbc0fPavlin Radoslavov     * Intent used to broadcast the change in the Audio Codec state of the
10744a4ef0aa93ebb2912f36d65af42ffbb1bcdbc0fPavlin Radoslavov     * A2DP Source profile.
10844a4ef0aa93ebb2912f36d65af42ffbb1bcdbc0fPavlin Radoslavov     *
109b37f181c9853bd0d55d360db95d3bf1bba0b5a6fPavlin Radoslavov     * <p>This intent will have 2 extras:
11044a4ef0aa93ebb2912f36d65af42ffbb1bcdbc0fPavlin Radoslavov     * <ul>
111b37f181c9853bd0d55d360db95d3bf1bba0b5a6fPavlin Radoslavov     *   <li> {@link BluetoothCodecStatus#EXTRA_CODEC_STATUS} - The codec status. </li>
11244a4ef0aa93ebb2912f36d65af42ffbb1bcdbc0fPavlin Radoslavov     *   <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device if the device is currently
11344a4ef0aa93ebb2912f36d65af42ffbb1bcdbc0fPavlin Radoslavov     *   connected, otherwise it is not included.</li>
11444a4ef0aa93ebb2912f36d65af42ffbb1bcdbc0fPavlin Radoslavov     * </ul>
11544a4ef0aa93ebb2912f36d65af42ffbb1bcdbc0fPavlin Radoslavov     *
11644a4ef0aa93ebb2912f36d65af42ffbb1bcdbc0fPavlin Radoslavov     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
11744a4ef0aa93ebb2912f36d65af42ffbb1bcdbc0fPavlin Radoslavov     * receive.
11844a4ef0aa93ebb2912f36d65af42ffbb1bcdbc0fPavlin Radoslavov     *
11944a4ef0aa93ebb2912f36d65af42ffbb1bcdbc0fPavlin Radoslavov     * @hide
12044a4ef0aa93ebb2912f36d65af42ffbb1bcdbc0fPavlin Radoslavov     */
12144a4ef0aa93ebb2912f36d65af42ffbb1bcdbc0fPavlin Radoslavov    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
12244a4ef0aa93ebb2912f36d65af42ffbb1bcdbc0fPavlin Radoslavov    public static final String ACTION_CODEC_CONFIG_CHANGED =
12344a4ef0aa93ebb2912f36d65af42ffbb1bcdbc0fPavlin Radoslavov        "android.bluetooth.a2dp.profile.action.CODEC_CONFIG_CHANGED";
12444a4ef0aa93ebb2912f36d65af42ffbb1bcdbc0fPavlin Radoslavov
12544a4ef0aa93ebb2912f36d65af42ffbb1bcdbc0fPavlin Radoslavov    /**
12662c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh     * A2DP sink device is streaming music. This state can be one of
12762c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh     * {@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} of
12862c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh     * {@link #ACTION_PLAYING_STATE_CHANGED} intent.
12962c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh     */
13062c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh    public static final int STATE_PLAYING   =  10;
1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13262c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh    /**
13362c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh     * A2DP sink device is NOT streaming music. This state can be one of
13462c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh     * {@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} of
13562c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh     * {@link #ACTION_PLAYING_STATE_CHANGED} intent.
13662c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh     */
13762c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh    public static final int STATE_NOT_PLAYING   =  11;
138bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly
139f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent    /**
140f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent     * We don't have a stored preference for whether or not the given A2DP sink device supports
141f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent     * optional codecs.
142f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent     * @hide */
143f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent    public static final int OPTIONAL_CODECS_SUPPORT_UNKNOWN = -1;
144f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent
145f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent    /**
146f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent     * The given A2DP sink device does not support optional codecs.
147f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent     * @hide */
148f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent    public static final int OPTIONAL_CODECS_NOT_SUPPORTED = 0;
149f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent
150f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent    /**
151f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent     * The given A2DP sink device does support optional codecs.
152f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent     * @hide */
153f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent    public static final int OPTIONAL_CODECS_SUPPORTED = 1;
154f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent
155f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent    /**
156f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent     * We don't have a stored preference for whether optional codecs should be enabled or disabled
157f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent     * for the given A2DP device.
158f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent     * @hide */
159f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent    public static final int OPTIONAL_CODECS_PREF_UNKNOWN = -1;
160f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent
161f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent    /**
162f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent     * Optional codecs should be disabled for the given A2DP device.
163f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent     * @hide */
164f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent    public static final int OPTIONAL_CODECS_PREF_DISABLED = 0;
165f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent
166f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent    /**
167f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent     *  Optional codecs should be enabled for the given A2DP device.
168f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent     *  @hide */
169f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent    public static final int OPTIONAL_CODECS_PREF_ENABLED = 1;
170f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent
1713e8c82edb1feafc796aa52efafedc13f794c4dcdMatthew Xie    private Context mContext;
17262c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh    private ServiceListener mServiceListener;
173d7d16b9f372116da1658f589df213aed33c2ded6Calvin On    private final ReentrantReadWriteLock mServiceLock = new ReentrantReadWriteLock();
174d7d16b9f372116da1658f589df213aed33c2ded6Calvin On    @GuardedBy("mServiceLock") private IBluetoothA2dp mService;
17562c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh    private BluetoothAdapter mAdapter;
1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1770f42037eb7b5118015c2caca635538324ccf0ccffredc    final private IBluetoothStateChangeCallback mBluetoothStateChangeCallback =
1780f42037eb7b5118015c2caca635538324ccf0ccffredc            new IBluetoothStateChangeCallback.Stub() {
1790f42037eb7b5118015c2caca635538324ccf0ccffredc                public void onBluetoothStateChange(boolean up) {
1800f42037eb7b5118015c2caca635538324ccf0ccffredc                    if (DBG) Log.d(TAG, "onBluetoothStateChange: up=" + up);
1810f42037eb7b5118015c2caca635538324ccf0ccffredc                    if (!up) {
182d7d16b9f372116da1658f589df213aed33c2ded6Calvin On                        if (VDBG) Log.d(TAG, "Unbinding service...");
183d7d16b9f372116da1658f589df213aed33c2ded6Calvin On                        try {
184d7d16b9f372116da1658f589df213aed33c2ded6Calvin On                            mServiceLock.writeLock().lock();
185d7d16b9f372116da1658f589df213aed33c2ded6Calvin On                            mService = null;
186d7d16b9f372116da1658f589df213aed33c2ded6Calvin On                            mContext.unbindService(mConnection);
187d7d16b9f372116da1658f589df213aed33c2ded6Calvin On                        } catch (Exception re) {
188d7d16b9f372116da1658f589df213aed33c2ded6Calvin On                            Log.e(TAG, "", re);
189d7d16b9f372116da1658f589df213aed33c2ded6Calvin On                        } finally {
190d7d16b9f372116da1658f589df213aed33c2ded6Calvin On                            mServiceLock.writeLock().unlock();
1910f42037eb7b5118015c2caca635538324ccf0ccffredc                        }
1920f42037eb7b5118015c2caca635538324ccf0ccffredc                    } else {
193d7d16b9f372116da1658f589df213aed33c2ded6Calvin On                        try {
194d7d16b9f372116da1658f589df213aed33c2ded6Calvin On                            mServiceLock.readLock().lock();
195d7d16b9f372116da1658f589df213aed33c2ded6Calvin On                            if (mService == null) {
196d7d16b9f372116da1658f589df213aed33c2ded6Calvin On                                if (VDBG) Log.d(TAG,"Binding service...");
197d7d16b9f372116da1658f589df213aed33c2ded6Calvin On                                doBind();
1980f42037eb7b5118015c2caca635538324ccf0ccffredc                            }
199d7d16b9f372116da1658f589df213aed33c2ded6Calvin On                        } catch (Exception re) {
200d7d16b9f372116da1658f589df213aed33c2ded6Calvin On                            Log.e(TAG,"",re);
201d7d16b9f372116da1658f589df213aed33c2ded6Calvin On                        } finally {
202d7d16b9f372116da1658f589df213aed33c2ded6Calvin On                            mServiceLock.readLock().unlock();
2030f42037eb7b5118015c2caca635538324ccf0ccffredc                        }
2040f42037eb7b5118015c2caca635538324ccf0ccffredc                    }
2050f42037eb7b5118015c2caca635538324ccf0ccffredc                }
2060f42037eb7b5118015c2caca635538324ccf0ccffredc        };
2079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Create a BluetoothA2dp proxy object for interacting with the local
2099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Bluetooth A2DP service.
21062c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh     *
2119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2123e8c82edb1feafc796aa52efafedc13f794c4dcdMatthew Xie    /*package*/ BluetoothA2dp(Context context, ServiceListener l) {
2133e8c82edb1feafc796aa52efafedc13f794c4dcdMatthew Xie        mContext = context;
21462c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh        mServiceListener = l;
21562c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh        mAdapter = BluetoothAdapter.getDefaultAdapter();
2160f42037eb7b5118015c2caca635538324ccf0ccffredc        IBluetoothManager mgr = mAdapter.getBluetoothManager();
2170f42037eb7b5118015c2caca635538324ccf0ccffredc        if (mgr != null) {
2180f42037eb7b5118015c2caca635538324ccf0ccffredc            try {
2190f42037eb7b5118015c2caca635538324ccf0ccffredc                mgr.registerStateChangeCallback(mBluetoothStateChangeCallback);
2200f42037eb7b5118015c2caca635538324ccf0ccffredc            } catch (RemoteException e) {
2210f42037eb7b5118015c2caca635538324ccf0ccffredc                Log.e(TAG,"",e);
2220f42037eb7b5118015c2caca635538324ccf0ccffredc            }
2230f42037eb7b5118015c2caca635538324ccf0ccffredc        }
2240f42037eb7b5118015c2caca635538324ccf0ccffredc
225221ea892dcc661bd07d6f36ff012edca2c48aed4Dianne Hackborn        doBind();
226221ea892dcc661bd07d6f36ff012edca2c48aed4Dianne Hackborn    }
227221ea892dcc661bd07d6f36ff012edca2c48aed4Dianne Hackborn
228221ea892dcc661bd07d6f36ff012edca2c48aed4Dianne Hackborn    boolean doBind() {
229221ea892dcc661bd07d6f36ff012edca2c48aed4Dianne Hackborn        Intent intent = new Intent(IBluetoothA2dp.class.getName());
230221ea892dcc661bd07d6f36ff012edca2c48aed4Dianne Hackborn        ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
231221ea892dcc661bd07d6f36ff012edca2c48aed4Dianne Hackborn        intent.setComponent(comp);
232466ce96da8ca7ea8c97e716b02a7d55007179aa1Dianne Hackborn        if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0,
233466ce96da8ca7ea8c97e716b02a7d55007179aa1Dianne Hackborn                android.os.Process.myUserHandle())) {
234221ea892dcc661bd07d6f36ff012edca2c48aed4Dianne Hackborn            Log.e(TAG, "Could not bind to Bluetooth A2DP Service with " + intent);
235221ea892dcc661bd07d6f36ff012edca2c48aed4Dianne Hackborn            return false;
2369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
237221ea892dcc661bd07d6f36ff012edca2c48aed4Dianne Hackborn        return true;
2389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2409bb275197df8eb999eab4cdd0a2aff83c2bb2ef6Jaikumar Ganesh    /*package*/ void close() {
2419bb275197df8eb999eab4cdd0a2aff83c2bb2ef6Jaikumar Ganesh        mServiceListener = null;
2420f42037eb7b5118015c2caca635538324ccf0ccffredc        IBluetoothManager mgr = mAdapter.getBluetoothManager();
2430f42037eb7b5118015c2caca635538324ccf0ccffredc        if (mgr != null) {
2440f42037eb7b5118015c2caca635538324ccf0ccffredc            try {
2450f42037eb7b5118015c2caca635538324ccf0ccffredc                mgr.unregisterStateChangeCallback(mBluetoothStateChangeCallback);
2460f42037eb7b5118015c2caca635538324ccf0ccffredc            } catch (Exception e) {
2470f42037eb7b5118015c2caca635538324ccf0ccffredc                Log.e(TAG,"",e);
2480f42037eb7b5118015c2caca635538324ccf0ccffredc            }
2490f42037eb7b5118015c2caca635538324ccf0ccffredc        }
2500f42037eb7b5118015c2caca635538324ccf0ccffredc
251d7d16b9f372116da1658f589df213aed33c2ded6Calvin On        try {
252d7d16b9f372116da1658f589df213aed33c2ded6Calvin On            mServiceLock.writeLock().lock();
2530f42037eb7b5118015c2caca635538324ccf0ccffredc            if (mService != null) {
254d7d16b9f372116da1658f589df213aed33c2ded6Calvin On                mService = null;
255d7d16b9f372116da1658f589df213aed33c2ded6Calvin On                mContext.unbindService(mConnection);
2560f42037eb7b5118015c2caca635538324ccf0ccffredc            }
257d7d16b9f372116da1658f589df213aed33c2ded6Calvin On        } catch (Exception re) {
258d7d16b9f372116da1658f589df213aed33c2ded6Calvin On            Log.e(TAG, "", re);
259d7d16b9f372116da1658f589df213aed33c2ded6Calvin On        } finally {
260d7d16b9f372116da1658f589df213aed33c2ded6Calvin On            mServiceLock.writeLock().unlock();
2610f42037eb7b5118015c2caca635538324ccf0ccffredc        }
2629bb275197df8eb999eab4cdd0a2aff83c2bb2ef6Jaikumar Ganesh    }
2639bb275197df8eb999eab4cdd0a2aff83c2bb2ef6Jaikumar Ganesh
2640f42037eb7b5118015c2caca635538324ccf0ccffredc    public void finalize() {
2652d2d8c28545c687dbb105006ef4554eac8480313Mathias Jeppsson        // The empty finalize needs to be kept or the
2662d2d8c28545c687dbb105006ef4554eac8480313Mathias Jeppsson        // cts signature tests would fail.
2670f42037eb7b5118015c2caca635538324ccf0ccffredc    }
26862c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh    /**
269f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * Initiate connection to a profile of the remote bluetooth device.
270f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     *
271f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * <p> Currently, the system supports only 1 connection to the
272f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * A2DP profile. The API will automatically disconnect connected
273f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * devices before connecting.
274f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     *
275f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * <p> This API returns false in scenarios like the profile on the
276f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * device is already connected or Bluetooth is not turned on.
277f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * When this API returns true, it is guaranteed that
278f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * connection state intent for the profile will be broadcasted with
279f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * the state. Users can get the connection state of the profile
280f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * from this intent.
281f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     *
282f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
283f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * permission.
284f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     *
285f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * @param device Remote Bluetooth Device
286f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * @return false on immediate error,
287f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     *               true otherwise
28862c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh     * @hide
2899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
29062c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh    public boolean connect(BluetoothDevice device) {
29162c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh        if (DBG) log("connect(" + device + ")");
292d7d16b9f372116da1658f589df213aed33c2ded6Calvin On        try {
293d7d16b9f372116da1658f589df213aed33c2ded6Calvin On            mServiceLock.readLock().lock();
294d7d16b9f372116da1658f589df213aed33c2ded6Calvin On            if (mService != null && isEnabled() &&
295d7d16b9f372116da1658f589df213aed33c2ded6Calvin On                isValidDevice(device)) {
29662c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh                return mService.connect(device);
29762c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh            }
298d7d16b9f372116da1658f589df213aed33c2ded6Calvin On            if (mService == null) Log.w(TAG, "Proxy not attached to service");
299d7d16b9f372116da1658f589df213aed33c2ded6Calvin On            return false;
300d7d16b9f372116da1658f589df213aed33c2ded6Calvin On        } catch (RemoteException e) {
301d7d16b9f372116da1658f589df213aed33c2ded6Calvin On            Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
302d7d16b9f372116da1658f589df213aed33c2ded6Calvin On            return false;
303d7d16b9f372116da1658f589df213aed33c2ded6Calvin On        } finally {
304d7d16b9f372116da1658f589df213aed33c2ded6Calvin On            mServiceLock.readLock().unlock();
3059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
30862c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh    /**
309f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * Initiate disconnection from a profile
310f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     *
311f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * <p> This API will return false in scenarios like the profile on the
312f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * Bluetooth device is not in connected state etc. When this API returns,
313f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * true, it is guaranteed that the connection state change
314f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * intent will be broadcasted with the state. Users can get the
315f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * disconnection state of the profile from this intent.
316f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     *
317f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * <p> If the disconnection is initiated by a remote device, the state
318f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * will transition from {@link #STATE_CONNECTED} to
319f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * {@link #STATE_DISCONNECTED}. If the disconnect is initiated by the
320f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * host (local) device the state will transition from
321f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * {@link #STATE_CONNECTED} to state {@link #STATE_DISCONNECTING} to
322f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * state {@link #STATE_DISCONNECTED}. The transition to
323f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * {@link #STATE_DISCONNECTING} can be used to distinguish between the
324f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * two scenarios.
325f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     *
326f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
327f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * permission.
328f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     *
329f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * @param device Remote Bluetooth Device
330f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * @return false on immediate error,
331f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     *               true otherwise
33262c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh     * @hide
3339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
33462c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh    public boolean disconnect(BluetoothDevice device) {
33562c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh        if (DBG) log("disconnect(" + device + ")");
336d7d16b9f372116da1658f589df213aed33c2ded6Calvin On        try {
337d7d16b9f372116da1658f589df213aed33c2ded6Calvin On            mServiceLock.readLock().lock();
338d7d16b9f372116da1658f589df213aed33c2ded6Calvin On            if (mService != null && isEnabled() &&
339d7d16b9f372116da1658f589df213aed33c2ded6Calvin On                isValidDevice(device)) {
34062c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh                return mService.disconnect(device);
34162c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh            }
342d7d16b9f372116da1658f589df213aed33c2ded6Calvin On            if (mService == null) Log.w(TAG, "Proxy not attached to service");
343d7d16b9f372116da1658f589df213aed33c2ded6Calvin On            return false;
344d7d16b9f372116da1658f589df213aed33c2ded6Calvin On        } catch (RemoteException e) {
345d7d16b9f372116da1658f589df213aed33c2ded6Calvin On            Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
346d7d16b9f372116da1658f589df213aed33c2ded6Calvin On            return false;
347d7d16b9f372116da1658f589df213aed33c2ded6Calvin On        } finally {
348d7d16b9f372116da1658f589df213aed33c2ded6Calvin On            mServiceLock.readLock().unlock();
3499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
35262c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh    /**
35362c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh     * {@inheritDoc}
354f9bbe1e71a502fe7bd1f4a23ba5bbe4dde0d9d57Zhu Lan     */
35503cd78cf5e51c3adb78d2e3d314838dcf3e36b26Jaikumar Ganesh    public List<BluetoothDevice> getConnectedDevices() {
356563e414784eb81e4ea4051667d5c8855b17f7534Matthew Xie        if (VDBG) log("getConnectedDevices()");
357d7d16b9f372116da1658f589df213aed33c2ded6Calvin On        try {
358d7d16b9f372116da1658f589df213aed33c2ded6Calvin On            mServiceLock.readLock().lock();
359d7d16b9f372116da1658f589df213aed33c2ded6Calvin On            if (mService != null && isEnabled()) {
36003cd78cf5e51c3adb78d2e3d314838dcf3e36b26Jaikumar Ganesh                return mService.getConnectedDevices();
36162c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh            }
362d7d16b9f372116da1658f589df213aed33c2ded6Calvin On            if (mService == null) Log.w(TAG, "Proxy not attached to service");
363d7d16b9f372116da1658f589df213aed33c2ded6Calvin On            return new ArrayList<BluetoothDevice>();
364d7d16b9f372116da1658f589df213aed33c2ded6Calvin On        } catch (RemoteException e) {
365d7d16b9f372116da1658f589df213aed33c2ded6Calvin On            Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
366d7d16b9f372116da1658f589df213aed33c2ded6Calvin On            return new ArrayList<BluetoothDevice>();
367d7d16b9f372116da1658f589df213aed33c2ded6Calvin On        } finally {
368d7d16b9f372116da1658f589df213aed33c2ded6Calvin On            mServiceLock.readLock().unlock();
369f9bbe1e71a502fe7bd1f4a23ba5bbe4dde0d9d57Zhu Lan        }
370f9bbe1e71a502fe7bd1f4a23ba5bbe4dde0d9d57Zhu Lan    }
371f9bbe1e71a502fe7bd1f4a23ba5bbe4dde0d9d57Zhu Lan
37262c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh    /**
37362c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh     * {@inheritDoc}
374f9bbe1e71a502fe7bd1f4a23ba5bbe4dde0d9d57Zhu Lan     */
37503cd78cf5e51c3adb78d2e3d314838dcf3e36b26Jaikumar Ganesh    public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
376563e414784eb81e4ea4051667d5c8855b17f7534Matthew Xie        if (VDBG) log("getDevicesMatchingStates()");
377d7d16b9f372116da1658f589df213aed33c2ded6Calvin On        try {
378d7d16b9f372116da1658f589df213aed33c2ded6Calvin On            mServiceLock.readLock().lock();
379d7d16b9f372116da1658f589df213aed33c2ded6Calvin On            if (mService != null && isEnabled()) {
38003cd78cf5e51c3adb78d2e3d314838dcf3e36b26Jaikumar Ganesh                return mService.getDevicesMatchingConnectionStates(states);
38162c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh            }
382d7d16b9f372116da1658f589df213aed33c2ded6Calvin On            if (mService == null) Log.w(TAG, "Proxy not attached to service");
383d7d16b9f372116da1658f589df213aed33c2ded6Calvin On            return new ArrayList<BluetoothDevice>();
384d7d16b9f372116da1658f589df213aed33c2ded6Calvin On        } catch (RemoteException e) {
385d7d16b9f372116da1658f589df213aed33c2ded6Calvin On            Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
386d7d16b9f372116da1658f589df213aed33c2ded6Calvin On            return new ArrayList<BluetoothDevice>();
387d7d16b9f372116da1658f589df213aed33c2ded6Calvin On        } finally {
388d7d16b9f372116da1658f589df213aed33c2ded6Calvin On            mServiceLock.readLock().unlock();
389f9bbe1e71a502fe7bd1f4a23ba5bbe4dde0d9d57Zhu Lan        }
390f9bbe1e71a502fe7bd1f4a23ba5bbe4dde0d9d57Zhu Lan    }
391f9bbe1e71a502fe7bd1f4a23ba5bbe4dde0d9d57Zhu Lan
39262c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh    /**
39362c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh     * {@inheritDoc}
3949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
39562c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh    public int getConnectionState(BluetoothDevice device) {
396563e414784eb81e4ea4051667d5c8855b17f7534Matthew Xie        if (VDBG) log("getState(" + device + ")");
397d7d16b9f372116da1658f589df213aed33c2ded6Calvin On        try {
398d7d16b9f372116da1658f589df213aed33c2ded6Calvin On            mServiceLock.readLock().lock();
399d7d16b9f372116da1658f589df213aed33c2ded6Calvin On            if (mService != null && isEnabled()
400d7d16b9f372116da1658f589df213aed33c2ded6Calvin On                && isValidDevice(device)) {
40162c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh                return mService.getConnectionState(device);
40262c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh            }
403d7d16b9f372116da1658f589df213aed33c2ded6Calvin On            if (mService == null) Log.w(TAG, "Proxy not attached to service");
404d7d16b9f372116da1658f589df213aed33c2ded6Calvin On            return BluetoothProfile.STATE_DISCONNECTED;
405d7d16b9f372116da1658f589df213aed33c2ded6Calvin On        } catch (RemoteException e) {
406d7d16b9f372116da1658f589df213aed33c2ded6Calvin On            Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
407d7d16b9f372116da1658f589df213aed33c2ded6Calvin On            return BluetoothProfile.STATE_DISCONNECTED;
408d7d16b9f372116da1658f589df213aed33c2ded6Calvin On        } finally {
409d7d16b9f372116da1658f589df213aed33c2ded6Calvin On            mServiceLock.readLock().unlock();
41062c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh        }
4119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
41362c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh    /**
414f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * Set priority of the profile
415f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     *
416f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * <p> The device should already be paired.
4170f42037eb7b5118015c2caca635538324ccf0ccffredc     *  Priority can be one of {@link #PRIORITY_ON} orgetBluetoothManager
418f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * {@link #PRIORITY_OFF},
419f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     *
420f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
421f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * permission.
422f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     *
423f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * @param device Paired bluetooth device
424f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * @param priority
425f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * @return true if priority is set, false on error
4269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @hide
4279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
42862c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh    public boolean setPriority(BluetoothDevice device, int priority) {
42962c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh        if (DBG) log("setPriority(" + device + ", " + priority + ")");
430d7d16b9f372116da1658f589df213aed33c2ded6Calvin On        try {
431d7d16b9f372116da1658f589df213aed33c2ded6Calvin On            mServiceLock.readLock().lock();
432d7d16b9f372116da1658f589df213aed33c2ded6Calvin On            if (mService != null && isEnabled()
433d7d16b9f372116da1658f589df213aed33c2ded6Calvin On                && isValidDevice(device)) {
434d7d16b9f372116da1658f589df213aed33c2ded6Calvin On                if (priority != BluetoothProfile.PRIORITY_OFF &&
435d7d16b9f372116da1658f589df213aed33c2ded6Calvin On                    priority != BluetoothProfile.PRIORITY_ON) {
436d7d16b9f372116da1658f589df213aed33c2ded6Calvin On                    return false;
437d7d16b9f372116da1658f589df213aed33c2ded6Calvin On                }
43862c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh                return mService.setPriority(device, priority);
43962c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh            }
440d7d16b9f372116da1658f589df213aed33c2ded6Calvin On            if (mService == null) Log.w(TAG, "Proxy not attached to service");
441d7d16b9f372116da1658f589df213aed33c2ded6Calvin On            return false;
442d7d16b9f372116da1658f589df213aed33c2ded6Calvin On        } catch (RemoteException e) {
443d7d16b9f372116da1658f589df213aed33c2ded6Calvin On            Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
444d7d16b9f372116da1658f589df213aed33c2ded6Calvin On            return false;
445d7d16b9f372116da1658f589df213aed33c2ded6Calvin On        } finally {
446d7d16b9f372116da1658f589df213aed33c2ded6Calvin On            mServiceLock.readLock().unlock();
4479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
45062c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh    /**
451f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * Get the priority of the profile.
452f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     *
453f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * <p> The priority can be any of:
454f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * {@link #PRIORITY_AUTO_CONNECT}, {@link #PRIORITY_OFF},
455f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * {@link #PRIORITY_ON}, {@link #PRIORITY_UNDEFINED}
456f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     *
457f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * @param device Bluetooth device
458f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * @return priority of the device
459b16c4f7dd92dabf0cc27438a5d3d9ebd203a38b3Jaikumar Ganesh     * @hide
460b16c4f7dd92dabf0cc27438a5d3d9ebd203a38b3Jaikumar Ganesh     */
4612d49752ee050ab7f1cd848933f6c62a73707e2d9Tor Norbye    @RequiresPermission(Manifest.permission.BLUETOOTH)
46262c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh    public int getPriority(BluetoothDevice device) {
463563e414784eb81e4ea4051667d5c8855b17f7534Matthew Xie        if (VDBG) log("getPriority(" + device + ")");
464d7d16b9f372116da1658f589df213aed33c2ded6Calvin On        try {
465d7d16b9f372116da1658f589df213aed33c2ded6Calvin On            mServiceLock.readLock().lock();
466d7d16b9f372116da1658f589df213aed33c2ded6Calvin On            if (mService != null && isEnabled()
467d7d16b9f372116da1658f589df213aed33c2ded6Calvin On                && isValidDevice(device)) {
46862c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh                return mService.getPriority(device);
46962c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh            }
470d7d16b9f372116da1658f589df213aed33c2ded6Calvin On            if (mService == null) Log.w(TAG, "Proxy not attached to service");
471d7d16b9f372116da1658f589df213aed33c2ded6Calvin On            return BluetoothProfile.PRIORITY_OFF;
472d7d16b9f372116da1658f589df213aed33c2ded6Calvin On        } catch (RemoteException e) {
473d7d16b9f372116da1658f589df213aed33c2ded6Calvin On            Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
474d7d16b9f372116da1658f589df213aed33c2ded6Calvin On            return BluetoothProfile.PRIORITY_OFF;
475d7d16b9f372116da1658f589df213aed33c2ded6Calvin On        } finally {
476d7d16b9f372116da1658f589df213aed33c2ded6Calvin On            mServiceLock.readLock().unlock();
477b16c4f7dd92dabf0cc27438a5d3d9ebd203a38b3Jaikumar Ganesh        }
478b16c4f7dd92dabf0cc27438a5d3d9ebd203a38b3Jaikumar Ganesh    }
479b16c4f7dd92dabf0cc27438a5d3d9ebd203a38b3Jaikumar Ganesh
48062c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh    /**
4815a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du     * Checks if Avrcp device supports the absolute volume feature.
4825a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du     *
4835a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du     * @return true if device supports absolute volume
4845a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du     * @hide
4855a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du     */
4865a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du    public boolean isAvrcpAbsoluteVolumeSupported() {
4875a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du        if (DBG) Log.d(TAG, "isAvrcpAbsoluteVolumeSupported");
488d7d16b9f372116da1658f589df213aed33c2ded6Calvin On        try {
489d7d16b9f372116da1658f589df213aed33c2ded6Calvin On            mServiceLock.readLock().lock();
490d7d16b9f372116da1658f589df213aed33c2ded6Calvin On            if (mService != null && isEnabled()) {
4915a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                return mService.isAvrcpAbsoluteVolumeSupported();
4925a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du            }
493d7d16b9f372116da1658f589df213aed33c2ded6Calvin On            if (mService == null) Log.w(TAG, "Proxy not attached to service");
494d7d16b9f372116da1658f589df213aed33c2ded6Calvin On            return false;
495d7d16b9f372116da1658f589df213aed33c2ded6Calvin On        } catch (RemoteException e) {
496d7d16b9f372116da1658f589df213aed33c2ded6Calvin On            Log.e(TAG, "Error talking to BT service in isAvrcpAbsoluteVolumeSupported()", e);
497d7d16b9f372116da1658f589df213aed33c2ded6Calvin On            return false;
498d7d16b9f372116da1658f589df213aed33c2ded6Calvin On        } finally {
499d7d16b9f372116da1658f589df213aed33c2ded6Calvin On            mServiceLock.readLock().unlock();
5005a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du        }
5015a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du    }
5025a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du
5035a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du    /**
5044197cb60bc74629fe4c04ab10cb3b1c9a7427d24RoboErik     * Tells remote device to adjust volume. Only if absolute volume is
5054197cb60bc74629fe4c04ab10cb3b1c9a7427d24RoboErik     * supported. Uses the following values:
5064197cb60bc74629fe4c04ab10cb3b1c9a7427d24RoboErik     * <ul>
5074197cb60bc74629fe4c04ab10cb3b1c9a7427d24RoboErik     * <li>{@link AudioManager#ADJUST_LOWER}</li>
5084197cb60bc74629fe4c04ab10cb3b1c9a7427d24RoboErik     * <li>{@link AudioManager#ADJUST_RAISE}</li>
5094197cb60bc74629fe4c04ab10cb3b1c9a7427d24RoboErik     * <li>{@link AudioManager#ADJUST_MUTE}</li>
5104197cb60bc74629fe4c04ab10cb3b1c9a7427d24RoboErik     * <li>{@link AudioManager#ADJUST_UNMUTE}</li>
5114197cb60bc74629fe4c04ab10cb3b1c9a7427d24RoboErik     * </ul>
5125a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du     *
5134197cb60bc74629fe4c04ab10cb3b1c9a7427d24RoboErik     * @param direction One of the supported adjust values.
5145a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du     * @hide
5155a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du     */
5165a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du    public void adjustAvrcpAbsoluteVolume(int direction) {
5175a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du        if (DBG) Log.d(TAG, "adjustAvrcpAbsoluteVolume");
518d7d16b9f372116da1658f589df213aed33c2ded6Calvin On        try {
519d7d16b9f372116da1658f589df213aed33c2ded6Calvin On            mServiceLock.readLock().lock();
520d7d16b9f372116da1658f589df213aed33c2ded6Calvin On            if (mService != null && isEnabled()) {
5215a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                mService.adjustAvrcpAbsoluteVolume(direction);
5225a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du            }
523d7d16b9f372116da1658f589df213aed33c2ded6Calvin On            if (mService == null) Log.w(TAG, "Proxy not attached to service");
524d7d16b9f372116da1658f589df213aed33c2ded6Calvin On        } catch (RemoteException e) {
525d7d16b9f372116da1658f589df213aed33c2ded6Calvin On            Log.e(TAG, "Error talking to BT service in adjustAvrcpAbsoluteVolume()", e);
526d7d16b9f372116da1658f589df213aed33c2ded6Calvin On        } finally {
527d7d16b9f372116da1658f589df213aed33c2ded6Calvin On            mServiceLock.readLock().unlock();
5285a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du        }
5295a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du    }
5305a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du
5315a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du    /**
5325a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du     * Tells remote device to set an absolute volume. Only if absolute volume is supported
5335a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du     *
5345a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du     * @param volume Absolute volume to be set on AVRCP side
5355a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du     * @hide
5365a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du     */
5375a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du    public void setAvrcpAbsoluteVolume(int volume) {
5385a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du        if (DBG) Log.d(TAG, "setAvrcpAbsoluteVolume");
539d7d16b9f372116da1658f589df213aed33c2ded6Calvin On        try {
540d7d16b9f372116da1658f589df213aed33c2ded6Calvin On            mServiceLock.readLock().lock();
541d7d16b9f372116da1658f589df213aed33c2ded6Calvin On            if (mService != null && isEnabled()) {
5425a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                mService.setAvrcpAbsoluteVolume(volume);
5435a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du            }
544d7d16b9f372116da1658f589df213aed33c2ded6Calvin On            if (mService == null) Log.w(TAG, "Proxy not attached to service");
545d7d16b9f372116da1658f589df213aed33c2ded6Calvin On        } catch (RemoteException e) {
546d7d16b9f372116da1658f589df213aed33c2ded6Calvin On            Log.e(TAG, "Error talking to BT service in setAvrcpAbsoluteVolume()", e);
547d7d16b9f372116da1658f589df213aed33c2ded6Calvin On        } finally {
548d7d16b9f372116da1658f589df213aed33c2ded6Calvin On            mServiceLock.readLock().unlock();
5495a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du        }
5505a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du    }
5515a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du
5525a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du    /**
55362c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh     * Check if A2DP profile is streaming music.
55462c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh     *
555c8fa4ff838a0c3d2c67db65540fa751e5abe27edJaikumar Ganesh     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
55662c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh     *
55762c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh     * @param device BluetoothDevice device
5589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
55962c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh    public boolean isA2dpPlaying(BluetoothDevice device) {
560d7d16b9f372116da1658f589df213aed33c2ded6Calvin On        try {
561d7d16b9f372116da1658f589df213aed33c2ded6Calvin On            mServiceLock.readLock().lock();
562d7d16b9f372116da1658f589df213aed33c2ded6Calvin On            if (mService != null && isEnabled()
563d7d16b9f372116da1658f589df213aed33c2ded6Calvin On                && isValidDevice(device)) {
56462c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh                return mService.isA2dpPlaying(device);
56562c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh            }
566d7d16b9f372116da1658f589df213aed33c2ded6Calvin On            if (mService == null) Log.w(TAG, "Proxy not attached to service");
567d7d16b9f372116da1658f589df213aed33c2ded6Calvin On            return false;
568d7d16b9f372116da1658f589df213aed33c2ded6Calvin On        } catch (RemoteException e) {
569d7d16b9f372116da1658f589df213aed33c2ded6Calvin On            Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
570d7d16b9f372116da1658f589df213aed33c2ded6Calvin On            return false;
571d7d16b9f372116da1658f589df213aed33c2ded6Calvin On        } finally {
572d7d16b9f372116da1658f589df213aed33c2ded6Calvin On            mServiceLock.readLock().unlock();
5739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
57741d5c805d96aef0aaa9a2aaa86ccc4b77ca75e11Jaikumar Ganesh     * This function checks if the remote device is an AVCRP
57841d5c805d96aef0aaa9a2aaa86ccc4b77ca75e11Jaikumar Ganesh     * target and thus whether we should send volume keys
57941d5c805d96aef0aaa9a2aaa86ccc4b77ca75e11Jaikumar Ganesh     * changes or not.
58041d5c805d96aef0aaa9a2aaa86ccc4b77ca75e11Jaikumar Ganesh     * @hide
58141d5c805d96aef0aaa9a2aaa86ccc4b77ca75e11Jaikumar Ganesh     */
58241d5c805d96aef0aaa9a2aaa86ccc4b77ca75e11Jaikumar Ganesh    public boolean shouldSendVolumeKeys(BluetoothDevice device) {
58341d5c805d96aef0aaa9a2aaa86ccc4b77ca75e11Jaikumar Ganesh        if (isEnabled() && isValidDevice(device)) {
58441d5c805d96aef0aaa9a2aaa86ccc4b77ca75e11Jaikumar Ganesh            ParcelUuid[] uuids = device.getUuids();
58541d5c805d96aef0aaa9a2aaa86ccc4b77ca75e11Jaikumar Ganesh            if (uuids == null) return false;
58641d5c805d96aef0aaa9a2aaa86ccc4b77ca75e11Jaikumar Ganesh
58741d5c805d96aef0aaa9a2aaa86ccc4b77ca75e11Jaikumar Ganesh            for (ParcelUuid uuid: uuids) {
58841d5c805d96aef0aaa9a2aaa86ccc4b77ca75e11Jaikumar Ganesh                if (BluetoothUuid.isAvrcpTarget(uuid)) {
58941d5c805d96aef0aaa9a2aaa86ccc4b77ca75e11Jaikumar Ganesh                    return true;
59041d5c805d96aef0aaa9a2aaa86ccc4b77ca75e11Jaikumar Ganesh                }
59141d5c805d96aef0aaa9a2aaa86ccc4b77ca75e11Jaikumar Ganesh            }
59241d5c805d96aef0aaa9a2aaa86ccc4b77ca75e11Jaikumar Ganesh        }
59341d5c805d96aef0aaa9a2aaa86ccc4b77ca75e11Jaikumar Ganesh        return false;
59441d5c805d96aef0aaa9a2aaa86ccc4b77ca75e11Jaikumar Ganesh    }
59541d5c805d96aef0aaa9a2aaa86ccc4b77ca75e11Jaikumar Ganesh
596a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie    /**
597b37f181c9853bd0d55d360db95d3bf1bba0b5a6fPavlin Radoslavov     * Gets the current codec status (configuration and capability).
59844a4ef0aa93ebb2912f36d65af42ffbb1bcdbc0fPavlin Radoslavov     *
599b37f181c9853bd0d55d360db95d3bf1bba0b5a6fPavlin Radoslavov     * @return the current codec status
60044a4ef0aa93ebb2912f36d65af42ffbb1bcdbc0fPavlin Radoslavov     * @hide
60144a4ef0aa93ebb2912f36d65af42ffbb1bcdbc0fPavlin Radoslavov     */
602b37f181c9853bd0d55d360db95d3bf1bba0b5a6fPavlin Radoslavov    public BluetoothCodecStatus getCodecStatus() {
603b37f181c9853bd0d55d360db95d3bf1bba0b5a6fPavlin Radoslavov        if (DBG) Log.d(TAG, "getCodecStatus");
60444a4ef0aa93ebb2912f36d65af42ffbb1bcdbc0fPavlin Radoslavov        try {
60544a4ef0aa93ebb2912f36d65af42ffbb1bcdbc0fPavlin Radoslavov            mServiceLock.readLock().lock();
60644a4ef0aa93ebb2912f36d65af42ffbb1bcdbc0fPavlin Radoslavov            if (mService != null && isEnabled()) {
607b37f181c9853bd0d55d360db95d3bf1bba0b5a6fPavlin Radoslavov                return mService.getCodecStatus();
60844a4ef0aa93ebb2912f36d65af42ffbb1bcdbc0fPavlin Radoslavov            }
60944a4ef0aa93ebb2912f36d65af42ffbb1bcdbc0fPavlin Radoslavov            if (mService == null) {
61044a4ef0aa93ebb2912f36d65af42ffbb1bcdbc0fPavlin Radoslavov                Log.w(TAG, "Proxy not attached to service");
61144a4ef0aa93ebb2912f36d65af42ffbb1bcdbc0fPavlin Radoslavov            }
61244a4ef0aa93ebb2912f36d65af42ffbb1bcdbc0fPavlin Radoslavov            return null;
61344a4ef0aa93ebb2912f36d65af42ffbb1bcdbc0fPavlin Radoslavov        } catch (RemoteException e) {
614b37f181c9853bd0d55d360db95d3bf1bba0b5a6fPavlin Radoslavov            Log.e(TAG, "Error talking to BT service in getCodecStatus()", e);
61544a4ef0aa93ebb2912f36d65af42ffbb1bcdbc0fPavlin Radoslavov            return null;
61644a4ef0aa93ebb2912f36d65af42ffbb1bcdbc0fPavlin Radoslavov        } finally {
61744a4ef0aa93ebb2912f36d65af42ffbb1bcdbc0fPavlin Radoslavov            mServiceLock.readLock().unlock();
61844a4ef0aa93ebb2912f36d65af42ffbb1bcdbc0fPavlin Radoslavov        }
61944a4ef0aa93ebb2912f36d65af42ffbb1bcdbc0fPavlin Radoslavov    }
62044a4ef0aa93ebb2912f36d65af42ffbb1bcdbc0fPavlin Radoslavov
62144a4ef0aa93ebb2912f36d65af42ffbb1bcdbc0fPavlin Radoslavov    /**
62244a4ef0aa93ebb2912f36d65af42ffbb1bcdbc0fPavlin Radoslavov     * Sets the codec configuration preference.
62344a4ef0aa93ebb2912f36d65af42ffbb1bcdbc0fPavlin Radoslavov     *
62444a4ef0aa93ebb2912f36d65af42ffbb1bcdbc0fPavlin Radoslavov     * @param codecConfig the codec configuration preference
62544a4ef0aa93ebb2912f36d65af42ffbb1bcdbc0fPavlin Radoslavov     * @hide
62644a4ef0aa93ebb2912f36d65af42ffbb1bcdbc0fPavlin Radoslavov     */
62744a4ef0aa93ebb2912f36d65af42ffbb1bcdbc0fPavlin Radoslavov    public void setCodecConfigPreference(BluetoothCodecConfig codecConfig) {
62844a4ef0aa93ebb2912f36d65af42ffbb1bcdbc0fPavlin Radoslavov        if (DBG) Log.d(TAG, "setCodecConfigPreference");
62944a4ef0aa93ebb2912f36d65af42ffbb1bcdbc0fPavlin Radoslavov        try {
63044a4ef0aa93ebb2912f36d65af42ffbb1bcdbc0fPavlin Radoslavov            mServiceLock.readLock().lock();
63144a4ef0aa93ebb2912f36d65af42ffbb1bcdbc0fPavlin Radoslavov            if (mService != null && isEnabled()) {
63244a4ef0aa93ebb2912f36d65af42ffbb1bcdbc0fPavlin Radoslavov                mService.setCodecConfigPreference(codecConfig);
63344a4ef0aa93ebb2912f36d65af42ffbb1bcdbc0fPavlin Radoslavov            }
63444a4ef0aa93ebb2912f36d65af42ffbb1bcdbc0fPavlin Radoslavov            if (mService == null) Log.w(TAG, "Proxy not attached to service");
63544a4ef0aa93ebb2912f36d65af42ffbb1bcdbc0fPavlin Radoslavov            return;
63644a4ef0aa93ebb2912f36d65af42ffbb1bcdbc0fPavlin Radoslavov        } catch (RemoteException e) {
63744a4ef0aa93ebb2912f36d65af42ffbb1bcdbc0fPavlin Radoslavov            Log.e(TAG, "Error talking to BT service in setCodecConfigPreference()", e);
63844a4ef0aa93ebb2912f36d65af42ffbb1bcdbc0fPavlin Radoslavov            return;
63944a4ef0aa93ebb2912f36d65af42ffbb1bcdbc0fPavlin Radoslavov        } finally {
64044a4ef0aa93ebb2912f36d65af42ffbb1bcdbc0fPavlin Radoslavov            mServiceLock.readLock().unlock();
64144a4ef0aa93ebb2912f36d65af42ffbb1bcdbc0fPavlin Radoslavov        }
64244a4ef0aa93ebb2912f36d65af42ffbb1bcdbc0fPavlin Radoslavov    }
64344a4ef0aa93ebb2912f36d65af42ffbb1bcdbc0fPavlin Radoslavov
64444a4ef0aa93ebb2912f36d65af42ffbb1bcdbc0fPavlin Radoslavov    /**
645011597b5a933e8291d0bca9c3f3b17b9e816d654Pavlin Radoslavov     * Enables the optional codecs.
646011597b5a933e8291d0bca9c3f3b17b9e816d654Pavlin Radoslavov     *
647011597b5a933e8291d0bca9c3f3b17b9e816d654Pavlin Radoslavov     * @hide
648011597b5a933e8291d0bca9c3f3b17b9e816d654Pavlin Radoslavov     */
649011597b5a933e8291d0bca9c3f3b17b9e816d654Pavlin Radoslavov    public void enableOptionalCodecs() {
650011597b5a933e8291d0bca9c3f3b17b9e816d654Pavlin Radoslavov        if (DBG) Log.d(TAG, "enableOptionalCodecs");
651011597b5a933e8291d0bca9c3f3b17b9e816d654Pavlin Radoslavov        enableDisableOptionalCodecs(true);
652011597b5a933e8291d0bca9c3f3b17b9e816d654Pavlin Radoslavov    }
653011597b5a933e8291d0bca9c3f3b17b9e816d654Pavlin Radoslavov
654011597b5a933e8291d0bca9c3f3b17b9e816d654Pavlin Radoslavov    /**
655011597b5a933e8291d0bca9c3f3b17b9e816d654Pavlin Radoslavov     * Disables the optional codecs.
656011597b5a933e8291d0bca9c3f3b17b9e816d654Pavlin Radoslavov     *
657011597b5a933e8291d0bca9c3f3b17b9e816d654Pavlin Radoslavov     * @hide
658011597b5a933e8291d0bca9c3f3b17b9e816d654Pavlin Radoslavov     */
659011597b5a933e8291d0bca9c3f3b17b9e816d654Pavlin Radoslavov    public void disableOptionalCodecs() {
660011597b5a933e8291d0bca9c3f3b17b9e816d654Pavlin Radoslavov        if (DBG) Log.d(TAG, "disableOptionalCodecs");
661011597b5a933e8291d0bca9c3f3b17b9e816d654Pavlin Radoslavov        enableDisableOptionalCodecs(false);
662011597b5a933e8291d0bca9c3f3b17b9e816d654Pavlin Radoslavov    }
663011597b5a933e8291d0bca9c3f3b17b9e816d654Pavlin Radoslavov
664011597b5a933e8291d0bca9c3f3b17b9e816d654Pavlin Radoslavov    /**
665011597b5a933e8291d0bca9c3f3b17b9e816d654Pavlin Radoslavov     * Enables or disables the optional codecs.
666011597b5a933e8291d0bca9c3f3b17b9e816d654Pavlin Radoslavov     *
667011597b5a933e8291d0bca9c3f3b17b9e816d654Pavlin Radoslavov     * @param enable if true, enable the optional codecs, other disable them
668011597b5a933e8291d0bca9c3f3b17b9e816d654Pavlin Radoslavov     */
669011597b5a933e8291d0bca9c3f3b17b9e816d654Pavlin Radoslavov    private void enableDisableOptionalCodecs(boolean enable) {
670011597b5a933e8291d0bca9c3f3b17b9e816d654Pavlin Radoslavov        try {
671011597b5a933e8291d0bca9c3f3b17b9e816d654Pavlin Radoslavov            mServiceLock.readLock().lock();
672011597b5a933e8291d0bca9c3f3b17b9e816d654Pavlin Radoslavov            if (mService != null && isEnabled()) {
673011597b5a933e8291d0bca9c3f3b17b9e816d654Pavlin Radoslavov                if (enable) {
674011597b5a933e8291d0bca9c3f3b17b9e816d654Pavlin Radoslavov                    mService.enableOptionalCodecs();
675011597b5a933e8291d0bca9c3f3b17b9e816d654Pavlin Radoslavov                } else {
676011597b5a933e8291d0bca9c3f3b17b9e816d654Pavlin Radoslavov                    mService.disableOptionalCodecs();
677011597b5a933e8291d0bca9c3f3b17b9e816d654Pavlin Radoslavov                }
678011597b5a933e8291d0bca9c3f3b17b9e816d654Pavlin Radoslavov            }
679011597b5a933e8291d0bca9c3f3b17b9e816d654Pavlin Radoslavov            if (mService == null) Log.w(TAG, "Proxy not attached to service");
680011597b5a933e8291d0bca9c3f3b17b9e816d654Pavlin Radoslavov            return;
681011597b5a933e8291d0bca9c3f3b17b9e816d654Pavlin Radoslavov        } catch (RemoteException e) {
682011597b5a933e8291d0bca9c3f3b17b9e816d654Pavlin Radoslavov            Log.e(TAG, "Error talking to BT service in enableDisableOptionalCodecs()", e);
683011597b5a933e8291d0bca9c3f3b17b9e816d654Pavlin Radoslavov            return;
684011597b5a933e8291d0bca9c3f3b17b9e816d654Pavlin Radoslavov        } finally {
685011597b5a933e8291d0bca9c3f3b17b9e816d654Pavlin Radoslavov            mServiceLock.readLock().unlock();
686011597b5a933e8291d0bca9c3f3b17b9e816d654Pavlin Radoslavov        }
687011597b5a933e8291d0bca9c3f3b17b9e816d654Pavlin Radoslavov    }
688011597b5a933e8291d0bca9c3f3b17b9e816d654Pavlin Radoslavov
689011597b5a933e8291d0bca9c3f3b17b9e816d654Pavlin Radoslavov    /**
690f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent     * Returns whether this device supports optional codecs.
691f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent     *
692f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent     * @param device The device to check
693f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent     * @return one of OPTIONAL_CODECS_SUPPORT_UNKNOWN, OPTIONAL_CODECS_NOT_SUPPORTED, or
694f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent     *         OPTIONAL_CODECS_SUPPORTED.
695f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent     *
696f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent     * @hide
697f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent     */
698f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent    public int supportsOptionalCodecs(BluetoothDevice device) {
699f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent        try {
700f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent            mServiceLock.readLock().lock();
701f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent            if (mService != null && isEnabled() && isValidDevice(device)) {
702f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent                return mService.supportsOptionalCodecs(device);
703f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent            }
704f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent            if (mService == null) Log.w(TAG, "Proxy not attached to service");
705f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent            return OPTIONAL_CODECS_SUPPORT_UNKNOWN;
706f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent        } catch (RemoteException e) {
707f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent            Log.e(TAG, "Error talking to BT service in getSupportsOptionalCodecs()", e);
708f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent            return OPTIONAL_CODECS_SUPPORT_UNKNOWN;
709f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent        } finally {
710f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent            mServiceLock.readLock().unlock();
711f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent        }
712f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent    }
713f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent
714f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent    /**
715f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent     * Returns whether this device should have optional codecs enabled.
716f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent     *
717f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent     * @param device The device in question.
718f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent     * @return one of OPTIONAL_CODECS_PREF_UNKNOWN, OPTIONAL_CODECS_PREF_ENABLED, or
719f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent     *         OPTIONAL_CODECS_PREF_DISABLED.
720f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent     *
721f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent     * @hide
722f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent     */
723f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent    public int getOptionalCodecsEnabled(BluetoothDevice device) {
724f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent        try {
725f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent            mServiceLock.readLock().lock();
726f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent            if (mService != null && isEnabled() && isValidDevice(device)) {
727f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent                return mService.getOptionalCodecsEnabled(device);
728f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent            }
729f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent            if (mService == null) Log.w(TAG, "Proxy not attached to service");
730f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent            return OPTIONAL_CODECS_PREF_UNKNOWN;
731f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent        } catch (RemoteException e) {
732f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent            Log.e(TAG, "Error talking to BT service in getSupportsOptionalCodecs()", e);
733f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent            return OPTIONAL_CODECS_PREF_UNKNOWN;
734f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent        } finally {
735f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent            mServiceLock.readLock().unlock();
736f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent        }
737f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent    }
738f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent
739f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent    /**
740f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent     * Sets a persistent preference for whether a given device should have optional codecs enabled.
741f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent     *
742f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent     * @param device The device to set this preference for.
743f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent     * @param value Whether the optional codecs should be enabled for this device.  This should be
744f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent     *              one of OPTIONAL_CODECS_PREF_UNKNOWN, OPTIONAL_CODECS_PREF_ENABLED, or
745f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent     *              OPTIONAL_CODECS_PREF_DISABLED.
746f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent     * @hide
747f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent     */
748f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent    public void setOptionalCodecsEnabled(BluetoothDevice device, int value) {
749f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent        try {
750f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent            if (value != BluetoothA2dp.OPTIONAL_CODECS_PREF_UNKNOWN &&
751f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent                    value != BluetoothA2dp.OPTIONAL_CODECS_PREF_DISABLED &&
752f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent                    value != BluetoothA2dp.OPTIONAL_CODECS_PREF_ENABLED) {
753f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent                Log.e(TAG, "Invalid value passed to setOptionalCodecsEnabled: " + value);
754f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent                return;
755f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent            }
756f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent            mServiceLock.readLock().lock();
757f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent            if (mService != null && isEnabled()
758f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent                    && isValidDevice(device)) {
759f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent                mService.setOptionalCodecsEnabled(device, value);
760f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent            }
761f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent            if (mService == null) Log.w(TAG, "Proxy not attached to service");
762f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent            return;
763f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent        } catch (RemoteException e) {
764f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent            Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
765f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent            return;
766f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent        } finally {
767f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent            mServiceLock.readLock().unlock();
768f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent        }
769f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent    }
770f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent
771f5772c6121ee1f5f2aa06711e2762c0f07fb61ccAntony Sargent    /**
77262c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh     * Helper for converting a state to a string.
77362c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh     *
7749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * For debug use only - strings are not internationalized.
7759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @hide
7769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
7779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static String stateToString(int state) {
7789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        switch (state) {
7799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        case STATE_DISCONNECTED:
7809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "disconnected";
7819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        case STATE_CONNECTING:
7829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "connecting";
7839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        case STATE_CONNECTED:
7849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "connected";
7859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        case STATE_DISCONNECTING:
7869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "disconnecting";
7879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        case STATE_PLAYING:
7889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "playing";
78962c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh        case STATE_NOT_PLAYING:
79062c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh          return "not playing";
7919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        default:
7929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "<unknown state " + state + ">";
7939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
795f5b4b98fada53d91c4c2ebeb5a1d33ccc95c94d2The Android Open Source Project
7969b6939939901cb82bc6fca93aad3810a4936dfc6Matthew Xie    private final ServiceConnection mConnection = new ServiceConnection() {
7973e8c82edb1feafc796aa52efafedc13f794c4dcdMatthew Xie        public void onServiceConnected(ComponentName className, IBinder service) {
7983e8c82edb1feafc796aa52efafedc13f794c4dcdMatthew Xie            if (DBG) Log.d(TAG, "Proxy object connected");
799d7d16b9f372116da1658f589df213aed33c2ded6Calvin On            try {
800d7d16b9f372116da1658f589df213aed33c2ded6Calvin On                mServiceLock.writeLock().lock();
8010a17db1cc5942ea000ca87bb72853de57a15ec64Jeff Sharkey                mService = IBluetoothA2dp.Stub.asInterface(Binder.allowBlocking(service));
802d7d16b9f372116da1658f589df213aed33c2ded6Calvin On            } finally {
803d7d16b9f372116da1658f589df213aed33c2ded6Calvin On                mServiceLock.writeLock().unlock();
804d7d16b9f372116da1658f589df213aed33c2ded6Calvin On            }
8053e8c82edb1feafc796aa52efafedc13f794c4dcdMatthew Xie
8063e8c82edb1feafc796aa52efafedc13f794c4dcdMatthew Xie            if (mServiceListener != null) {
8073e8c82edb1feafc796aa52efafedc13f794c4dcdMatthew Xie                mServiceListener.onServiceConnected(BluetoothProfile.A2DP, BluetoothA2dp.this);
8083e8c82edb1feafc796aa52efafedc13f794c4dcdMatthew Xie            }
8093e8c82edb1feafc796aa52efafedc13f794c4dcdMatthew Xie        }
8103e8c82edb1feafc796aa52efafedc13f794c4dcdMatthew Xie        public void onServiceDisconnected(ComponentName className) {
8113e8c82edb1feafc796aa52efafedc13f794c4dcdMatthew Xie            if (DBG) Log.d(TAG, "Proxy object disconnected");
812d7d16b9f372116da1658f589df213aed33c2ded6Calvin On            try {
813d7d16b9f372116da1658f589df213aed33c2ded6Calvin On                mServiceLock.writeLock().lock();
814d7d16b9f372116da1658f589df213aed33c2ded6Calvin On                mService = null;
815d7d16b9f372116da1658f589df213aed33c2ded6Calvin On            } finally {
816d7d16b9f372116da1658f589df213aed33c2ded6Calvin On                mServiceLock.writeLock().unlock();
817d7d16b9f372116da1658f589df213aed33c2ded6Calvin On            }
8183e8c82edb1feafc796aa52efafedc13f794c4dcdMatthew Xie            if (mServiceListener != null) {
8193e8c82edb1feafc796aa52efafedc13f794c4dcdMatthew Xie                mServiceListener.onServiceDisconnected(BluetoothProfile.A2DP);
8203e8c82edb1feafc796aa52efafedc13f794c4dcdMatthew Xie            }
8213e8c82edb1feafc796aa52efafedc13f794c4dcdMatthew Xie        }
8223e8c82edb1feafc796aa52efafedc13f794c4dcdMatthew Xie    };
8233e8c82edb1feafc796aa52efafedc13f794c4dcdMatthew Xie
82462c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh    private boolean isEnabled() {
82562c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh       if (mAdapter.getState() == BluetoothAdapter.STATE_ON) return true;
82662c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh       return false;
82762c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh    }
82862c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh
82962c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh    private boolean isValidDevice(BluetoothDevice device) {
83062c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh       if (device == null) return false;
83162c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh
83262c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh       if (BluetoothAdapter.checkBluetoothAddress(device.getAddress())) return true;
83362c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh       return false;
83462c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh    }
83562c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh
836f5b4b98fada53d91c4c2ebeb5a1d33ccc95c94d2The Android Open Source Project    private static void log(String msg) {
83762c37efc9e894809b29a004c142a8e0a6b374db7Jaikumar Ganesh      Log.d(TAG, msg);
838f5b4b98fada53d91c4c2ebeb5a1d33ccc95c94d2The Android Open Source Project    }
8399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
840