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.avrcp.Avrcp;
     27 import com.android.bluetooth.btservice.ProfileService;
     28 import com.android.bluetooth.Utils;
     29 import java.util.ArrayList;
     30 import java.util.Iterator;
     31 import java.util.List;
     32 import java.util.Map;
     33 
     34 /**
     35  * Provides Bluetooth A2DP profile, as a service in the Bluetooth application.
     36  * @hide
     37  */
     38 public class A2dpService extends ProfileService {
     39     private static final boolean DBG = false;
     40     private static final String TAG="A2dpService";
     41 
     42     private A2dpStateMachine mStateMachine;
     43     private Avrcp mAvrcp;
     44     private static A2dpService sAd2dpService;
     45 
     46     protected String getName() {
     47         return TAG;
     48     }
     49 
     50     protected IProfileServiceBinder initBinder() {
     51         return new BluetoothA2dpBinder(this);
     52     }
     53 
     54     protected boolean start() {
     55         mAvrcp = Avrcp.make(this);
     56         mStateMachine = A2dpStateMachine.make(this, this);
     57         setA2dpService(this);
     58         return true;
     59     }
     60 
     61     protected boolean stop() {
     62         if (mStateMachine != null) {
     63             mStateMachine.doQuit();
     64         }
     65         if (mAvrcp != null) {
     66             mAvrcp.doQuit();
     67         }
     68         return true;
     69     }
     70 
     71     protected boolean cleanup() {
     72         if (mStateMachine!= null) {
     73             mStateMachine.cleanup();
     74         }
     75         if (mAvrcp != null) {
     76             mAvrcp.cleanup();
     77             mAvrcp = null;
     78         }
     79         clearA2dpService();
     80         return true;
     81     }
     82 
     83     //API Methods
     84 
     85     public static synchronized A2dpService getA2dpService(){
     86         if (sAd2dpService != null && sAd2dpService.isAvailable()) {
     87             if (DBG) Log.d(TAG, "getA2DPService(): returning " + sAd2dpService);
     88             return sAd2dpService;
     89         }
     90         if (DBG)  {
     91             if (sAd2dpService == null) {
     92                 Log.d(TAG, "getA2dpService(): service is NULL");
     93             } else if (!(sAd2dpService.isAvailable())) {
     94                 Log.d(TAG,"getA2dpService(): service is not available");
     95             }
     96         }
     97         return null;
     98     }
     99 
    100     private static synchronized void setA2dpService(A2dpService instance) {
    101         if (instance != null && instance.isAvailable()) {
    102             if (DBG) Log.d(TAG, "setA2dpService(): set to: " + sAd2dpService);
    103             sAd2dpService = instance;
    104         } else {
    105             if (DBG)  {
    106                 if (sAd2dpService == null) {
    107                     Log.d(TAG, "setA2dpService(): service not available");
    108                 } else if (!sAd2dpService.isAvailable()) {
    109                     Log.d(TAG,"setA2dpService(): service is cleaning up");
    110                 }
    111             }
    112         }
    113     }
    114 
    115     private static synchronized void clearA2dpService() {
    116         sAd2dpService = null;
    117     }
    118 
    119     public boolean connect(BluetoothDevice device) {
    120         enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
    121                                        "Need BLUETOOTH ADMIN permission");
    122 
    123         if (getPriority(device) == BluetoothProfile.PRIORITY_OFF) {
    124             return false;
    125         }
    126 
    127         int connectionState = mStateMachine.getConnectionState(device);
    128         if (connectionState == BluetoothProfile.STATE_CONNECTED ||
    129             connectionState == BluetoothProfile.STATE_CONNECTING) {
    130             return false;
    131         }
    132 
    133         mStateMachine.sendMessage(A2dpStateMachine.CONNECT, device);
    134         return true;
    135     }
    136 
    137     boolean disconnect(BluetoothDevice device) {
    138         enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
    139                                        "Need BLUETOOTH ADMIN permission");
    140         int connectionState = mStateMachine.getConnectionState(device);
    141         if (connectionState != BluetoothProfile.STATE_CONNECTED &&
    142             connectionState != BluetoothProfile.STATE_CONNECTING) {
    143             return false;
    144         }
    145 
    146         mStateMachine.sendMessage(A2dpStateMachine.DISCONNECT, device);
    147         return true;
    148     }
    149 
    150     public List<BluetoothDevice> getConnectedDevices() {
    151         enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
    152         return mStateMachine.getConnectedDevices();
    153     }
    154 
    155     List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
    156         enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
    157         return mStateMachine.getDevicesMatchingConnectionStates(states);
    158     }
    159 
    160     int getConnectionState(BluetoothDevice device) {
    161         enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
    162         return mStateMachine.getConnectionState(device);
    163     }
    164 
    165     public boolean setPriority(BluetoothDevice device, int priority) {
    166         enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
    167                                        "Need BLUETOOTH_ADMIN permission");
    168         Settings.Global.putInt(getContentResolver(),
    169             Settings.Global.getBluetoothA2dpSinkPriorityKey(device.getAddress()),
    170             priority);
    171         if (DBG) Log.d(TAG,"Saved priority " + device + " = " + priority);
    172         return true;
    173     }
    174 
    175     public int getPriority(BluetoothDevice device) {
    176         enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
    177                                        "Need BLUETOOTH_ADMIN permission");
    178         int priority = Settings.Global.getInt(getContentResolver(),
    179             Settings.Global.getBluetoothA2dpSinkPriorityKey(device.getAddress()),
    180             BluetoothProfile.PRIORITY_UNDEFINED);
    181         return priority;
    182     }
    183 
    184     /* Absolute volume implementation */
    185     public boolean isAvrcpAbsoluteVolumeSupported() {
    186         return mAvrcp.isAbsoluteVolumeSupported();
    187     }
    188 
    189     public void adjustAvrcpAbsoluteVolume(int direction) {
    190         mAvrcp.adjustVolume(direction);
    191     }
    192 
    193     public void setAvrcpAbsoluteVolume(int volume) {
    194         mAvrcp.setAbsoluteVolume(volume);
    195     }
    196 
    197     public void setAvrcpAudioState(int state) {
    198         mAvrcp.setA2dpAudioState(state);
    199     }
    200 
    201     synchronized boolean isA2dpPlaying(BluetoothDevice device) {
    202         enforceCallingOrSelfPermission(BLUETOOTH_PERM,
    203                                        "Need BLUETOOTH permission");
    204         if (DBG) Log.d(TAG, "isA2dpPlaying(" + device + ")");
    205         return mStateMachine.isPlaying(device);
    206     }
    207 
    208     //Binder object: Must be static class or memory leak may occur
    209     private static class BluetoothA2dpBinder extends IBluetoothA2dp.Stub
    210         implements IProfileServiceBinder {
    211         private A2dpService mService;
    212 
    213         private A2dpService getService() {
    214             if (!Utils.checkCaller()) {
    215                 Log.w(TAG,"A2dp call not allowed for non-active user");
    216                 return null;
    217             }
    218 
    219             if (mService != null && mService.isAvailable()) {
    220                 return mService;
    221             }
    222             return null;
    223         }
    224 
    225         BluetoothA2dpBinder(A2dpService svc) {
    226             mService = svc;
    227         }
    228 
    229         public boolean cleanup()  {
    230             mService = null;
    231             return true;
    232         }
    233 
    234         public boolean connect(BluetoothDevice device) {
    235             A2dpService service = getService();
    236             if (service == null) return false;
    237             return service.connect(device);
    238         }
    239 
    240         public boolean disconnect(BluetoothDevice device) {
    241             A2dpService service = getService();
    242             if (service == null) return false;
    243             return service.disconnect(device);
    244         }
    245 
    246         public List<BluetoothDevice> getConnectedDevices() {
    247             A2dpService service = getService();
    248             if (service == null) return new ArrayList<BluetoothDevice>(0);
    249             return service.getConnectedDevices();
    250         }
    251 
    252         public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
    253             A2dpService service = getService();
    254             if (service == null) return new ArrayList<BluetoothDevice>(0);
    255             return service.getDevicesMatchingConnectionStates(states);
    256         }
    257 
    258         public int getConnectionState(BluetoothDevice device) {
    259             A2dpService service = getService();
    260             if (service == null) return BluetoothProfile.STATE_DISCONNECTED;
    261             return service.getConnectionState(device);
    262         }
    263 
    264         public boolean setPriority(BluetoothDevice device, int priority) {
    265             A2dpService service = getService();
    266             if (service == null) return false;
    267             return service.setPriority(device, priority);
    268         }
    269 
    270         public int getPriority(BluetoothDevice device) {
    271             A2dpService service = getService();
    272             if (service == null) return BluetoothProfile.PRIORITY_UNDEFINED;
    273             return service.getPriority(device);
    274         }
    275 
    276         public boolean isAvrcpAbsoluteVolumeSupported() {
    277             A2dpService service = getService();
    278             if (service == null) return false;
    279             return service.isAvrcpAbsoluteVolumeSupported();
    280         }
    281 
    282         public void adjustAvrcpAbsoluteVolume(int direction) {
    283             A2dpService service = getService();
    284             if (service == null) return;
    285             service.adjustAvrcpAbsoluteVolume(direction);
    286         }
    287 
    288         public void setAvrcpAbsoluteVolume(int volume) {
    289             A2dpService service = getService();
    290             if (service == null) return;
    291             service.setAvrcpAbsoluteVolume(volume);
    292         }
    293 
    294         public boolean isA2dpPlaying(BluetoothDevice device) {
    295             A2dpService service = getService();
    296             if (service == null) return false;
    297             return service.isA2dpPlaying(device);
    298         }
    299     };
    300 
    301     @Override
    302     public void dump(StringBuilder sb) {
    303         super.dump(sb);
    304         if (mStateMachine != null) {
    305             mStateMachine.dump(sb);
    306         }
    307         if (mAvrcp != null) {
    308             mAvrcp.dump(sb);
    309         }
    310     }
    311 }
    312