A2dpService.java revision 17675906064bb72fdcca75baa56cdf8bb8968d01
1/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.bluetooth.a2dp;
18
19import android.bluetooth.BluetoothDevice;
20import android.bluetooth.BluetoothProfile;
21import android.bluetooth.IBluetoothA2dp;
22import android.content.Context;
23import android.content.Intent;
24import android.provider.Settings;
25import android.util.Log;
26import com.android.bluetooth.btservice.ProfileService;
27import com.android.bluetooth.Utils;
28import java.util.ArrayList;
29import java.util.Iterator;
30import java.util.List;
31import java.util.Map;
32
33/**
34 * Provides Bluetooth A2DP profile, as a service in the Bluetooth application.
35 * @hide
36 */
37public class A2dpService extends ProfileService {
38    private static final boolean DBG = false;
39    private static final String TAG="A2dpService";
40
41    private A2dpStateMachine mStateMachine;
42    private Avrcp mAvrcp;
43    private static A2dpService sAd2dpService;
44
45    protected String getName() {
46        return TAG;
47    }
48
49    protected IProfileServiceBinder initBinder() {
50        return new BluetoothA2dpBinder(this);
51    }
52
53    protected boolean start() {
54        mStateMachine = A2dpStateMachine.make(this, this);
55        mAvrcp = Avrcp.make(this);
56        setA2dpService(this);
57        return true;
58    }
59
60    protected boolean stop() {
61        mStateMachine.doQuit();
62        mAvrcp.doQuit();
63        return true;
64    }
65
66    protected boolean cleanup() {
67        if (mStateMachine!= null) {
68            mStateMachine.cleanup();
69        }
70        if (mAvrcp != null) {
71            mAvrcp.cleanup();
72            mAvrcp = null;
73        }
74        clearA2dpService();
75        return true;
76    }
77
78    //API Methods
79
80    public static synchronized A2dpService getA2dpService(){
81        if (sAd2dpService != null && sAd2dpService.isAvailable()) {
82            if (DBG) Log.d(TAG, "getA2DPService(): returning " + sAd2dpService);
83            return sAd2dpService;
84        }
85        if (DBG)  {
86            if (sAd2dpService == null) {
87                Log.d(TAG, "getA2dpService(): service is NULL");
88            } else if (!(sAd2dpService.isAvailable())) {
89                Log.d(TAG,"getA2dpService(): service is not available");
90            }
91        }
92        return null;
93    }
94
95    private static synchronized void setA2dpService(A2dpService instance) {
96        if (instance != null && instance.isAvailable()) {
97            if (DBG) Log.d(TAG, "setA2dpService(): set to: " + sAd2dpService);
98            sAd2dpService = instance;
99        } else {
100            if (DBG)  {
101                if (sAd2dpService == null) {
102                    Log.d(TAG, "setA2dpService(): service not available");
103                } else if (!sAd2dpService.isAvailable()) {
104                    Log.d(TAG,"setA2dpService(): service is cleaning up");
105                }
106            }
107        }
108    }
109
110    private static synchronized void clearA2dpService() {
111        sAd2dpService = null;
112    }
113
114    public boolean connect(BluetoothDevice device) {
115        enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
116                                       "Need BLUETOOTH ADMIN permission");
117
118        if (getPriority(device) == BluetoothProfile.PRIORITY_OFF) {
119            return false;
120        }
121
122        int connectionState = mStateMachine.getConnectionState(device);
123        if (connectionState == BluetoothProfile.STATE_CONNECTED ||
124            connectionState == BluetoothProfile.STATE_CONNECTING) {
125            return false;
126        }
127
128        mStateMachine.sendMessage(A2dpStateMachine.CONNECT, device);
129        return true;
130    }
131
132    boolean disconnect(BluetoothDevice device) {
133        enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
134                                       "Need BLUETOOTH ADMIN permission");
135        int connectionState = mStateMachine.getConnectionState(device);
136        if (connectionState != BluetoothProfile.STATE_CONNECTED &&
137            connectionState != BluetoothProfile.STATE_CONNECTING) {
138            return false;
139        }
140
141        mStateMachine.sendMessage(A2dpStateMachine.DISCONNECT, device);
142        return true;
143    }
144
145    public List<BluetoothDevice> getConnectedDevices() {
146        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
147        return mStateMachine.getConnectedDevices();
148    }
149
150    List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
151        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
152        return mStateMachine.getDevicesMatchingConnectionStates(states);
153    }
154
155    int getConnectionState(BluetoothDevice device) {
156        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
157        return mStateMachine.getConnectionState(device);
158    }
159
160    public boolean setPriority(BluetoothDevice device, int priority) {
161        enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
162                                       "Need BLUETOOTH_ADMIN permission");
163        Settings.Global.putInt(getContentResolver(),
164            Settings.Global.getBluetoothA2dpSinkPriorityKey(device.getAddress()),
165            priority);
166        if (DBG) Log.d(TAG,"Saved priority " + device + " = " + priority);
167        return true;
168    }
169
170    public int getPriority(BluetoothDevice device) {
171        enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
172                                       "Need BLUETOOTH_ADMIN permission");
173        int priority = Settings.Global.getInt(getContentResolver(),
174            Settings.Global.getBluetoothA2dpSinkPriorityKey(device.getAddress()),
175            BluetoothProfile.PRIORITY_UNDEFINED);
176        return priority;
177    }
178
179    /* Absolute volume implementation */
180    public boolean isAvrcpAbsoluteVolumeSupported() {
181        return mAvrcp.isAbsoluteVolumeSupported();
182    }
183
184    public void adjustAvrcpAbsoluteVolume(int direction) {
185        mAvrcp.adjustVolume(direction);
186    }
187
188    public void setAvrcpAbsoluteVolume(int volume) {
189        mAvrcp.setAbsoluteVolume(volume);
190    }
191
192    synchronized boolean isA2dpPlaying(BluetoothDevice device) {
193        enforceCallingOrSelfPermission(BLUETOOTH_PERM,
194                                       "Need BLUETOOTH permission");
195        if (DBG) Log.d(TAG, "isA2dpPlaying(" + device + ")");
196        return mStateMachine.isPlaying(device);
197    }
198
199    //Binder object: Must be static class or memory leak may occur
200    private static class BluetoothA2dpBinder extends IBluetoothA2dp.Stub
201        implements IProfileServiceBinder {
202        private A2dpService mService;
203
204        private A2dpService getService() {
205            if (!Utils.checkCaller()) {
206                Log.w(TAG,"A2dp call not allowed for non-active user");
207                return null;
208            }
209
210            if (mService != null && mService.isAvailable()) {
211                return mService;
212            }
213            return null;
214        }
215
216        BluetoothA2dpBinder(A2dpService svc) {
217            mService = svc;
218        }
219
220        public boolean cleanup()  {
221            mService = null;
222            return true;
223        }
224
225        public boolean connect(BluetoothDevice device) {
226            A2dpService service = getService();
227            if (service == null) return false;
228            return service.connect(device);
229        }
230
231        public boolean disconnect(BluetoothDevice device) {
232            A2dpService service = getService();
233            if (service == null) return false;
234            return service.disconnect(device);
235        }
236
237        public List<BluetoothDevice> getConnectedDevices() {
238            A2dpService service = getService();
239            if (service == null) return new ArrayList<BluetoothDevice>(0);
240            return service.getConnectedDevices();
241        }
242
243        public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
244            A2dpService service = getService();
245            if (service == null) return new ArrayList<BluetoothDevice>(0);
246            return service.getDevicesMatchingConnectionStates(states);
247        }
248
249        public int getConnectionState(BluetoothDevice device) {
250            A2dpService service = getService();
251            if (service == null) return BluetoothProfile.STATE_DISCONNECTED;
252            return service.getConnectionState(device);
253        }
254
255        public boolean setPriority(BluetoothDevice device, int priority) {
256            A2dpService service = getService();
257            if (service == null) return false;
258            return service.setPriority(device, priority);
259        }
260
261        public int getPriority(BluetoothDevice device) {
262            A2dpService service = getService();
263            if (service == null) return BluetoothProfile.PRIORITY_UNDEFINED;
264            return service.getPriority(device);
265        }
266
267        public boolean isAvrcpAbsoluteVolumeSupported() {
268            A2dpService service = getService();
269            if (service == null) return false;
270            return service.isAvrcpAbsoluteVolumeSupported();
271        }
272
273        public void adjustAvrcpAbsoluteVolume(int direction) {
274            A2dpService service = getService();
275            if (service == null) return;
276            service.adjustAvrcpAbsoluteVolume(direction);
277        }
278
279        public void setAvrcpAbsoluteVolume(int volume) {
280            A2dpService service = getService();
281            if (service == null) return;
282            service.setAvrcpAbsoluteVolume(volume);
283        }
284
285        public boolean isA2dpPlaying(BluetoothDevice device) {
286            A2dpService service = getService();
287            if (service == null) return false;
288            return service.isA2dpPlaying(device);
289        }
290    };
291}
292