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;
216c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xieimport android.bluetooth.IBluetoothA2dp;
226c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xieimport android.content.Context;
236c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xieimport android.content.Intent;
246c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xieimport android.provider.Settings;
256c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xieimport android.util.Log;
26066ad9e16a548218b139424f758b92db7af34af2Mike Lockwoodimport com.android.bluetooth.avrcp.Avrcp;
2737510150ee738ccfa5913f7120e28f25ae7768dfZhihai Xuimport com.android.bluetooth.btservice.ProfileService;
2837510150ee738ccfa5913f7120e28f25ae7768dfZhihai Xuimport com.android.bluetooth.Utils;
2974ae04c73312403e89db0f8e9bd9601d403b4783fredcimport java.util.ArrayList;
306654f5c903de510a70f9e72cd5ad7837b615d93ffredcimport java.util.Iterator;
3137510150ee738ccfa5913f7120e28f25ae7768dfZhihai Xuimport java.util.List;
326654f5c903de510a70f9e72cd5ad7837b615d93ffredcimport java.util.Map;
336c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
346c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie/**
356c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie * Provides Bluetooth A2DP profile, as a service in the Bluetooth application.
366c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie * @hide
376c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie */
38b5cc776c9353a203cdde97e62b25f05d9633d14cfredcpublic class A2dpService extends ProfileService {
39fd1da115cbf09b7dd9bca3c7d3a4fb816a835dc5Matthew Xie    private static final boolean DBG = false;
40b5cc776c9353a203cdde97e62b25f05d9633d14cfredc    private static final String TAG="A2dpService";
416c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
426c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie    private A2dpStateMachine mStateMachine;
43c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    private Avrcp mAvrcp;
444f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta    private static A2dpService sAd2dpService;
456c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
4674ae04c73312403e89db0f8e9bd9601d403b4783fredc    protected String getName() {
4774ae04c73312403e89db0f8e9bd9601d403b4783fredc        return TAG;
4874ae04c73312403e89db0f8e9bd9601d403b4783fredc    }
4974ae04c73312403e89db0f8e9bd9601d403b4783fredc
5074ae04c73312403e89db0f8e9bd9601d403b4783fredc    protected IProfileServiceBinder initBinder() {
5174ae04c73312403e89db0f8e9bd9601d403b4783fredc        return new BluetoothA2dpBinder(this);
5274ae04c73312403e89db0f8e9bd9601d403b4783fredc    }
536c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
54b5cc776c9353a203cdde97e62b25f05d9633d14cfredc    protected boolean start() {
55c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        mAvrcp = Avrcp.make(this);
56188f205b5f093850d4cc627917a21204be36c56aZhihai Xu        mStateMachine = A2dpStateMachine.make(this, this);
574f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta        setA2dpService(this);
58b5cc776c9353a203cdde97e62b25f05d9633d14cfredc        return true;
596654f5c903de510a70f9e72cd5ad7837b615d93ffredc    }
606654f5c903de510a70f9e72cd5ad7837b615d93ffredc
61b5cc776c9353a203cdde97e62b25f05d9633d14cfredc    protected boolean stop() {
62ff833ce646e50c3593a313cd6a0be53577e41112Thomas Lehaux        if (mStateMachine != null) {
63ff833ce646e50c3593a313cd6a0be53577e41112Thomas Lehaux            mStateMachine.doQuit();
64ff833ce646e50c3593a313cd6a0be53577e41112Thomas Lehaux        }
652609a11670563837625f7dde2192deaba7417e46Andre Eisenbach        if (mAvrcp != null) {
662609a11670563837625f7dde2192deaba7417e46Andre Eisenbach            mAvrcp.doQuit();
672609a11670563837625f7dde2192deaba7417e46Andre Eisenbach        }
6874ae04c73312403e89db0f8e9bd9601d403b4783fredc        return true;
6974ae04c73312403e89db0f8e9bd9601d403b4783fredc    }
7074ae04c73312403e89db0f8e9bd9601d403b4783fredc
7174ae04c73312403e89db0f8e9bd9601d403b4783fredc    protected boolean cleanup() {
726654f5c903de510a70f9e72cd5ad7837b615d93ffredc        if (mStateMachine!= null) {
736654f5c903de510a70f9e72cd5ad7837b615d93ffredc            mStateMachine.cleanup();
746654f5c903de510a70f9e72cd5ad7837b615d93ffredc        }
75c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        if (mAvrcp != null) {
76c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            mAvrcp.cleanup();
77c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            mAvrcp = null;
78c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        }
794f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta        clearA2dpService();
80b5cc776c9353a203cdde97e62b25f05d9633d14cfredc        return true;
81b5cc776c9353a203cdde97e62b25f05d9633d14cfredc    }
826654f5c903de510a70f9e72cd5ad7837b615d93ffredc
8374ae04c73312403e89db0f8e9bd9601d403b4783fredc    //API Methods
844f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta
854f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta    public static synchronized A2dpService getA2dpService(){
864f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta        if (sAd2dpService != null && sAd2dpService.isAvailable()) {
874f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta            if (DBG) Log.d(TAG, "getA2DPService(): returning " + sAd2dpService);
884f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta            return sAd2dpService;
894f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta        }
904f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta        if (DBG)  {
914f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta            if (sAd2dpService == null) {
924f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta                Log.d(TAG, "getA2dpService(): service is NULL");
934f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta            } else if (!(sAd2dpService.isAvailable())) {
944f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta                Log.d(TAG,"getA2dpService(): service is not available");
954f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta            }
964f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta        }
974f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta        return null;
984f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta    }
994f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta
1004f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta    private static synchronized void setA2dpService(A2dpService instance) {
1014f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta        if (instance != null && instance.isAvailable()) {
1024f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta            if (DBG) Log.d(TAG, "setA2dpService(): set to: " + sAd2dpService);
1034f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta            sAd2dpService = instance;
1044f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta        } else {
1054f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta            if (DBG)  {
1064f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta                if (sAd2dpService == null) {
1074f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta                    Log.d(TAG, "setA2dpService(): service not available");
1084f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta                } else if (!sAd2dpService.isAvailable()) {
1094f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta                    Log.d(TAG,"setA2dpService(): service is cleaning up");
1104f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta                }
1114f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta            }
1124f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta        }
1134f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta    }
1144f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta
1154f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta    private static synchronized void clearA2dpService() {
1164f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta        sAd2dpService = null;
1174f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta    }
1184f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta
1194f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta    public boolean connect(BluetoothDevice device) {
12074ae04c73312403e89db0f8e9bd9601d403b4783fredc        enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
12174ae04c73312403e89db0f8e9bd9601d403b4783fredc                                       "Need BLUETOOTH ADMIN permission");
12274ae04c73312403e89db0f8e9bd9601d403b4783fredc
12374ae04c73312403e89db0f8e9bd9601d403b4783fredc        if (getPriority(device) == BluetoothProfile.PRIORITY_OFF) {
12474ae04c73312403e89db0f8e9bd9601d403b4783fredc            return false;
12574ae04c73312403e89db0f8e9bd9601d403b4783fredc        }
12674ae04c73312403e89db0f8e9bd9601d403b4783fredc
12774ae04c73312403e89db0f8e9bd9601d403b4783fredc        int connectionState = mStateMachine.getConnectionState(device);
12874ae04c73312403e89db0f8e9bd9601d403b4783fredc        if (connectionState == BluetoothProfile.STATE_CONNECTED ||
12974ae04c73312403e89db0f8e9bd9601d403b4783fredc            connectionState == BluetoothProfile.STATE_CONNECTING) {
13074ae04c73312403e89db0f8e9bd9601d403b4783fredc            return false;
13174ae04c73312403e89db0f8e9bd9601d403b4783fredc        }
13274ae04c73312403e89db0f8e9bd9601d403b4783fredc
13374ae04c73312403e89db0f8e9bd9601d403b4783fredc        mStateMachine.sendMessage(A2dpStateMachine.CONNECT, device);
13474ae04c73312403e89db0f8e9bd9601d403b4783fredc        return true;
135b5cc776c9353a203cdde97e62b25f05d9633d14cfredc    }
136b5cc776c9353a203cdde97e62b25f05d9633d14cfredc
13774ae04c73312403e89db0f8e9bd9601d403b4783fredc    boolean disconnect(BluetoothDevice device) {
13874ae04c73312403e89db0f8e9bd9601d403b4783fredc        enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
13974ae04c73312403e89db0f8e9bd9601d403b4783fredc                                       "Need BLUETOOTH ADMIN permission");
14074ae04c73312403e89db0f8e9bd9601d403b4783fredc        int connectionState = mStateMachine.getConnectionState(device);
14174ae04c73312403e89db0f8e9bd9601d403b4783fredc        if (connectionState != BluetoothProfile.STATE_CONNECTED &&
14274ae04c73312403e89db0f8e9bd9601d403b4783fredc            connectionState != BluetoothProfile.STATE_CONNECTING) {
14374ae04c73312403e89db0f8e9bd9601d403b4783fredc            return false;
14474ae04c73312403e89db0f8e9bd9601d403b4783fredc        }
14574ae04c73312403e89db0f8e9bd9601d403b4783fredc
14674ae04c73312403e89db0f8e9bd9601d403b4783fredc        mStateMachine.sendMessage(A2dpStateMachine.DISCONNECT, device);
14774ae04c73312403e89db0f8e9bd9601d403b4783fredc        return true;
1486c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie    }
1496c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
1504f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta    public List<BluetoothDevice> getConnectedDevices() {
15174ae04c73312403e89db0f8e9bd9601d403b4783fredc        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
15274ae04c73312403e89db0f8e9bd9601d403b4783fredc        return mStateMachine.getConnectedDevices();
15374ae04c73312403e89db0f8e9bd9601d403b4783fredc    }
1546c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
15574ae04c73312403e89db0f8e9bd9601d403b4783fredc    List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
15674ae04c73312403e89db0f8e9bd9601d403b4783fredc        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
15774ae04c73312403e89db0f8e9bd9601d403b4783fredc        return mStateMachine.getDevicesMatchingConnectionStates(states);
15874ae04c73312403e89db0f8e9bd9601d403b4783fredc    }
1596c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
16074ae04c73312403e89db0f8e9bd9601d403b4783fredc    int getConnectionState(BluetoothDevice device) {
16174ae04c73312403e89db0f8e9bd9601d403b4783fredc        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
16274ae04c73312403e89db0f8e9bd9601d403b4783fredc        return mStateMachine.getConnectionState(device);
16374ae04c73312403e89db0f8e9bd9601d403b4783fredc    }
16474ae04c73312403e89db0f8e9bd9601d403b4783fredc
1654f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta    public boolean setPriority(BluetoothDevice device, int priority) {
16674ae04c73312403e89db0f8e9bd9601d403b4783fredc        enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
16774ae04c73312403e89db0f8e9bd9601d403b4783fredc                                       "Need BLUETOOTH_ADMIN permission");
168c7ead6d5827f3832b9210e92fab7597142059852Jeff Sharkey        Settings.Global.putInt(getContentResolver(),
169c7ead6d5827f3832b9210e92fab7597142059852Jeff Sharkey            Settings.Global.getBluetoothA2dpSinkPriorityKey(device.getAddress()),
17074ae04c73312403e89db0f8e9bd9601d403b4783fredc            priority);
17174ae04c73312403e89db0f8e9bd9601d403b4783fredc        if (DBG) Log.d(TAG,"Saved priority " + device + " = " + priority);
17274ae04c73312403e89db0f8e9bd9601d403b4783fredc        return true;
17374ae04c73312403e89db0f8e9bd9601d403b4783fredc    }
1746c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
1754f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta    public int getPriority(BluetoothDevice device) {
17674ae04c73312403e89db0f8e9bd9601d403b4783fredc        enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
17774ae04c73312403e89db0f8e9bd9601d403b4783fredc                                       "Need BLUETOOTH_ADMIN permission");
178c7ead6d5827f3832b9210e92fab7597142059852Jeff Sharkey        int priority = Settings.Global.getInt(getContentResolver(),
179c7ead6d5827f3832b9210e92fab7597142059852Jeff Sharkey            Settings.Global.getBluetoothA2dpSinkPriorityKey(device.getAddress()),
18074ae04c73312403e89db0f8e9bd9601d403b4783fredc            BluetoothProfile.PRIORITY_UNDEFINED);
18174ae04c73312403e89db0f8e9bd9601d403b4783fredc        return priority;
18274ae04c73312403e89db0f8e9bd9601d403b4783fredc    }
18374ae04c73312403e89db0f8e9bd9601d403b4783fredc
18417675906064bb72fdcca75baa56cdf8bb8968d01John Du    /* Absolute volume implementation */
18517675906064bb72fdcca75baa56cdf8bb8968d01John Du    public boolean isAvrcpAbsoluteVolumeSupported() {
18617675906064bb72fdcca75baa56cdf8bb8968d01John Du        return mAvrcp.isAbsoluteVolumeSupported();
18717675906064bb72fdcca75baa56cdf8bb8968d01John Du    }
18817675906064bb72fdcca75baa56cdf8bb8968d01John Du
18917675906064bb72fdcca75baa56cdf8bb8968d01John Du    public void adjustAvrcpAbsoluteVolume(int direction) {
19017675906064bb72fdcca75baa56cdf8bb8968d01John Du        mAvrcp.adjustVolume(direction);
19117675906064bb72fdcca75baa56cdf8bb8968d01John Du    }
19217675906064bb72fdcca75baa56cdf8bb8968d01John Du
19317675906064bb72fdcca75baa56cdf8bb8968d01John Du    public void setAvrcpAbsoluteVolume(int volume) {
19417675906064bb72fdcca75baa56cdf8bb8968d01John Du        mAvrcp.setAbsoluteVolume(volume);
19517675906064bb72fdcca75baa56cdf8bb8968d01John Du    }
19617675906064bb72fdcca75baa56cdf8bb8968d01John Du
197188f205b5f093850d4cc627917a21204be36c56aZhihai Xu    public void setAvrcpAudioState(int state) {
198188f205b5f093850d4cc627917a21204be36c56aZhihai Xu        mAvrcp.setA2dpAudioState(state);
199188f205b5f093850d4cc627917a21204be36c56aZhihai Xu    }
200188f205b5f093850d4cc627917a21204be36c56aZhihai Xu
20174ae04c73312403e89db0f8e9bd9601d403b4783fredc    synchronized boolean isA2dpPlaying(BluetoothDevice device) {
20274ae04c73312403e89db0f8e9bd9601d403b4783fredc        enforceCallingOrSelfPermission(BLUETOOTH_PERM,
20374ae04c73312403e89db0f8e9bd9601d403b4783fredc                                       "Need BLUETOOTH permission");
20474ae04c73312403e89db0f8e9bd9601d403b4783fredc        if (DBG) Log.d(TAG, "isA2dpPlaying(" + device + ")");
20574ae04c73312403e89db0f8e9bd9601d403b4783fredc        return mStateMachine.isPlaying(device);
20674ae04c73312403e89db0f8e9bd9601d403b4783fredc    }
20774ae04c73312403e89db0f8e9bd9601d403b4783fredc
20874ae04c73312403e89db0f8e9bd9601d403b4783fredc    //Binder object: Must be static class or memory leak may occur
20974ae04c73312403e89db0f8e9bd9601d403b4783fredc    private static class BluetoothA2dpBinder extends IBluetoothA2dp.Stub
21074ae04c73312403e89db0f8e9bd9601d403b4783fredc        implements IProfileServiceBinder {
21174ae04c73312403e89db0f8e9bd9601d403b4783fredc        private A2dpService mService;
21274ae04c73312403e89db0f8e9bd9601d403b4783fredc
21374ae04c73312403e89db0f8e9bd9601d403b4783fredc        private A2dpService getService() {
21437510150ee738ccfa5913f7120e28f25ae7768dfZhihai Xu            if (!Utils.checkCaller()) {
21537510150ee738ccfa5913f7120e28f25ae7768dfZhihai Xu                Log.w(TAG,"A2dp call not allowed for non-active user");
21637510150ee738ccfa5913f7120e28f25ae7768dfZhihai Xu                return null;
21737510150ee738ccfa5913f7120e28f25ae7768dfZhihai Xu            }
21837510150ee738ccfa5913f7120e28f25ae7768dfZhihai Xu
21937510150ee738ccfa5913f7120e28f25ae7768dfZhihai Xu            if (mService != null && mService.isAvailable()) {
22074ae04c73312403e89db0f8e9bd9601d403b4783fredc                return mService;
2216c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            }
22274ae04c73312403e89db0f8e9bd9601d403b4783fredc            return null;
22374ae04c73312403e89db0f8e9bd9601d403b4783fredc        }
2246c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
22574ae04c73312403e89db0f8e9bd9601d403b4783fredc        BluetoothA2dpBinder(A2dpService svc) {
22674ae04c73312403e89db0f8e9bd9601d403b4783fredc            mService = svc;
22774ae04c73312403e89db0f8e9bd9601d403b4783fredc        }
22874ae04c73312403e89db0f8e9bd9601d403b4783fredc
22974ae04c73312403e89db0f8e9bd9601d403b4783fredc        public boolean cleanup()  {
23074ae04c73312403e89db0f8e9bd9601d403b4783fredc            mService = null;
2316c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            return true;
2326c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        }
2336c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
23474ae04c73312403e89db0f8e9bd9601d403b4783fredc        public boolean connect(BluetoothDevice device) {
23574ae04c73312403e89db0f8e9bd9601d403b4783fredc            A2dpService service = getService();
23674ae04c73312403e89db0f8e9bd9601d403b4783fredc            if (service == null) return false;
23774ae04c73312403e89db0f8e9bd9601d403b4783fredc            return service.connect(device);
23874ae04c73312403e89db0f8e9bd9601d403b4783fredc        }
2396c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
24074ae04c73312403e89db0f8e9bd9601d403b4783fredc        public boolean disconnect(BluetoothDevice device) {
24174ae04c73312403e89db0f8e9bd9601d403b4783fredc            A2dpService service = getService();
24274ae04c73312403e89db0f8e9bd9601d403b4783fredc            if (service == null) return false;
24374ae04c73312403e89db0f8e9bd9601d403b4783fredc            return service.disconnect(device);
2446c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        }
2456c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
2466c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        public List<BluetoothDevice> getConnectedDevices() {
24774ae04c73312403e89db0f8e9bd9601d403b4783fredc            A2dpService service = getService();
24874ae04c73312403e89db0f8e9bd9601d403b4783fredc            if (service == null) return new ArrayList<BluetoothDevice>(0);
24974ae04c73312403e89db0f8e9bd9601d403b4783fredc            return service.getConnectedDevices();
2506c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        }
2516c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
2526c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
25374ae04c73312403e89db0f8e9bd9601d403b4783fredc            A2dpService service = getService();
25474ae04c73312403e89db0f8e9bd9601d403b4783fredc            if (service == null) return new ArrayList<BluetoothDevice>(0);
25574ae04c73312403e89db0f8e9bd9601d403b4783fredc            return service.getDevicesMatchingConnectionStates(states);
2566c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        }
2576c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
2586c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        public int getConnectionState(BluetoothDevice device) {
25974ae04c73312403e89db0f8e9bd9601d403b4783fredc            A2dpService service = getService();
26074ae04c73312403e89db0f8e9bd9601d403b4783fredc            if (service == null) return BluetoothProfile.STATE_DISCONNECTED;
26174ae04c73312403e89db0f8e9bd9601d403b4783fredc            return service.getConnectionState(device);
2626c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        }
2636c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
2646c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        public boolean setPriority(BluetoothDevice device, int priority) {
26574ae04c73312403e89db0f8e9bd9601d403b4783fredc            A2dpService service = getService();
26674ae04c73312403e89db0f8e9bd9601d403b4783fredc            if (service == null) return false;
26774ae04c73312403e89db0f8e9bd9601d403b4783fredc            return service.setPriority(device, priority);
2686c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        }
2696c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
2706c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        public int getPriority(BluetoothDevice device) {
27174ae04c73312403e89db0f8e9bd9601d403b4783fredc            A2dpService service = getService();
27274ae04c73312403e89db0f8e9bd9601d403b4783fredc            if (service == null) return BluetoothProfile.PRIORITY_UNDEFINED;
27374ae04c73312403e89db0f8e9bd9601d403b4783fredc            return service.getPriority(device);
2746c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        }
2756c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
27617675906064bb72fdcca75baa56cdf8bb8968d01John Du        public boolean isAvrcpAbsoluteVolumeSupported() {
27717675906064bb72fdcca75baa56cdf8bb8968d01John Du            A2dpService service = getService();
27817675906064bb72fdcca75baa56cdf8bb8968d01John Du            if (service == null) return false;
27917675906064bb72fdcca75baa56cdf8bb8968d01John Du            return service.isAvrcpAbsoluteVolumeSupported();
28017675906064bb72fdcca75baa56cdf8bb8968d01John Du        }
28117675906064bb72fdcca75baa56cdf8bb8968d01John Du
28217675906064bb72fdcca75baa56cdf8bb8968d01John Du        public void adjustAvrcpAbsoluteVolume(int direction) {
28317675906064bb72fdcca75baa56cdf8bb8968d01John Du            A2dpService service = getService();
28417675906064bb72fdcca75baa56cdf8bb8968d01John Du            if (service == null) return;
28517675906064bb72fdcca75baa56cdf8bb8968d01John Du            service.adjustAvrcpAbsoluteVolume(direction);
28617675906064bb72fdcca75baa56cdf8bb8968d01John Du        }
28717675906064bb72fdcca75baa56cdf8bb8968d01John Du
28817675906064bb72fdcca75baa56cdf8bb8968d01John Du        public void setAvrcpAbsoluteVolume(int volume) {
28917675906064bb72fdcca75baa56cdf8bb8968d01John Du            A2dpService service = getService();
29017675906064bb72fdcca75baa56cdf8bb8968d01John Du            if (service == null) return;
29117675906064bb72fdcca75baa56cdf8bb8968d01John Du            service.setAvrcpAbsoluteVolume(volume);
29217675906064bb72fdcca75baa56cdf8bb8968d01John Du        }
29317675906064bb72fdcca75baa56cdf8bb8968d01John Du
29474ae04c73312403e89db0f8e9bd9601d403b4783fredc        public boolean isA2dpPlaying(BluetoothDevice device) {
29574ae04c73312403e89db0f8e9bd9601d403b4783fredc            A2dpService service = getService();
29674ae04c73312403e89db0f8e9bd9601d403b4783fredc            if (service == null) return false;
29774ae04c73312403e89db0f8e9bd9601d403b4783fredc            return service.isA2dpPlaying(device);
2986c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        }
2996c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie    };
3006c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie}
301