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         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