Home | History | Annotate | Download | only in a2dp
      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 
     17 package com.android.bluetooth.a2dp;
     18 
     19 import android.bluetooth.BluetoothDevice;
     20 import android.bluetooth.BluetoothProfile;
     21 import android.bluetooth.IBluetoothA2dp;
     22 import android.content.Context;
     23 import android.content.Intent;
     24 import android.provider.Settings;
     25 import android.util.Log;
     26 import com.android.bluetooth.btservice.ProfileService;
     27 import com.android.bluetooth.Utils;
     28 import java.util.ArrayList;
     29 import java.util.Iterator;
     30 import java.util.List;
     31 import java.util.Map;
     32 
     33 /**
     34  * Provides Bluetooth A2DP profile, as a service in the Bluetooth application.
     35  * @hide
     36  */
     37 public 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         mAvrcp = Avrcp.make(this);
     55         mStateMachine = A2dpStateMachine.make(this, 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     public void setAvrcpAudioState(int state) {
    193         mAvrcp.setA2dpAudioState(state);
    194     }
    195 
    196     synchronized boolean isA2dpPlaying(BluetoothDevice device) {
    197         enforceCallingOrSelfPermission(BLUETOOTH_PERM,
    198                                        "Need BLUETOOTH permission");
    199         if (DBG) Log.d(TAG, "isA2dpPlaying(" + device + ")");
    200         return mStateMachine.isPlaying(device);
    201     }
    202 
    203     //Binder object: Must be static class or memory leak may occur
    204     private static class BluetoothA2dpBinder extends IBluetoothA2dp.Stub
    205         implements IProfileServiceBinder {
    206         private A2dpService mService;
    207 
    208         private A2dpService getService() {
    209             if (!Utils.checkCaller()) {
    210                 Log.w(TAG,"A2dp call not allowed for non-active user");
    211                 return null;
    212             }
    213 
    214             if (mService != null && mService.isAvailable()) {
    215                 return mService;
    216             }
    217             return null;
    218         }
    219 
    220         BluetoothA2dpBinder(A2dpService svc) {
    221             mService = svc;
    222         }
    223 
    224         public boolean cleanup()  {
    225             mService = null;
    226             return true;
    227         }
    228 
    229         public boolean connect(BluetoothDevice device) {
    230             A2dpService service = getService();
    231             if (service == null) return false;
    232             return service.connect(device);
    233         }
    234 
    235         public boolean disconnect(BluetoothDevice device) {
    236             A2dpService service = getService();
    237             if (service == null) return false;
    238             return service.disconnect(device);
    239         }
    240 
    241         public List<BluetoothDevice> getConnectedDevices() {
    242             A2dpService service = getService();
    243             if (service == null) return new ArrayList<BluetoothDevice>(0);
    244             return service.getConnectedDevices();
    245         }
    246 
    247         public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
    248             A2dpService service = getService();
    249             if (service == null) return new ArrayList<BluetoothDevice>(0);
    250             return service.getDevicesMatchingConnectionStates(states);
    251         }
    252 
    253         public int getConnectionState(BluetoothDevice device) {
    254             A2dpService service = getService();
    255             if (service == null) return BluetoothProfile.STATE_DISCONNECTED;
    256             return service.getConnectionState(device);
    257         }
    258 
    259         public boolean setPriority(BluetoothDevice device, int priority) {
    260             A2dpService service = getService();
    261             if (service == null) return false;
    262             return service.setPriority(device, priority);
    263         }
    264 
    265         public int getPriority(BluetoothDevice device) {
    266             A2dpService service = getService();
    267             if (service == null) return BluetoothProfile.PRIORITY_UNDEFINED;
    268             return service.getPriority(device);
    269         }
    270 
    271         public boolean isAvrcpAbsoluteVolumeSupported() {
    272             A2dpService service = getService();
    273             if (service == null) return false;
    274             return service.isAvrcpAbsoluteVolumeSupported();
    275         }
    276 
    277         public void adjustAvrcpAbsoluteVolume(int direction) {
    278             A2dpService service = getService();
    279             if (service == null) return;
    280             service.adjustAvrcpAbsoluteVolume(direction);
    281         }
    282 
    283         public void setAvrcpAbsoluteVolume(int volume) {
    284             A2dpService service = getService();
    285             if (service == null) return;
    286             service.setAvrcpAbsoluteVolume(volume);
    287         }
    288 
    289         public boolean isA2dpPlaying(BluetoothDevice device) {
    290             A2dpService service = getService();
    291             if (service == null) return false;
    292             return service.isA2dpPlaying(device);
    293         }
    294     };
    295 }
    296