Home | History | Annotate | Download | only in a2dp
      1 /*
      2  * Copyright (C) 2014 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.BluetoothAudioConfig;
     20 import android.bluetooth.BluetoothDevice;
     21 import android.bluetooth.BluetoothProfile;
     22 import android.bluetooth.IBluetoothA2dpSink;
     23 import android.util.Log;
     24 import com.android.bluetooth.btservice.ProfileService;
     25 import com.android.bluetooth.Utils;
     26 import java.util.ArrayList;
     27 import java.util.List;
     28 import java.util.Map;
     29 
     30 /**
     31  * Provides Bluetooth A2DP Sink profile, as a service in the Bluetooth application.
     32  * @hide
     33  */
     34 public class A2dpSinkService extends ProfileService {
     35     private static final boolean DBG = false;
     36     private static final String TAG = "A2dpSinkService";
     37 
     38     private A2dpSinkStateMachine mStateMachine;
     39     private static A2dpSinkService sA2dpSinkService;
     40 
     41     protected String getName() {
     42         return TAG;
     43     }
     44 
     45     protected IProfileServiceBinder initBinder() {
     46         return new BluetoothA2dpSinkBinder(this);
     47     }
     48 
     49     protected boolean start() {
     50         mStateMachine = A2dpSinkStateMachine.make(this, this);
     51         setA2dpSinkService(this);
     52         return true;
     53     }
     54 
     55     protected boolean stop() {
     56         mStateMachine.doQuit();
     57         return true;
     58     }
     59 
     60     protected boolean cleanup() {
     61         if (mStateMachine!= null) {
     62             mStateMachine.cleanup();
     63         }
     64         clearA2dpSinkService();
     65         return true;
     66     }
     67 
     68     //API Methods
     69 
     70     public static synchronized A2dpSinkService getA2dpSinkService(){
     71         if (sA2dpSinkService != null && sA2dpSinkService.isAvailable()) {
     72             if (DBG) Log.d(TAG, "getA2dpSinkService(): returning " + sA2dpSinkService);
     73             return sA2dpSinkService;
     74         }
     75         if (DBG)  {
     76             if (sA2dpSinkService == null) {
     77                 Log.d(TAG, "getA2dpSinkService(): service is NULL");
     78             } else if (!(sA2dpSinkService.isAvailable())) {
     79                 Log.d(TAG,"getA2dpSinkService(): service is not available");
     80             }
     81         }
     82         return null;
     83     }
     84 
     85     private static synchronized void setA2dpSinkService(A2dpSinkService instance) {
     86         if (instance != null && instance.isAvailable()) {
     87             if (DBG) Log.d(TAG, "setA2dpSinkService(): set to: " + sA2dpSinkService);
     88             sA2dpSinkService = instance;
     89         } else {
     90             if (DBG)  {
     91                 if (sA2dpSinkService == null) {
     92                     Log.d(TAG, "setA2dpSinkService(): service not available");
     93                 } else if (!sA2dpSinkService.isAvailable()) {
     94                     Log.d(TAG,"setA2dpSinkService(): service is cleaning up");
     95                 }
     96             }
     97         }
     98     }
     99 
    100     private static synchronized void clearA2dpSinkService() {
    101         sA2dpSinkService = null;
    102     }
    103 
    104     public boolean connect(BluetoothDevice device) {
    105         enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
    106                                        "Need BLUETOOTH ADMIN permission");
    107 
    108         int connectionState = mStateMachine.getConnectionState(device);
    109         if (connectionState == BluetoothProfile.STATE_CONNECTED ||
    110             connectionState == BluetoothProfile.STATE_CONNECTING) {
    111             return false;
    112         }
    113 
    114         mStateMachine.sendMessage(A2dpSinkStateMachine.CONNECT, device);
    115         return true;
    116     }
    117 
    118     boolean disconnect(BluetoothDevice device) {
    119         enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
    120                                        "Need BLUETOOTH ADMIN permission");
    121         int connectionState = mStateMachine.getConnectionState(device);
    122         if (connectionState != BluetoothProfile.STATE_CONNECTED &&
    123             connectionState != BluetoothProfile.STATE_CONNECTING) {
    124             return false;
    125         }
    126 
    127         mStateMachine.sendMessage(A2dpSinkStateMachine.DISCONNECT, device);
    128         return true;
    129     }
    130 
    131     public List<BluetoothDevice> getConnectedDevices() {
    132         enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
    133         return mStateMachine.getConnectedDevices();
    134     }
    135 
    136     List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
    137         enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
    138         return mStateMachine.getDevicesMatchingConnectionStates(states);
    139     }
    140 
    141     int getConnectionState(BluetoothDevice device) {
    142         enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
    143         return mStateMachine.getConnectionState(device);
    144     }
    145 
    146     BluetoothAudioConfig getAudioConfig(BluetoothDevice device) {
    147         enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
    148         return mStateMachine.getAudioConfig(device);
    149     }
    150 
    151     //Binder object: Must be static class or memory leak may occur
    152     private static class BluetoothA2dpSinkBinder extends IBluetoothA2dpSink.Stub
    153         implements IProfileServiceBinder {
    154         private A2dpSinkService mService;
    155 
    156         private A2dpSinkService getService() {
    157             if (!Utils.checkCaller()) {
    158                 Log.w(TAG,"A2dp call not allowed for non-active user");
    159                 return null;
    160             }
    161 
    162             if (mService != null && mService.isAvailable()) {
    163                 return mService;
    164             }
    165             return null;
    166         }
    167 
    168         BluetoothA2dpSinkBinder(A2dpSinkService svc) {
    169             mService = svc;
    170         }
    171 
    172         public boolean cleanup()  {
    173             mService = null;
    174             return true;
    175         }
    176 
    177         public boolean connect(BluetoothDevice device) {
    178             A2dpSinkService service = getService();
    179             if (service == null) return false;
    180             return service.connect(device);
    181         }
    182 
    183         public boolean disconnect(BluetoothDevice device) {
    184             A2dpSinkService service = getService();
    185             if (service == null) return false;
    186             return service.disconnect(device);
    187         }
    188 
    189         public List<BluetoothDevice> getConnectedDevices() {
    190             A2dpSinkService service = getService();
    191             if (service == null) return new ArrayList<BluetoothDevice>(0);
    192             return service.getConnectedDevices();
    193         }
    194 
    195         public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
    196             A2dpSinkService service = getService();
    197             if (service == null) return new ArrayList<BluetoothDevice>(0);
    198             return service.getDevicesMatchingConnectionStates(states);
    199         }
    200 
    201         public int getConnectionState(BluetoothDevice device) {
    202             A2dpSinkService service = getService();
    203             if (service == null) return BluetoothProfile.STATE_DISCONNECTED;
    204             return service.getConnectionState(device);
    205         }
    206 
    207         public BluetoothAudioConfig getAudioConfig(BluetoothDevice device) {
    208             A2dpSinkService service = getService();
    209             if (service == null) return null;
    210             return service.getAudioConfig(device);
    211         }
    212     };
    213 
    214     @Override
    215     public void dump(StringBuilder sb) {
    216         super.dump(sb);
    217         if (mStateMachine != null) {
    218             mStateMachine.dump(sb);
    219         }
    220     }
    221 }
    222