16c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie/*
2ede67c26e7b2564ea35db6d9b3027a269c150e13Zhihai Xu * Copyright (C) 2012 The Android Open Source Project
3ede67c26e7b2564ea35db6d9b3027a269c150e13Zhihai Xu *
4ede67c26e7b2564ea35db6d9b3027a269c150e13Zhihai Xu * Licensed under the Apache License, Version 2.0 (the "License");
5ede67c26e7b2564ea35db6d9b3027a269c150e13Zhihai Xu * you may not use this file except in compliance with the License.
6ede67c26e7b2564ea35db6d9b3027a269c150e13Zhihai Xu * You may obtain a copy of the License at
7ede67c26e7b2564ea35db6d9b3027a269c150e13Zhihai Xu *
8ede67c26e7b2564ea35db6d9b3027a269c150e13Zhihai Xu *      http://www.apache.org/licenses/LICENSE-2.0
9ede67c26e7b2564ea35db6d9b3027a269c150e13Zhihai Xu *
10ede67c26e7b2564ea35db6d9b3027a269c150e13Zhihai Xu * Unless required by applicable law or agreed to in writing, software
11ede67c26e7b2564ea35db6d9b3027a269c150e13Zhihai Xu * distributed under the License is distributed on an "AS IS" BASIS,
12ede67c26e7b2564ea35db6d9b3027a269c150e13Zhihai Xu * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13ede67c26e7b2564ea35db6d9b3027a269c150e13Zhihai Xu * See the License for the specific language governing permissions and
14ede67c26e7b2564ea35db6d9b3027a269c150e13Zhihai Xu * limitations under the License.
156c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie */
16ede67c26e7b2564ea35db6d9b3027a269c150e13Zhihai Xu
176c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xiepackage com.android.bluetooth.a2dp;
186c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
196c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xieimport android.bluetooth.BluetoothDevice;
206c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xieimport android.bluetooth.BluetoothProfile;
21e316dfc9b3f648ad3d7b2691927758ea885043c0Anubhav Guptaimport android.bluetooth.BluetoothUuid;
226c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xieimport android.bluetooth.IBluetoothA2dp;
236c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xieimport android.content.Context;
246c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xieimport android.content.Intent;
25e316dfc9b3f648ad3d7b2691927758ea885043c0Anubhav Guptaimport android.os.ParcelUuid;
266c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xieimport android.provider.Settings;
276c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xieimport android.util.Log;
28066ad9e16a548218b139424f758b92db7af34af2Mike Lockwoodimport com.android.bluetooth.avrcp.Avrcp;
2937510150ee738ccfa5913f7120e28f25ae7768dfZhihai Xuimport com.android.bluetooth.btservice.ProfileService;
3037510150ee738ccfa5913f7120e28f25ae7768dfZhihai Xuimport com.android.bluetooth.Utils;
3174ae04c73312403e89db0f8e9bd9601d403b4783fredcimport java.util.ArrayList;
326654f5c903de510a70f9e72cd5ad7837b615d93ffredcimport java.util.Iterator;
3337510150ee738ccfa5913f7120e28f25ae7768dfZhihai Xuimport java.util.List;
346654f5c903de510a70f9e72cd5ad7837b615d93ffredcimport java.util.Map;
356c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
366c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie/**
376c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie * Provides Bluetooth A2DP profile, as a service in the Bluetooth application.
386c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie * @hide
396c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie */
40b5cc776c9353a203cdde97e62b25f05d9633d14cfredcpublic class A2dpService extends ProfileService {
41fd1da115cbf09b7dd9bca3c7d3a4fb816a835dc5Matthew Xie    private static final boolean DBG = false;
42b5cc776c9353a203cdde97e62b25f05d9633d14cfredc    private static final String TAG="A2dpService";
436c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
446c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie    private A2dpStateMachine mStateMachine;
45c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    private Avrcp mAvrcp;
464f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta    private static A2dpService sAd2dpService;
47e316dfc9b3f648ad3d7b2691927758ea885043c0Anubhav Gupta    static final ParcelUuid[] A2DP_SOURCE_UUID = {
48e316dfc9b3f648ad3d7b2691927758ea885043c0Anubhav Gupta        BluetoothUuid.AudioSource
49e316dfc9b3f648ad3d7b2691927758ea885043c0Anubhav Gupta    };
50e316dfc9b3f648ad3d7b2691927758ea885043c0Anubhav Gupta    static final ParcelUuid[] A2DP_SOURCE_SINK_UUIDS = {
51e316dfc9b3f648ad3d7b2691927758ea885043c0Anubhav Gupta        BluetoothUuid.AudioSource,
52e316dfc9b3f648ad3d7b2691927758ea885043c0Anubhav Gupta        BluetoothUuid.AudioSink
53e316dfc9b3f648ad3d7b2691927758ea885043c0Anubhav Gupta    };
546c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
5574ae04c73312403e89db0f8e9bd9601d403b4783fredc    protected String getName() {
5674ae04c73312403e89db0f8e9bd9601d403b4783fredc        return TAG;
5774ae04c73312403e89db0f8e9bd9601d403b4783fredc    }
5874ae04c73312403e89db0f8e9bd9601d403b4783fredc
5974ae04c73312403e89db0f8e9bd9601d403b4783fredc    protected IProfileServiceBinder initBinder() {
6074ae04c73312403e89db0f8e9bd9601d403b4783fredc        return new BluetoothA2dpBinder(this);
6174ae04c73312403e89db0f8e9bd9601d403b4783fredc    }
626c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
63b5cc776c9353a203cdde97e62b25f05d9633d14cfredc    protected boolean start() {
64c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        mAvrcp = Avrcp.make(this);
65188f205b5f093850d4cc627917a21204be36c56aZhihai Xu        mStateMachine = A2dpStateMachine.make(this, this);
664f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta        setA2dpService(this);
67b5cc776c9353a203cdde97e62b25f05d9633d14cfredc        return true;
686654f5c903de510a70f9e72cd5ad7837b615d93ffredc    }
696654f5c903de510a70f9e72cd5ad7837b615d93ffredc
70b5cc776c9353a203cdde97e62b25f05d9633d14cfredc    protected boolean stop() {
71ff833ce646e50c3593a313cd6a0be53577e41112Thomas Lehaux        if (mStateMachine != null) {
72ff833ce646e50c3593a313cd6a0be53577e41112Thomas Lehaux            mStateMachine.doQuit();
73ff833ce646e50c3593a313cd6a0be53577e41112Thomas Lehaux        }
742609a11670563837625f7dde2192deaba7417e46Andre Eisenbach        if (mAvrcp != null) {
752609a11670563837625f7dde2192deaba7417e46Andre Eisenbach            mAvrcp.doQuit();
762609a11670563837625f7dde2192deaba7417e46Andre Eisenbach        }
7774ae04c73312403e89db0f8e9bd9601d403b4783fredc        return true;
7874ae04c73312403e89db0f8e9bd9601d403b4783fredc    }
7974ae04c73312403e89db0f8e9bd9601d403b4783fredc
8074ae04c73312403e89db0f8e9bd9601d403b4783fredc    protected boolean cleanup() {
816654f5c903de510a70f9e72cd5ad7837b615d93ffredc        if (mStateMachine!= null) {
826654f5c903de510a70f9e72cd5ad7837b615d93ffredc            mStateMachine.cleanup();
836654f5c903de510a70f9e72cd5ad7837b615d93ffredc        }
84c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        if (mAvrcp != null) {
85c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            mAvrcp.cleanup();
86c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            mAvrcp = null;
87c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        }
884f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta        clearA2dpService();
89b5cc776c9353a203cdde97e62b25f05d9633d14cfredc        return true;
90b5cc776c9353a203cdde97e62b25f05d9633d14cfredc    }
916654f5c903de510a70f9e72cd5ad7837b615d93ffredc
9274ae04c73312403e89db0f8e9bd9601d403b4783fredc    //API Methods
934f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta
944f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta    public static synchronized A2dpService getA2dpService(){
954f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta        if (sAd2dpService != null && sAd2dpService.isAvailable()) {
964f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta            if (DBG) Log.d(TAG, "getA2DPService(): returning " + sAd2dpService);
974f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta            return sAd2dpService;
984f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta        }
994f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta        if (DBG)  {
1004f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta            if (sAd2dpService == null) {
1014f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta                Log.d(TAG, "getA2dpService(): service is NULL");
1024f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta            } else if (!(sAd2dpService.isAvailable())) {
1034f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta                Log.d(TAG,"getA2dpService(): service is not available");
1044f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta            }
1054f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta        }
1064f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta        return null;
1074f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta    }
1084f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta
1094f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta    private static synchronized void setA2dpService(A2dpService instance) {
1104f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta        if (instance != null && instance.isAvailable()) {
1114f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta            if (DBG) Log.d(TAG, "setA2dpService(): set to: " + sAd2dpService);
1124f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta            sAd2dpService = instance;
1134f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta        } else {
1144f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta            if (DBG)  {
1154f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta                if (sAd2dpService == null) {
1164f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta                    Log.d(TAG, "setA2dpService(): service not available");
1174f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta                } else if (!sAd2dpService.isAvailable()) {
1184f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta                    Log.d(TAG,"setA2dpService(): service is cleaning up");
1194f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta                }
1204f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta            }
1214f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta        }
1224f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta    }
1234f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta
1244f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta    private static synchronized void clearA2dpService() {
1254f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta        sAd2dpService = null;
1264f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta    }
1274f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta
1284f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta    public boolean connect(BluetoothDevice device) {
12974ae04c73312403e89db0f8e9bd9601d403b4783fredc        enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
13074ae04c73312403e89db0f8e9bd9601d403b4783fredc                                       "Need BLUETOOTH ADMIN permission");
13174ae04c73312403e89db0f8e9bd9601d403b4783fredc
13274ae04c73312403e89db0f8e9bd9601d403b4783fredc        if (getPriority(device) == BluetoothProfile.PRIORITY_OFF) {
13374ae04c73312403e89db0f8e9bd9601d403b4783fredc            return false;
13474ae04c73312403e89db0f8e9bd9601d403b4783fredc        }
135e316dfc9b3f648ad3d7b2691927758ea885043c0Anubhav Gupta        ParcelUuid[] featureUuids = device.getUuids();
136e316dfc9b3f648ad3d7b2691927758ea885043c0Anubhav Gupta        if ((BluetoothUuid.containsAnyUuid(featureUuids, A2DP_SOURCE_UUID)) &&
137e316dfc9b3f648ad3d7b2691927758ea885043c0Anubhav Gupta            !(BluetoothUuid.containsAllUuids(featureUuids ,A2DP_SOURCE_SINK_UUIDS))) {
138e316dfc9b3f648ad3d7b2691927758ea885043c0Anubhav Gupta            Log.e(TAG,"Remote does not have A2dp Sink UUID");
139e316dfc9b3f648ad3d7b2691927758ea885043c0Anubhav Gupta            return false;
140e316dfc9b3f648ad3d7b2691927758ea885043c0Anubhav Gupta        }
14174ae04c73312403e89db0f8e9bd9601d403b4783fredc
14274ae04c73312403e89db0f8e9bd9601d403b4783fredc        int connectionState = mStateMachine.getConnectionState(device);
14374ae04c73312403e89db0f8e9bd9601d403b4783fredc        if (connectionState == BluetoothProfile.STATE_CONNECTED ||
14474ae04c73312403e89db0f8e9bd9601d403b4783fredc            connectionState == BluetoothProfile.STATE_CONNECTING) {
14574ae04c73312403e89db0f8e9bd9601d403b4783fredc            return false;
14674ae04c73312403e89db0f8e9bd9601d403b4783fredc        }
14774ae04c73312403e89db0f8e9bd9601d403b4783fredc
14874ae04c73312403e89db0f8e9bd9601d403b4783fredc        mStateMachine.sendMessage(A2dpStateMachine.CONNECT, device);
14974ae04c73312403e89db0f8e9bd9601d403b4783fredc        return true;
150b5cc776c9353a203cdde97e62b25f05d9633d14cfredc    }
151b5cc776c9353a203cdde97e62b25f05d9633d14cfredc
15274ae04c73312403e89db0f8e9bd9601d403b4783fredc    boolean disconnect(BluetoothDevice device) {
15374ae04c73312403e89db0f8e9bd9601d403b4783fredc        enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
15474ae04c73312403e89db0f8e9bd9601d403b4783fredc                                       "Need BLUETOOTH ADMIN permission");
15574ae04c73312403e89db0f8e9bd9601d403b4783fredc        int connectionState = mStateMachine.getConnectionState(device);
15674ae04c73312403e89db0f8e9bd9601d403b4783fredc        if (connectionState != BluetoothProfile.STATE_CONNECTED &&
15774ae04c73312403e89db0f8e9bd9601d403b4783fredc            connectionState != BluetoothProfile.STATE_CONNECTING) {
15874ae04c73312403e89db0f8e9bd9601d403b4783fredc            return false;
15974ae04c73312403e89db0f8e9bd9601d403b4783fredc        }
16074ae04c73312403e89db0f8e9bd9601d403b4783fredc
16174ae04c73312403e89db0f8e9bd9601d403b4783fredc        mStateMachine.sendMessage(A2dpStateMachine.DISCONNECT, device);
16274ae04c73312403e89db0f8e9bd9601d403b4783fredc        return true;
1636c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie    }
1646c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
1654f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta    public List<BluetoothDevice> getConnectedDevices() {
16674ae04c73312403e89db0f8e9bd9601d403b4783fredc        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
16774ae04c73312403e89db0f8e9bd9601d403b4783fredc        return mStateMachine.getConnectedDevices();
16874ae04c73312403e89db0f8e9bd9601d403b4783fredc    }
1696c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
17074ae04c73312403e89db0f8e9bd9601d403b4783fredc    List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
17174ae04c73312403e89db0f8e9bd9601d403b4783fredc        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
17274ae04c73312403e89db0f8e9bd9601d403b4783fredc        return mStateMachine.getDevicesMatchingConnectionStates(states);
17374ae04c73312403e89db0f8e9bd9601d403b4783fredc    }
1746c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
17574ae04c73312403e89db0f8e9bd9601d403b4783fredc    int getConnectionState(BluetoothDevice device) {
17674ae04c73312403e89db0f8e9bd9601d403b4783fredc        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
17774ae04c73312403e89db0f8e9bd9601d403b4783fredc        return mStateMachine.getConnectionState(device);
17874ae04c73312403e89db0f8e9bd9601d403b4783fredc    }
17974ae04c73312403e89db0f8e9bd9601d403b4783fredc
1804f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta    public boolean setPriority(BluetoothDevice device, int priority) {
18174ae04c73312403e89db0f8e9bd9601d403b4783fredc        enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
18274ae04c73312403e89db0f8e9bd9601d403b4783fredc                                       "Need BLUETOOTH_ADMIN permission");
183c7ead6d5827f3832b9210e92fab7597142059852Jeff Sharkey        Settings.Global.putInt(getContentResolver(),
184c7ead6d5827f3832b9210e92fab7597142059852Jeff Sharkey            Settings.Global.getBluetoothA2dpSinkPriorityKey(device.getAddress()),
18574ae04c73312403e89db0f8e9bd9601d403b4783fredc            priority);
18674ae04c73312403e89db0f8e9bd9601d403b4783fredc        if (DBG) Log.d(TAG,"Saved priority " + device + " = " + priority);
18774ae04c73312403e89db0f8e9bd9601d403b4783fredc        return true;
18874ae04c73312403e89db0f8e9bd9601d403b4783fredc    }
1896c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
1904f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta    public int getPriority(BluetoothDevice device) {
19174ae04c73312403e89db0f8e9bd9601d403b4783fredc        enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
19274ae04c73312403e89db0f8e9bd9601d403b4783fredc                                       "Need BLUETOOTH_ADMIN permission");
193c7ead6d5827f3832b9210e92fab7597142059852Jeff Sharkey        int priority = Settings.Global.getInt(getContentResolver(),
194c7ead6d5827f3832b9210e92fab7597142059852Jeff Sharkey            Settings.Global.getBluetoothA2dpSinkPriorityKey(device.getAddress()),
19574ae04c73312403e89db0f8e9bd9601d403b4783fredc            BluetoothProfile.PRIORITY_UNDEFINED);
19674ae04c73312403e89db0f8e9bd9601d403b4783fredc        return priority;
19774ae04c73312403e89db0f8e9bd9601d403b4783fredc    }
19874ae04c73312403e89db0f8e9bd9601d403b4783fredc
19917675906064bb72fdcca75baa56cdf8bb8968d01John Du    /* Absolute volume implementation */
20017675906064bb72fdcca75baa56cdf8bb8968d01John Du    public boolean isAvrcpAbsoluteVolumeSupported() {
20117675906064bb72fdcca75baa56cdf8bb8968d01John Du        return mAvrcp.isAbsoluteVolumeSupported();
20217675906064bb72fdcca75baa56cdf8bb8968d01John Du    }
20317675906064bb72fdcca75baa56cdf8bb8968d01John Du
20417675906064bb72fdcca75baa56cdf8bb8968d01John Du    public void adjustAvrcpAbsoluteVolume(int direction) {
20517675906064bb72fdcca75baa56cdf8bb8968d01John Du        mAvrcp.adjustVolume(direction);
20617675906064bb72fdcca75baa56cdf8bb8968d01John Du    }
20717675906064bb72fdcca75baa56cdf8bb8968d01John Du
20817675906064bb72fdcca75baa56cdf8bb8968d01John Du    public void setAvrcpAbsoluteVolume(int volume) {
20917675906064bb72fdcca75baa56cdf8bb8968d01John Du        mAvrcp.setAbsoluteVolume(volume);
21017675906064bb72fdcca75baa56cdf8bb8968d01John Du    }
21117675906064bb72fdcca75baa56cdf8bb8968d01John Du
212188f205b5f093850d4cc627917a21204be36c56aZhihai Xu    public void setAvrcpAudioState(int state) {
213188f205b5f093850d4cc627917a21204be36c56aZhihai Xu        mAvrcp.setA2dpAudioState(state);
214188f205b5f093850d4cc627917a21204be36c56aZhihai Xu    }
215188f205b5f093850d4cc627917a21204be36c56aZhihai Xu
21611798b011c962b602217b479130d413f3b30f19aLiejun Tao    public void resetAvrcpBlacklist(BluetoothDevice device) {
217f924b023dbe14a1183ca9d9688c38406e8717381Pavlin Radoslavov        if (mAvrcp != null) {
218f924b023dbe14a1183ca9d9688c38406e8717381Pavlin Radoslavov            mAvrcp.resetBlackList(device.getAddress());
219f924b023dbe14a1183ca9d9688c38406e8717381Pavlin Radoslavov        }
22011798b011c962b602217b479130d413f3b30f19aLiejun Tao    }
22111798b011c962b602217b479130d413f3b30f19aLiejun Tao
22274ae04c73312403e89db0f8e9bd9601d403b4783fredc    synchronized boolean isA2dpPlaying(BluetoothDevice device) {
22374ae04c73312403e89db0f8e9bd9601d403b4783fredc        enforceCallingOrSelfPermission(BLUETOOTH_PERM,
22474ae04c73312403e89db0f8e9bd9601d403b4783fredc                                       "Need BLUETOOTH permission");
22574ae04c73312403e89db0f8e9bd9601d403b4783fredc        if (DBG) Log.d(TAG, "isA2dpPlaying(" + device + ")");
22674ae04c73312403e89db0f8e9bd9601d403b4783fredc        return mStateMachine.isPlaying(device);
22774ae04c73312403e89db0f8e9bd9601d403b4783fredc    }
22874ae04c73312403e89db0f8e9bd9601d403b4783fredc
22974ae04c73312403e89db0f8e9bd9601d403b4783fredc    //Binder object: Must be static class or memory leak may occur
23074ae04c73312403e89db0f8e9bd9601d403b4783fredc    private static class BluetoothA2dpBinder extends IBluetoothA2dp.Stub
23174ae04c73312403e89db0f8e9bd9601d403b4783fredc        implements IProfileServiceBinder {
23274ae04c73312403e89db0f8e9bd9601d403b4783fredc        private A2dpService mService;
23374ae04c73312403e89db0f8e9bd9601d403b4783fredc
23474ae04c73312403e89db0f8e9bd9601d403b4783fredc        private A2dpService getService() {
23537510150ee738ccfa5913f7120e28f25ae7768dfZhihai Xu            if (!Utils.checkCaller()) {
23637510150ee738ccfa5913f7120e28f25ae7768dfZhihai Xu                Log.w(TAG,"A2dp call not allowed for non-active user");
23737510150ee738ccfa5913f7120e28f25ae7768dfZhihai Xu                return null;
23837510150ee738ccfa5913f7120e28f25ae7768dfZhihai Xu            }
23937510150ee738ccfa5913f7120e28f25ae7768dfZhihai Xu
24037510150ee738ccfa5913f7120e28f25ae7768dfZhihai Xu            if (mService != null && mService.isAvailable()) {
24174ae04c73312403e89db0f8e9bd9601d403b4783fredc                return mService;
2426c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            }
24374ae04c73312403e89db0f8e9bd9601d403b4783fredc            return null;
24474ae04c73312403e89db0f8e9bd9601d403b4783fredc        }
2456c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
24674ae04c73312403e89db0f8e9bd9601d403b4783fredc        BluetoothA2dpBinder(A2dpService svc) {
24774ae04c73312403e89db0f8e9bd9601d403b4783fredc            mService = svc;
24874ae04c73312403e89db0f8e9bd9601d403b4783fredc        }
24974ae04c73312403e89db0f8e9bd9601d403b4783fredc
25074ae04c73312403e89db0f8e9bd9601d403b4783fredc        public boolean cleanup()  {
25174ae04c73312403e89db0f8e9bd9601d403b4783fredc            mService = null;
2526c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            return true;
2536c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        }
2546c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
25574ae04c73312403e89db0f8e9bd9601d403b4783fredc        public boolean connect(BluetoothDevice device) {
25674ae04c73312403e89db0f8e9bd9601d403b4783fredc            A2dpService service = getService();
25774ae04c73312403e89db0f8e9bd9601d403b4783fredc            if (service == null) return false;
25874ae04c73312403e89db0f8e9bd9601d403b4783fredc            return service.connect(device);
25974ae04c73312403e89db0f8e9bd9601d403b4783fredc        }
2606c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
26174ae04c73312403e89db0f8e9bd9601d403b4783fredc        public boolean disconnect(BluetoothDevice device) {
26274ae04c73312403e89db0f8e9bd9601d403b4783fredc            A2dpService service = getService();
26374ae04c73312403e89db0f8e9bd9601d403b4783fredc            if (service == null) return false;
26474ae04c73312403e89db0f8e9bd9601d403b4783fredc            return service.disconnect(device);
2656c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        }
2666c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
2676c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        public List<BluetoothDevice> getConnectedDevices() {
26874ae04c73312403e89db0f8e9bd9601d403b4783fredc            A2dpService service = getService();
26974ae04c73312403e89db0f8e9bd9601d403b4783fredc            if (service == null) return new ArrayList<BluetoothDevice>(0);
27074ae04c73312403e89db0f8e9bd9601d403b4783fredc            return service.getConnectedDevices();
2716c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        }
2726c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
2736c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
27474ae04c73312403e89db0f8e9bd9601d403b4783fredc            A2dpService service = getService();
27574ae04c73312403e89db0f8e9bd9601d403b4783fredc            if (service == null) return new ArrayList<BluetoothDevice>(0);
27674ae04c73312403e89db0f8e9bd9601d403b4783fredc            return service.getDevicesMatchingConnectionStates(states);
2776c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        }
2786c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
2796c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        public int getConnectionState(BluetoothDevice device) {
28074ae04c73312403e89db0f8e9bd9601d403b4783fredc            A2dpService service = getService();
28174ae04c73312403e89db0f8e9bd9601d403b4783fredc            if (service == null) return BluetoothProfile.STATE_DISCONNECTED;
28274ae04c73312403e89db0f8e9bd9601d403b4783fredc            return service.getConnectionState(device);
2836c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        }
2846c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
2856c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        public boolean setPriority(BluetoothDevice device, int priority) {
28674ae04c73312403e89db0f8e9bd9601d403b4783fredc            A2dpService service = getService();
28774ae04c73312403e89db0f8e9bd9601d403b4783fredc            if (service == null) return false;
28874ae04c73312403e89db0f8e9bd9601d403b4783fredc            return service.setPriority(device, priority);
2896c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        }
2906c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
2916c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        public int getPriority(BluetoothDevice device) {
29274ae04c73312403e89db0f8e9bd9601d403b4783fredc            A2dpService service = getService();
29374ae04c73312403e89db0f8e9bd9601d403b4783fredc            if (service == null) return BluetoothProfile.PRIORITY_UNDEFINED;
29474ae04c73312403e89db0f8e9bd9601d403b4783fredc            return service.getPriority(device);
2956c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        }
2966c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
29717675906064bb72fdcca75baa56cdf8bb8968d01John Du        public boolean isAvrcpAbsoluteVolumeSupported() {
29817675906064bb72fdcca75baa56cdf8bb8968d01John Du            A2dpService service = getService();
29917675906064bb72fdcca75baa56cdf8bb8968d01John Du            if (service == null) return false;
30017675906064bb72fdcca75baa56cdf8bb8968d01John Du            return service.isAvrcpAbsoluteVolumeSupported();
30117675906064bb72fdcca75baa56cdf8bb8968d01John Du        }
30217675906064bb72fdcca75baa56cdf8bb8968d01John Du
30317675906064bb72fdcca75baa56cdf8bb8968d01John Du        public void adjustAvrcpAbsoluteVolume(int direction) {
30417675906064bb72fdcca75baa56cdf8bb8968d01John Du            A2dpService service = getService();
30517675906064bb72fdcca75baa56cdf8bb8968d01John Du            if (service == null) return;
30617675906064bb72fdcca75baa56cdf8bb8968d01John Du            service.adjustAvrcpAbsoluteVolume(direction);
30717675906064bb72fdcca75baa56cdf8bb8968d01John Du        }
30817675906064bb72fdcca75baa56cdf8bb8968d01John Du
30917675906064bb72fdcca75baa56cdf8bb8968d01John Du        public void setAvrcpAbsoluteVolume(int volume) {
31017675906064bb72fdcca75baa56cdf8bb8968d01John Du            A2dpService service = getService();
31117675906064bb72fdcca75baa56cdf8bb8968d01John Du            if (service == null) return;
31217675906064bb72fdcca75baa56cdf8bb8968d01John Du            service.setAvrcpAbsoluteVolume(volume);
31317675906064bb72fdcca75baa56cdf8bb8968d01John Du        }
31417675906064bb72fdcca75baa56cdf8bb8968d01John Du
31574ae04c73312403e89db0f8e9bd9601d403b4783fredc        public boolean isA2dpPlaying(BluetoothDevice device) {
31674ae04c73312403e89db0f8e9bd9601d403b4783fredc            A2dpService service = getService();
31774ae04c73312403e89db0f8e9bd9601d403b4783fredc            if (service == null) return false;
31874ae04c73312403e89db0f8e9bd9601d403b4783fredc            return service.isA2dpPlaying(device);
3196c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        }
3206c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie    };
321838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood
322838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood    @Override
323838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood    public void dump(StringBuilder sb) {
324838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood        super.dump(sb);
325838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood        if (mStateMachine != null) {
326838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood            mStateMachine.dump(sb);
327838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood        }
328838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood        if (mAvrcp != null) {
329838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood            mAvrcp.dump(sb);
330838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood        }
331838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood    }
3326c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie}
333