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
1920155af8008337cb70ea0556472854abf46ca1ebAntony Sargentimport android.bluetooth.BluetoothA2dp;
2033b6b7d2b08dcd7ced1809e2ac653c5e8c2514afPavlin Radoslavovimport android.bluetooth.BluetoothCodecConfig;
2108d3925d3d72837e6f86c9e0beaed5f7b813ea37Pavlin Radoslavovimport android.bluetooth.BluetoothCodecStatus;
226c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xieimport android.bluetooth.BluetoothDevice;
236c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xieimport android.bluetooth.BluetoothProfile;
24e316dfc9b3f648ad3d7b2691927758ea885043c0Anubhav Guptaimport android.bluetooth.BluetoothUuid;
256c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xieimport android.bluetooth.IBluetoothA2dp;
2620155af8008337cb70ea0556472854abf46ca1ebAntony Sargentimport android.content.BroadcastReceiver;
2720155af8008337cb70ea0556472854abf46ca1ebAntony Sargentimport android.content.Context;
2820155af8008337cb70ea0556472854abf46ca1ebAntony Sargentimport android.content.Intent;
2920155af8008337cb70ea0556472854abf46ca1ebAntony Sargentimport android.content.IntentFilter;
30e316dfc9b3f648ad3d7b2691927758ea885043c0Anubhav Guptaimport android.os.ParcelUuid;
316c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xieimport android.provider.Settings;
326c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xieimport android.util.Log;
33066ad9e16a548218b139424f758b92db7af34af2Mike Lockwoodimport com.android.bluetooth.avrcp.Avrcp;
3437510150ee738ccfa5913f7120e28f25ae7768dfZhihai Xuimport com.android.bluetooth.btservice.ProfileService;
3537510150ee738ccfa5913f7120e28f25ae7768dfZhihai Xuimport com.android.bluetooth.Utils;
3674ae04c73312403e89db0f8e9bd9601d403b4783fredcimport java.util.ArrayList;
3737510150ee738ccfa5913f7120e28f25ae7768dfZhihai Xuimport java.util.List;
3833b6b7d2b08dcd7ced1809e2ac653c5e8c2514afPavlin Radoslavovimport java.util.Objects;
396c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
406c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie/**
416c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie * Provides Bluetooth A2DP profile, as a service in the Bluetooth application.
426c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie * @hide
436c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie */
44b5cc776c9353a203cdde97e62b25f05d9633d14cfredcpublic class A2dpService extends ProfileService {
45fd1da115cbf09b7dd9bca3c7d3a4fb816a835dc5Matthew Xie    private static final boolean DBG = false;
46b5cc776c9353a203cdde97e62b25f05d9633d14cfredc    private static final String TAG="A2dpService";
476c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
486c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie    private A2dpStateMachine mStateMachine;
49c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    private Avrcp mAvrcp;
5020155af8008337cb70ea0556472854abf46ca1ebAntony Sargent
5120155af8008337cb70ea0556472854abf46ca1ebAntony Sargent    private BroadcastReceiver mConnectionStateChangedReceiver = new BroadcastReceiver() {
5220155af8008337cb70ea0556472854abf46ca1ebAntony Sargent        @Override
5320155af8008337cb70ea0556472854abf46ca1ebAntony Sargent        public void onReceive(Context context, Intent intent) {
5420155af8008337cb70ea0556472854abf46ca1ebAntony Sargent            if (!BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED.equals(intent.getAction())) {
5520155af8008337cb70ea0556472854abf46ca1ebAntony Sargent                return;
5620155af8008337cb70ea0556472854abf46ca1ebAntony Sargent            }
5720155af8008337cb70ea0556472854abf46ca1ebAntony Sargent            int state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1);
5820155af8008337cb70ea0556472854abf46ca1ebAntony Sargent            BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
5920155af8008337cb70ea0556472854abf46ca1ebAntony Sargent            if (state != BluetoothProfile.STATE_CONNECTED || device == null) {
6020155af8008337cb70ea0556472854abf46ca1ebAntony Sargent                return;
6120155af8008337cb70ea0556472854abf46ca1ebAntony Sargent            }
6220155af8008337cb70ea0556472854abf46ca1ebAntony Sargent            // Each time a device connects, we want to re-check if it supports optional
6320155af8008337cb70ea0556472854abf46ca1ebAntony Sargent            // codecs (perhaps it's had a firmware update, etc.) and save that state if
6420155af8008337cb70ea0556472854abf46ca1ebAntony Sargent            // it differs from what we had saved before.
6520155af8008337cb70ea0556472854abf46ca1ebAntony Sargent            int previousSupport = getSupportsOptionalCodecs(device);
6620155af8008337cb70ea0556472854abf46ca1ebAntony Sargent            boolean supportsOptional = false;
6720155af8008337cb70ea0556472854abf46ca1ebAntony Sargent            for (BluetoothCodecConfig config :
6820155af8008337cb70ea0556472854abf46ca1ebAntony Sargent                    mStateMachine.getCodecStatus().getCodecsSelectableCapabilities()) {
6920155af8008337cb70ea0556472854abf46ca1ebAntony Sargent                if (!config.isMandatoryCodec()) {
7020155af8008337cb70ea0556472854abf46ca1ebAntony Sargent                    supportsOptional = true;
7120155af8008337cb70ea0556472854abf46ca1ebAntony Sargent                    break;
7220155af8008337cb70ea0556472854abf46ca1ebAntony Sargent                }
7320155af8008337cb70ea0556472854abf46ca1ebAntony Sargent            }
7420155af8008337cb70ea0556472854abf46ca1ebAntony Sargent            if (previousSupport == BluetoothA2dp.OPTIONAL_CODECS_SUPPORT_UNKNOWN
7520155af8008337cb70ea0556472854abf46ca1ebAntony Sargent                    || supportsOptional
7620155af8008337cb70ea0556472854abf46ca1ebAntony Sargent                            != (previousSupport == BluetoothA2dp.OPTIONAL_CODECS_SUPPORTED)) {
7720155af8008337cb70ea0556472854abf46ca1ebAntony Sargent                setSupportsOptionalCodecs(device, supportsOptional);
7820155af8008337cb70ea0556472854abf46ca1ebAntony Sargent            }
7920155af8008337cb70ea0556472854abf46ca1ebAntony Sargent            if (supportsOptional) {
8020155af8008337cb70ea0556472854abf46ca1ebAntony Sargent                int enabled = getOptionalCodecsEnabled(device);
8120155af8008337cb70ea0556472854abf46ca1ebAntony Sargent                if (enabled == BluetoothA2dp.OPTIONAL_CODECS_PREF_ENABLED) {
8220155af8008337cb70ea0556472854abf46ca1ebAntony Sargent                    enableOptionalCodecs();
8320155af8008337cb70ea0556472854abf46ca1ebAntony Sargent                } else if (enabled == BluetoothA2dp.OPTIONAL_CODECS_PREF_DISABLED) {
8420155af8008337cb70ea0556472854abf46ca1ebAntony Sargent                    disableOptionalCodecs();
8520155af8008337cb70ea0556472854abf46ca1ebAntony Sargent                }
8620155af8008337cb70ea0556472854abf46ca1ebAntony Sargent            }
8720155af8008337cb70ea0556472854abf46ca1ebAntony Sargent        }
8820155af8008337cb70ea0556472854abf46ca1ebAntony Sargent    };
8920155af8008337cb70ea0556472854abf46ca1ebAntony Sargent
904f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta    private static A2dpService sAd2dpService;
91e316dfc9b3f648ad3d7b2691927758ea885043c0Anubhav Gupta    static final ParcelUuid[] A2DP_SOURCE_UUID = {
92e316dfc9b3f648ad3d7b2691927758ea885043c0Anubhav Gupta        BluetoothUuid.AudioSource
93e316dfc9b3f648ad3d7b2691927758ea885043c0Anubhav Gupta    };
94e316dfc9b3f648ad3d7b2691927758ea885043c0Anubhav Gupta    static final ParcelUuid[] A2DP_SOURCE_SINK_UUIDS = {
95e316dfc9b3f648ad3d7b2691927758ea885043c0Anubhav Gupta        BluetoothUuid.AudioSource,
96e316dfc9b3f648ad3d7b2691927758ea885043c0Anubhav Gupta        BluetoothUuid.AudioSink
97e316dfc9b3f648ad3d7b2691927758ea885043c0Anubhav Gupta    };
986c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
9974ae04c73312403e89db0f8e9bd9601d403b4783fredc    protected String getName() {
10074ae04c73312403e89db0f8e9bd9601d403b4783fredc        return TAG;
10174ae04c73312403e89db0f8e9bd9601d403b4783fredc    }
10274ae04c73312403e89db0f8e9bd9601d403b4783fredc
10374ae04c73312403e89db0f8e9bd9601d403b4783fredc    protected IProfileServiceBinder initBinder() {
10474ae04c73312403e89db0f8e9bd9601d403b4783fredc        return new BluetoothA2dpBinder(this);
10574ae04c73312403e89db0f8e9bd9601d403b4783fredc    }
1066c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
107b5cc776c9353a203cdde97e62b25f05d9633d14cfredc    protected boolean start() {
108c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        mAvrcp = Avrcp.make(this);
109188f205b5f093850d4cc627917a21204be36c56aZhihai Xu        mStateMachine = A2dpStateMachine.make(this, this);
1104f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta        setA2dpService(this);
11120155af8008337cb70ea0556472854abf46ca1ebAntony Sargent        IntentFilter filter = new IntentFilter();
11220155af8008337cb70ea0556472854abf46ca1ebAntony Sargent        filter.addAction(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED);
11320155af8008337cb70ea0556472854abf46ca1ebAntony Sargent        registerReceiver(mConnectionStateChangedReceiver, filter);
114b5cc776c9353a203cdde97e62b25f05d9633d14cfredc        return true;
1156654f5c903de510a70f9e72cd5ad7837b615d93ffredc    }
1166654f5c903de510a70f9e72cd5ad7837b615d93ffredc
117b5cc776c9353a203cdde97e62b25f05d9633d14cfredc    protected boolean stop() {
118ff833ce646e50c3593a313cd6a0be53577e41112Thomas Lehaux        if (mStateMachine != null) {
119ff833ce646e50c3593a313cd6a0be53577e41112Thomas Lehaux            mStateMachine.doQuit();
120ff833ce646e50c3593a313cd6a0be53577e41112Thomas Lehaux        }
1212609a11670563837625f7dde2192deaba7417e46Andre Eisenbach        if (mAvrcp != null) {
1222609a11670563837625f7dde2192deaba7417e46Andre Eisenbach            mAvrcp.doQuit();
1232609a11670563837625f7dde2192deaba7417e46Andre Eisenbach        }
12474ae04c73312403e89db0f8e9bd9601d403b4783fredc        return true;
12574ae04c73312403e89db0f8e9bd9601d403b4783fredc    }
12674ae04c73312403e89db0f8e9bd9601d403b4783fredc
12774ae04c73312403e89db0f8e9bd9601d403b4783fredc    protected boolean cleanup() {
12820155af8008337cb70ea0556472854abf46ca1ebAntony Sargent        unregisterReceiver(mConnectionStateChangedReceiver);
1296654f5c903de510a70f9e72cd5ad7837b615d93ffredc        if (mStateMachine!= null) {
1306654f5c903de510a70f9e72cd5ad7837b615d93ffredc            mStateMachine.cleanup();
1316654f5c903de510a70f9e72cd5ad7837b615d93ffredc        }
132c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        if (mAvrcp != null) {
133c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            mAvrcp.cleanup();
134c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            mAvrcp = null;
135c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        }
1364f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta        clearA2dpService();
137b5cc776c9353a203cdde97e62b25f05d9633d14cfredc        return true;
138b5cc776c9353a203cdde97e62b25f05d9633d14cfredc    }
1396654f5c903de510a70f9e72cd5ad7837b615d93ffredc
14074ae04c73312403e89db0f8e9bd9601d403b4783fredc    //API Methods
1414f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta
1424f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta    public static synchronized A2dpService getA2dpService(){
1434f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta        if (sAd2dpService != null && sAd2dpService.isAvailable()) {
1444f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta            if (DBG) Log.d(TAG, "getA2DPService(): returning " + sAd2dpService);
1454f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta            return sAd2dpService;
1464f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta        }
1474f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta        if (DBG)  {
1484f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta            if (sAd2dpService == null) {
1494f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta                Log.d(TAG, "getA2dpService(): service is NULL");
1504f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta            } else if (!(sAd2dpService.isAvailable())) {
1514f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta                Log.d(TAG,"getA2dpService(): service is not available");
1524f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta            }
1534f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta        }
1544f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta        return null;
1554f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta    }
1564f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta
1574f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta    private static synchronized void setA2dpService(A2dpService instance) {
1584f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta        if (instance != null && instance.isAvailable()) {
1594f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta            if (DBG) Log.d(TAG, "setA2dpService(): set to: " + sAd2dpService);
1604f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta            sAd2dpService = instance;
1614f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta        } else {
1624f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta            if (DBG)  {
1634f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta                if (sAd2dpService == null) {
1644f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta                    Log.d(TAG, "setA2dpService(): service not available");
1654f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta                } else if (!sAd2dpService.isAvailable()) {
1664f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta                    Log.d(TAG,"setA2dpService(): service is cleaning up");
1674f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta                }
1684f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta            }
1694f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta        }
1704f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta    }
1714f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta
1724f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta    private static synchronized void clearA2dpService() {
1734f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta        sAd2dpService = null;
1744f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta    }
1754f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta
1764f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta    public boolean connect(BluetoothDevice device) {
17774ae04c73312403e89db0f8e9bd9601d403b4783fredc        enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
17874ae04c73312403e89db0f8e9bd9601d403b4783fredc                                       "Need BLUETOOTH ADMIN permission");
17974ae04c73312403e89db0f8e9bd9601d403b4783fredc
18074ae04c73312403e89db0f8e9bd9601d403b4783fredc        if (getPriority(device) == BluetoothProfile.PRIORITY_OFF) {
18174ae04c73312403e89db0f8e9bd9601d403b4783fredc            return false;
18274ae04c73312403e89db0f8e9bd9601d403b4783fredc        }
183e316dfc9b3f648ad3d7b2691927758ea885043c0Anubhav Gupta        ParcelUuid[] featureUuids = device.getUuids();
184e316dfc9b3f648ad3d7b2691927758ea885043c0Anubhav Gupta        if ((BluetoothUuid.containsAnyUuid(featureUuids, A2DP_SOURCE_UUID)) &&
185e316dfc9b3f648ad3d7b2691927758ea885043c0Anubhav Gupta            !(BluetoothUuid.containsAllUuids(featureUuids ,A2DP_SOURCE_SINK_UUIDS))) {
186e316dfc9b3f648ad3d7b2691927758ea885043c0Anubhav Gupta            Log.e(TAG,"Remote does not have A2dp Sink UUID");
187e316dfc9b3f648ad3d7b2691927758ea885043c0Anubhav Gupta            return false;
188e316dfc9b3f648ad3d7b2691927758ea885043c0Anubhav Gupta        }
18974ae04c73312403e89db0f8e9bd9601d403b4783fredc
19074ae04c73312403e89db0f8e9bd9601d403b4783fredc        int connectionState = mStateMachine.getConnectionState(device);
19174ae04c73312403e89db0f8e9bd9601d403b4783fredc        if (connectionState == BluetoothProfile.STATE_CONNECTED ||
19274ae04c73312403e89db0f8e9bd9601d403b4783fredc            connectionState == BluetoothProfile.STATE_CONNECTING) {
19374ae04c73312403e89db0f8e9bd9601d403b4783fredc            return false;
19474ae04c73312403e89db0f8e9bd9601d403b4783fredc        }
19574ae04c73312403e89db0f8e9bd9601d403b4783fredc
19674ae04c73312403e89db0f8e9bd9601d403b4783fredc        mStateMachine.sendMessage(A2dpStateMachine.CONNECT, device);
19774ae04c73312403e89db0f8e9bd9601d403b4783fredc        return true;
198b5cc776c9353a203cdde97e62b25f05d9633d14cfredc    }
199b5cc776c9353a203cdde97e62b25f05d9633d14cfredc
20074ae04c73312403e89db0f8e9bd9601d403b4783fredc    boolean disconnect(BluetoothDevice device) {
20174ae04c73312403e89db0f8e9bd9601d403b4783fredc        enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
20274ae04c73312403e89db0f8e9bd9601d403b4783fredc                                       "Need BLUETOOTH ADMIN permission");
20374ae04c73312403e89db0f8e9bd9601d403b4783fredc        int connectionState = mStateMachine.getConnectionState(device);
20474ae04c73312403e89db0f8e9bd9601d403b4783fredc        if (connectionState != BluetoothProfile.STATE_CONNECTED &&
20574ae04c73312403e89db0f8e9bd9601d403b4783fredc            connectionState != BluetoothProfile.STATE_CONNECTING) {
20674ae04c73312403e89db0f8e9bd9601d403b4783fredc            return false;
20774ae04c73312403e89db0f8e9bd9601d403b4783fredc        }
20874ae04c73312403e89db0f8e9bd9601d403b4783fredc
20974ae04c73312403e89db0f8e9bd9601d403b4783fredc        mStateMachine.sendMessage(A2dpStateMachine.DISCONNECT, device);
21074ae04c73312403e89db0f8e9bd9601d403b4783fredc        return true;
2116c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie    }
2126c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
2134f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta    public List<BluetoothDevice> getConnectedDevices() {
21474ae04c73312403e89db0f8e9bd9601d403b4783fredc        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
21574ae04c73312403e89db0f8e9bd9601d403b4783fredc        return mStateMachine.getConnectedDevices();
21674ae04c73312403e89db0f8e9bd9601d403b4783fredc    }
2176c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
21874ae04c73312403e89db0f8e9bd9601d403b4783fredc    List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
21974ae04c73312403e89db0f8e9bd9601d403b4783fredc        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
22074ae04c73312403e89db0f8e9bd9601d403b4783fredc        return mStateMachine.getDevicesMatchingConnectionStates(states);
22174ae04c73312403e89db0f8e9bd9601d403b4783fredc    }
2226c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
22386c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal    public int getConnectionState(BluetoothDevice device) {
22474ae04c73312403e89db0f8e9bd9601d403b4783fredc        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
22574ae04c73312403e89db0f8e9bd9601d403b4783fredc        return mStateMachine.getConnectionState(device);
22674ae04c73312403e89db0f8e9bd9601d403b4783fredc    }
22774ae04c73312403e89db0f8e9bd9601d403b4783fredc
2284f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta    public boolean setPriority(BluetoothDevice device, int priority) {
22974ae04c73312403e89db0f8e9bd9601d403b4783fredc        enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
23074ae04c73312403e89db0f8e9bd9601d403b4783fredc                                       "Need BLUETOOTH_ADMIN permission");
231c7ead6d5827f3832b9210e92fab7597142059852Jeff Sharkey        Settings.Global.putInt(getContentResolver(),
232c7ead6d5827f3832b9210e92fab7597142059852Jeff Sharkey            Settings.Global.getBluetoothA2dpSinkPriorityKey(device.getAddress()),
23374ae04c73312403e89db0f8e9bd9601d403b4783fredc            priority);
23474ae04c73312403e89db0f8e9bd9601d403b4783fredc        if (DBG) Log.d(TAG,"Saved priority " + device + " = " + priority);
23574ae04c73312403e89db0f8e9bd9601d403b4783fredc        return true;
23674ae04c73312403e89db0f8e9bd9601d403b4783fredc    }
2376c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
2384f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta    public int getPriority(BluetoothDevice device) {
23974ae04c73312403e89db0f8e9bd9601d403b4783fredc        enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
24074ae04c73312403e89db0f8e9bd9601d403b4783fredc                                       "Need BLUETOOTH_ADMIN permission");
241c7ead6d5827f3832b9210e92fab7597142059852Jeff Sharkey        int priority = Settings.Global.getInt(getContentResolver(),
242c7ead6d5827f3832b9210e92fab7597142059852Jeff Sharkey            Settings.Global.getBluetoothA2dpSinkPriorityKey(device.getAddress()),
24374ae04c73312403e89db0f8e9bd9601d403b4783fredc            BluetoothProfile.PRIORITY_UNDEFINED);
24474ae04c73312403e89db0f8e9bd9601d403b4783fredc        return priority;
24574ae04c73312403e89db0f8e9bd9601d403b4783fredc    }
24674ae04c73312403e89db0f8e9bd9601d403b4783fredc
24717675906064bb72fdcca75baa56cdf8bb8968d01John Du    /* Absolute volume implementation */
24817675906064bb72fdcca75baa56cdf8bb8968d01John Du    public boolean isAvrcpAbsoluteVolumeSupported() {
24917675906064bb72fdcca75baa56cdf8bb8968d01John Du        return mAvrcp.isAbsoluteVolumeSupported();
25017675906064bb72fdcca75baa56cdf8bb8968d01John Du    }
25117675906064bb72fdcca75baa56cdf8bb8968d01John Du
25217675906064bb72fdcca75baa56cdf8bb8968d01John Du    public void adjustAvrcpAbsoluteVolume(int direction) {
25317675906064bb72fdcca75baa56cdf8bb8968d01John Du        mAvrcp.adjustVolume(direction);
25417675906064bb72fdcca75baa56cdf8bb8968d01John Du    }
25517675906064bb72fdcca75baa56cdf8bb8968d01John Du
25617675906064bb72fdcca75baa56cdf8bb8968d01John Du    public void setAvrcpAbsoluteVolume(int volume) {
25717675906064bb72fdcca75baa56cdf8bb8968d01John Du        mAvrcp.setAbsoluteVolume(volume);
25817675906064bb72fdcca75baa56cdf8bb8968d01John Du    }
25917675906064bb72fdcca75baa56cdf8bb8968d01John Du
260188f205b5f093850d4cc627917a21204be36c56aZhihai Xu    public void setAvrcpAudioState(int state) {
261188f205b5f093850d4cc627917a21204be36c56aZhihai Xu        mAvrcp.setA2dpAudioState(state);
262188f205b5f093850d4cc627917a21204be36c56aZhihai Xu    }
263188f205b5f093850d4cc627917a21204be36c56aZhihai Xu
26411798b011c962b602217b479130d413f3b30f19aLiejun Tao    public void resetAvrcpBlacklist(BluetoothDevice device) {
265ff495eca3027c9b3aa7d8ef4e9cfd2cde3bbb664Pavlin Radoslavov        if (mAvrcp != null) {
266ff495eca3027c9b3aa7d8ef4e9cfd2cde3bbb664Pavlin Radoslavov            mAvrcp.resetBlackList(device.getAddress());
267ff495eca3027c9b3aa7d8ef4e9cfd2cde3bbb664Pavlin Radoslavov        }
26811798b011c962b602217b479130d413f3b30f19aLiejun Tao    }
26911798b011c962b602217b479130d413f3b30f19aLiejun Tao
27074ae04c73312403e89db0f8e9bd9601d403b4783fredc    synchronized boolean isA2dpPlaying(BluetoothDevice device) {
27174ae04c73312403e89db0f8e9bd9601d403b4783fredc        enforceCallingOrSelfPermission(BLUETOOTH_PERM,
27274ae04c73312403e89db0f8e9bd9601d403b4783fredc                                       "Need BLUETOOTH permission");
27374ae04c73312403e89db0f8e9bd9601d403b4783fredc        if (DBG) Log.d(TAG, "isA2dpPlaying(" + device + ")");
27474ae04c73312403e89db0f8e9bd9601d403b4783fredc        return mStateMachine.isPlaying(device);
27574ae04c73312403e89db0f8e9bd9601d403b4783fredc    }
27674ae04c73312403e89db0f8e9bd9601d403b4783fredc
27708d3925d3d72837e6f86c9e0beaed5f7b813ea37Pavlin Radoslavov    public BluetoothCodecStatus getCodecStatus() {
27833b6b7d2b08dcd7ced1809e2ac653c5e8c2514afPavlin Radoslavov        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
27908d3925d3d72837e6f86c9e0beaed5f7b813ea37Pavlin Radoslavov        if (DBG) Log.d(TAG, "getCodecStatus()");
28008d3925d3d72837e6f86c9e0beaed5f7b813ea37Pavlin Radoslavov        return mStateMachine.getCodecStatus();
28133b6b7d2b08dcd7ced1809e2ac653c5e8c2514afPavlin Radoslavov    }
28233b6b7d2b08dcd7ced1809e2ac653c5e8c2514afPavlin Radoslavov
28333b6b7d2b08dcd7ced1809e2ac653c5e8c2514afPavlin Radoslavov    public void setCodecConfigPreference(BluetoothCodecConfig codecConfig) {
28433b6b7d2b08dcd7ced1809e2ac653c5e8c2514afPavlin Radoslavov        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
28533b6b7d2b08dcd7ced1809e2ac653c5e8c2514afPavlin Radoslavov        if (DBG) Log.d(TAG, "setCodecConfigPreference(): " + Objects.toString(codecConfig));
28633b6b7d2b08dcd7ced1809e2ac653c5e8c2514afPavlin Radoslavov        mStateMachine.setCodecConfigPreference(codecConfig);
28733b6b7d2b08dcd7ced1809e2ac653c5e8c2514afPavlin Radoslavov    }
28833b6b7d2b08dcd7ced1809e2ac653c5e8c2514afPavlin Radoslavov
2890e1abf2276c4bc7e940624da89113b23e526be7aPavlin Radoslavov    public void enableOptionalCodecs() {
2900e1abf2276c4bc7e940624da89113b23e526be7aPavlin Radoslavov        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
2910e1abf2276c4bc7e940624da89113b23e526be7aPavlin Radoslavov        if (DBG) Log.d(TAG, "enableOptionalCodecs()");
2920e1abf2276c4bc7e940624da89113b23e526be7aPavlin Radoslavov        mStateMachine.enableOptionalCodecs();
2930e1abf2276c4bc7e940624da89113b23e526be7aPavlin Radoslavov    }
2940e1abf2276c4bc7e940624da89113b23e526be7aPavlin Radoslavov
2950e1abf2276c4bc7e940624da89113b23e526be7aPavlin Radoslavov    public void disableOptionalCodecs() {
2960e1abf2276c4bc7e940624da89113b23e526be7aPavlin Radoslavov        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
2970e1abf2276c4bc7e940624da89113b23e526be7aPavlin Radoslavov        if (DBG) Log.d(TAG, "disableOptionalCodecs()");
2980e1abf2276c4bc7e940624da89113b23e526be7aPavlin Radoslavov        mStateMachine.disableOptionalCodecs();
2990e1abf2276c4bc7e940624da89113b23e526be7aPavlin Radoslavov    }
3000e1abf2276c4bc7e940624da89113b23e526be7aPavlin Radoslavov
30120155af8008337cb70ea0556472854abf46ca1ebAntony Sargent    public int getSupportsOptionalCodecs(BluetoothDevice device) {
30220155af8008337cb70ea0556472854abf46ca1ebAntony Sargent        enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission");
30320155af8008337cb70ea0556472854abf46ca1ebAntony Sargent        int support = Settings.Global.getInt(getContentResolver(),
30420155af8008337cb70ea0556472854abf46ca1ebAntony Sargent                Settings.Global.getBluetoothA2dpSupportsOptionalCodecsKey(device.getAddress()),
30520155af8008337cb70ea0556472854abf46ca1ebAntony Sargent                BluetoothA2dp.OPTIONAL_CODECS_SUPPORT_UNKNOWN);
30620155af8008337cb70ea0556472854abf46ca1ebAntony Sargent        return support;
30720155af8008337cb70ea0556472854abf46ca1ebAntony Sargent    }
30820155af8008337cb70ea0556472854abf46ca1ebAntony Sargent
30920155af8008337cb70ea0556472854abf46ca1ebAntony Sargent    public void setSupportsOptionalCodecs(BluetoothDevice device, boolean doesSupport) {
31020155af8008337cb70ea0556472854abf46ca1ebAntony Sargent        enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission");
31120155af8008337cb70ea0556472854abf46ca1ebAntony Sargent        int value = doesSupport ? BluetoothA2dp.OPTIONAL_CODECS_SUPPORTED
31220155af8008337cb70ea0556472854abf46ca1ebAntony Sargent                                : BluetoothA2dp.OPTIONAL_CODECS_NOT_SUPPORTED;
31320155af8008337cb70ea0556472854abf46ca1ebAntony Sargent        Settings.Global.putInt(getContentResolver(),
31420155af8008337cb70ea0556472854abf46ca1ebAntony Sargent                Settings.Global.getBluetoothA2dpSupportsOptionalCodecsKey(device.getAddress()),
31520155af8008337cb70ea0556472854abf46ca1ebAntony Sargent                value);
31620155af8008337cb70ea0556472854abf46ca1ebAntony Sargent    }
31720155af8008337cb70ea0556472854abf46ca1ebAntony Sargent
31820155af8008337cb70ea0556472854abf46ca1ebAntony Sargent    public int getOptionalCodecsEnabled(BluetoothDevice device) {
31920155af8008337cb70ea0556472854abf46ca1ebAntony Sargent        enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission");
32020155af8008337cb70ea0556472854abf46ca1ebAntony Sargent        return Settings.Global.getInt(getContentResolver(),
32120155af8008337cb70ea0556472854abf46ca1ebAntony Sargent                Settings.Global.getBluetoothA2dpOptionalCodecsEnabledKey(device.getAddress()),
32220155af8008337cb70ea0556472854abf46ca1ebAntony Sargent                BluetoothA2dp.OPTIONAL_CODECS_PREF_UNKNOWN);
32320155af8008337cb70ea0556472854abf46ca1ebAntony Sargent    }
32420155af8008337cb70ea0556472854abf46ca1ebAntony Sargent
32520155af8008337cb70ea0556472854abf46ca1ebAntony Sargent    public void setOptionalCodecsEnabled(BluetoothDevice device, int value) {
32620155af8008337cb70ea0556472854abf46ca1ebAntony Sargent        enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission");
32720155af8008337cb70ea0556472854abf46ca1ebAntony Sargent        if (value != BluetoothA2dp.OPTIONAL_CODECS_PREF_UNKNOWN
32820155af8008337cb70ea0556472854abf46ca1ebAntony Sargent                && value != BluetoothA2dp.OPTIONAL_CODECS_PREF_DISABLED
32920155af8008337cb70ea0556472854abf46ca1ebAntony Sargent                && value != BluetoothA2dp.OPTIONAL_CODECS_PREF_ENABLED) {
33020155af8008337cb70ea0556472854abf46ca1ebAntony Sargent            Log.w(TAG, "Unexpected value passed to setOptionalCodecsEnabled:" + value);
33120155af8008337cb70ea0556472854abf46ca1ebAntony Sargent            return;
33220155af8008337cb70ea0556472854abf46ca1ebAntony Sargent        }
33320155af8008337cb70ea0556472854abf46ca1ebAntony Sargent        Settings.Global.putInt(getContentResolver(),
33420155af8008337cb70ea0556472854abf46ca1ebAntony Sargent                Settings.Global.getBluetoothA2dpOptionalCodecsEnabledKey(device.getAddress()),
33520155af8008337cb70ea0556472854abf46ca1ebAntony Sargent                value);
33620155af8008337cb70ea0556472854abf46ca1ebAntony Sargent    }
33720155af8008337cb70ea0556472854abf46ca1ebAntony Sargent
33874ae04c73312403e89db0f8e9bd9601d403b4783fredc    //Binder object: Must be static class or memory leak may occur
33974ae04c73312403e89db0f8e9bd9601d403b4783fredc    private static class BluetoothA2dpBinder extends IBluetoothA2dp.Stub
34074ae04c73312403e89db0f8e9bd9601d403b4783fredc        implements IProfileServiceBinder {
34174ae04c73312403e89db0f8e9bd9601d403b4783fredc        private A2dpService mService;
34274ae04c73312403e89db0f8e9bd9601d403b4783fredc
34374ae04c73312403e89db0f8e9bd9601d403b4783fredc        private A2dpService getService() {
34437510150ee738ccfa5913f7120e28f25ae7768dfZhihai Xu            if (!Utils.checkCaller()) {
34537510150ee738ccfa5913f7120e28f25ae7768dfZhihai Xu                Log.w(TAG,"A2dp call not allowed for non-active user");
34637510150ee738ccfa5913f7120e28f25ae7768dfZhihai Xu                return null;
34737510150ee738ccfa5913f7120e28f25ae7768dfZhihai Xu            }
34837510150ee738ccfa5913f7120e28f25ae7768dfZhihai Xu
34937510150ee738ccfa5913f7120e28f25ae7768dfZhihai Xu            if (mService != null && mService.isAvailable()) {
35074ae04c73312403e89db0f8e9bd9601d403b4783fredc                return mService;
3516c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            }
35274ae04c73312403e89db0f8e9bd9601d403b4783fredc            return null;
35374ae04c73312403e89db0f8e9bd9601d403b4783fredc        }
3546c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
35574ae04c73312403e89db0f8e9bd9601d403b4783fredc        BluetoothA2dpBinder(A2dpService svc) {
35674ae04c73312403e89db0f8e9bd9601d403b4783fredc            mService = svc;
35774ae04c73312403e89db0f8e9bd9601d403b4783fredc        }
35874ae04c73312403e89db0f8e9bd9601d403b4783fredc
35974ae04c73312403e89db0f8e9bd9601d403b4783fredc        public boolean cleanup()  {
36074ae04c73312403e89db0f8e9bd9601d403b4783fredc            mService = null;
3616c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            return true;
3626c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        }
3636c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
36474ae04c73312403e89db0f8e9bd9601d403b4783fredc        public boolean connect(BluetoothDevice device) {
36574ae04c73312403e89db0f8e9bd9601d403b4783fredc            A2dpService service = getService();
36674ae04c73312403e89db0f8e9bd9601d403b4783fredc            if (service == null) return false;
36774ae04c73312403e89db0f8e9bd9601d403b4783fredc            return service.connect(device);
36874ae04c73312403e89db0f8e9bd9601d403b4783fredc        }
3696c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
37074ae04c73312403e89db0f8e9bd9601d403b4783fredc        public boolean disconnect(BluetoothDevice device) {
37174ae04c73312403e89db0f8e9bd9601d403b4783fredc            A2dpService service = getService();
37274ae04c73312403e89db0f8e9bd9601d403b4783fredc            if (service == null) return false;
37374ae04c73312403e89db0f8e9bd9601d403b4783fredc            return service.disconnect(device);
3746c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        }
3756c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
3766c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        public List<BluetoothDevice> getConnectedDevices() {
37774ae04c73312403e89db0f8e9bd9601d403b4783fredc            A2dpService service = getService();
37874ae04c73312403e89db0f8e9bd9601d403b4783fredc            if (service == null) return new ArrayList<BluetoothDevice>(0);
37974ae04c73312403e89db0f8e9bd9601d403b4783fredc            return service.getConnectedDevices();
3806c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        }
3816c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
3826c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
38374ae04c73312403e89db0f8e9bd9601d403b4783fredc            A2dpService service = getService();
38474ae04c73312403e89db0f8e9bd9601d403b4783fredc            if (service == null) return new ArrayList<BluetoothDevice>(0);
38574ae04c73312403e89db0f8e9bd9601d403b4783fredc            return service.getDevicesMatchingConnectionStates(states);
3866c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        }
3876c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
3886c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        public int getConnectionState(BluetoothDevice device) {
38974ae04c73312403e89db0f8e9bd9601d403b4783fredc            A2dpService service = getService();
39074ae04c73312403e89db0f8e9bd9601d403b4783fredc            if (service == null) return BluetoothProfile.STATE_DISCONNECTED;
39174ae04c73312403e89db0f8e9bd9601d403b4783fredc            return service.getConnectionState(device);
3926c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        }
3936c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
3946c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        public boolean setPriority(BluetoothDevice device, int priority) {
39574ae04c73312403e89db0f8e9bd9601d403b4783fredc            A2dpService service = getService();
39674ae04c73312403e89db0f8e9bd9601d403b4783fredc            if (service == null) return false;
39774ae04c73312403e89db0f8e9bd9601d403b4783fredc            return service.setPriority(device, priority);
3986c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        }
3996c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
4006c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        public int getPriority(BluetoothDevice device) {
40174ae04c73312403e89db0f8e9bd9601d403b4783fredc            A2dpService service = getService();
40274ae04c73312403e89db0f8e9bd9601d403b4783fredc            if (service == null) return BluetoothProfile.PRIORITY_UNDEFINED;
40374ae04c73312403e89db0f8e9bd9601d403b4783fredc            return service.getPriority(device);
4046c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        }
4056c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
40617675906064bb72fdcca75baa56cdf8bb8968d01John Du        public boolean isAvrcpAbsoluteVolumeSupported() {
40717675906064bb72fdcca75baa56cdf8bb8968d01John Du            A2dpService service = getService();
40817675906064bb72fdcca75baa56cdf8bb8968d01John Du            if (service == null) return false;
40917675906064bb72fdcca75baa56cdf8bb8968d01John Du            return service.isAvrcpAbsoluteVolumeSupported();
41017675906064bb72fdcca75baa56cdf8bb8968d01John Du        }
41117675906064bb72fdcca75baa56cdf8bb8968d01John Du
41217675906064bb72fdcca75baa56cdf8bb8968d01John Du        public void adjustAvrcpAbsoluteVolume(int direction) {
41317675906064bb72fdcca75baa56cdf8bb8968d01John Du            A2dpService service = getService();
41417675906064bb72fdcca75baa56cdf8bb8968d01John Du            if (service == null) return;
41517675906064bb72fdcca75baa56cdf8bb8968d01John Du            service.adjustAvrcpAbsoluteVolume(direction);
41617675906064bb72fdcca75baa56cdf8bb8968d01John Du        }
41717675906064bb72fdcca75baa56cdf8bb8968d01John Du
41817675906064bb72fdcca75baa56cdf8bb8968d01John Du        public void setAvrcpAbsoluteVolume(int volume) {
41917675906064bb72fdcca75baa56cdf8bb8968d01John Du            A2dpService service = getService();
42017675906064bb72fdcca75baa56cdf8bb8968d01John Du            if (service == null) return;
42117675906064bb72fdcca75baa56cdf8bb8968d01John Du            service.setAvrcpAbsoluteVolume(volume);
42217675906064bb72fdcca75baa56cdf8bb8968d01John Du        }
42317675906064bb72fdcca75baa56cdf8bb8968d01John Du
42474ae04c73312403e89db0f8e9bd9601d403b4783fredc        public boolean isA2dpPlaying(BluetoothDevice device) {
42574ae04c73312403e89db0f8e9bd9601d403b4783fredc            A2dpService service = getService();
42674ae04c73312403e89db0f8e9bd9601d403b4783fredc            if (service == null) return false;
42774ae04c73312403e89db0f8e9bd9601d403b4783fredc            return service.isA2dpPlaying(device);
4286c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        }
42933b6b7d2b08dcd7ced1809e2ac653c5e8c2514afPavlin Radoslavov
43008d3925d3d72837e6f86c9e0beaed5f7b813ea37Pavlin Radoslavov        public BluetoothCodecStatus getCodecStatus() {
43133b6b7d2b08dcd7ced1809e2ac653c5e8c2514afPavlin Radoslavov            A2dpService service = getService();
43233b6b7d2b08dcd7ced1809e2ac653c5e8c2514afPavlin Radoslavov            if (service == null) return null;
43308d3925d3d72837e6f86c9e0beaed5f7b813ea37Pavlin Radoslavov            return service.getCodecStatus();
43433b6b7d2b08dcd7ced1809e2ac653c5e8c2514afPavlin Radoslavov        }
43533b6b7d2b08dcd7ced1809e2ac653c5e8c2514afPavlin Radoslavov
43633b6b7d2b08dcd7ced1809e2ac653c5e8c2514afPavlin Radoslavov        public void setCodecConfigPreference(BluetoothCodecConfig codecConfig) {
43733b6b7d2b08dcd7ced1809e2ac653c5e8c2514afPavlin Radoslavov            A2dpService service = getService();
43833b6b7d2b08dcd7ced1809e2ac653c5e8c2514afPavlin Radoslavov            if (service == null) return;
43933b6b7d2b08dcd7ced1809e2ac653c5e8c2514afPavlin Radoslavov            service.setCodecConfigPreference(codecConfig);
44033b6b7d2b08dcd7ced1809e2ac653c5e8c2514afPavlin Radoslavov        }
4410e1abf2276c4bc7e940624da89113b23e526be7aPavlin Radoslavov
4420e1abf2276c4bc7e940624da89113b23e526be7aPavlin Radoslavov        public void enableOptionalCodecs() {
4430e1abf2276c4bc7e940624da89113b23e526be7aPavlin Radoslavov            A2dpService service = getService();
4440e1abf2276c4bc7e940624da89113b23e526be7aPavlin Radoslavov            if (service == null) return;
4450e1abf2276c4bc7e940624da89113b23e526be7aPavlin Radoslavov            service.enableOptionalCodecs();
4460e1abf2276c4bc7e940624da89113b23e526be7aPavlin Radoslavov        }
4470e1abf2276c4bc7e940624da89113b23e526be7aPavlin Radoslavov
4480e1abf2276c4bc7e940624da89113b23e526be7aPavlin Radoslavov        public void disableOptionalCodecs() {
4490e1abf2276c4bc7e940624da89113b23e526be7aPavlin Radoslavov            A2dpService service = getService();
4500e1abf2276c4bc7e940624da89113b23e526be7aPavlin Radoslavov            if (service == null) return;
4510e1abf2276c4bc7e940624da89113b23e526be7aPavlin Radoslavov            service.disableOptionalCodecs();
4520e1abf2276c4bc7e940624da89113b23e526be7aPavlin Radoslavov        }
45320155af8008337cb70ea0556472854abf46ca1ebAntony Sargent
45420155af8008337cb70ea0556472854abf46ca1ebAntony Sargent        public int supportsOptionalCodecs(BluetoothDevice device) {
45520155af8008337cb70ea0556472854abf46ca1ebAntony Sargent            A2dpService service = getService();
45620155af8008337cb70ea0556472854abf46ca1ebAntony Sargent            if (service == null) return BluetoothA2dp.OPTIONAL_CODECS_SUPPORT_UNKNOWN;
45720155af8008337cb70ea0556472854abf46ca1ebAntony Sargent            return service.getSupportsOptionalCodecs(device);
45820155af8008337cb70ea0556472854abf46ca1ebAntony Sargent        }
45920155af8008337cb70ea0556472854abf46ca1ebAntony Sargent
46020155af8008337cb70ea0556472854abf46ca1ebAntony Sargent        public int getOptionalCodecsEnabled(BluetoothDevice device) {
46120155af8008337cb70ea0556472854abf46ca1ebAntony Sargent            A2dpService service = getService();
46220155af8008337cb70ea0556472854abf46ca1ebAntony Sargent            if (service == null) return BluetoothA2dp.OPTIONAL_CODECS_PREF_UNKNOWN;
46320155af8008337cb70ea0556472854abf46ca1ebAntony Sargent            return service.getOptionalCodecsEnabled(device);
46420155af8008337cb70ea0556472854abf46ca1ebAntony Sargent        }
46520155af8008337cb70ea0556472854abf46ca1ebAntony Sargent
46620155af8008337cb70ea0556472854abf46ca1ebAntony Sargent        public void setOptionalCodecsEnabled(BluetoothDevice device, int value) {
46720155af8008337cb70ea0556472854abf46ca1ebAntony Sargent            A2dpService service = getService();
46820155af8008337cb70ea0556472854abf46ca1ebAntony Sargent            if (service == null) return;
46920155af8008337cb70ea0556472854abf46ca1ebAntony Sargent            service.setOptionalCodecsEnabled(device, value);
47020155af8008337cb70ea0556472854abf46ca1ebAntony Sargent        }
4716c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie    };
472838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood
473838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood    @Override
474838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood    public void dump(StringBuilder sb) {
475838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood        super.dump(sb);
476838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood        if (mStateMachine != null) {
477838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood            mStateMachine.dump(sb);
478838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood        }
479838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood        if (mAvrcp != null) {
480838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood            mAvrcp.dump(sb);
481838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood        }
482838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood    }
4836c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie}
484