Home | History | Annotate | Download | only in bluetooth
      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 android.bluetooth;
     18 
     19 import android.content.ComponentName;
     20 import android.content.Context;
     21 import android.content.Intent;
     22 import android.content.ServiceConnection;
     23 import android.os.IBinder;
     24 import android.os.RemoteException;
     25 import android.util.Log;
     26 
     27 import java.util.ArrayList;
     28 import java.util.List;
     29 
     30 /**
     31  * This class provides the public APIs to control the Bluetooth AVRCP Controller
     32  * profile.
     33  *
     34  *<p>BluetoothAvrcpController is a proxy object for controlling the Bluetooth AVRCP
     35  * Service via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get
     36  * the BluetoothAvrcpController proxy object.
     37  *
     38  * {@hide}
     39  */
     40 public final class BluetoothAvrcpController implements BluetoothProfile {
     41     private static final String TAG = "BluetoothAvrcpController";
     42     private static final boolean DBG = true;
     43     private static final boolean VDBG = false;
     44 
     45     /**
     46      * Intent used to broadcast the change in connection state of the AVRCP Controller
     47      * profile.
     48      *
     49      * <p>This intent will have 3 extras:
     50      * <ul>
     51      *   <li> {@link #EXTRA_STATE} - The current state of the profile. </li>
     52      *   <li> {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile.</li>
     53      *   <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li>
     54      * </ul>
     55      *
     56      * <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of
     57      * {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING},
     58      * {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}.
     59      *
     60      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
     61      * receive.
     62      */
     63     public static final String ACTION_CONNECTION_STATE_CHANGED =
     64         "android.bluetooth.acrcp-controller.profile.action.CONNECTION_STATE_CHANGED";
     65 
     66     private Context mContext;
     67     private ServiceListener mServiceListener;
     68     private IBluetoothAvrcpController mService;
     69     private BluetoothAdapter mAdapter;
     70 
     71     final private IBluetoothStateChangeCallback mBluetoothStateChangeCallback =
     72             new IBluetoothStateChangeCallback.Stub() {
     73                 public void onBluetoothStateChange(boolean up) {
     74                     if (DBG) Log.d(TAG, "onBluetoothStateChange: up=" + up);
     75                     if (!up) {
     76                         if (VDBG) Log.d(TAG,"Unbinding service...");
     77                         synchronized (mConnection) {
     78                             try {
     79                                 mService = null;
     80                                 mContext.unbindService(mConnection);
     81                             } catch (Exception re) {
     82                                 Log.e(TAG,"",re);
     83                             }
     84                         }
     85                     } else {
     86                         synchronized (mConnection) {
     87                             try {
     88                                 if (mService == null) {
     89                                     if (VDBG) Log.d(TAG,"Binding service...");
     90                                     doBind();
     91                                 }
     92                             } catch (Exception re) {
     93                                 Log.e(TAG,"",re);
     94                             }
     95                         }
     96                     }
     97                 }
     98         };
     99 
    100     /**
    101      * Create a BluetoothAvrcpController proxy object for interacting with the local
    102      * Bluetooth AVRCP service.
    103      *
    104      */
    105     /*package*/ BluetoothAvrcpController(Context context, ServiceListener l) {
    106         mContext = context;
    107         mServiceListener = l;
    108         mAdapter = BluetoothAdapter.getDefaultAdapter();
    109         IBluetoothManager mgr = mAdapter.getBluetoothManager();
    110         if (mgr != null) {
    111             try {
    112                 mgr.registerStateChangeCallback(mBluetoothStateChangeCallback);
    113             } catch (RemoteException e) {
    114                 Log.e(TAG,"",e);
    115             }
    116         }
    117 
    118         doBind();
    119     }
    120 
    121     boolean doBind() {
    122         Intent intent = new Intent(IBluetoothAvrcpController.class.getName());
    123         ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
    124         intent.setComponent(comp);
    125         if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0,
    126                 android.os.Process.myUserHandle())) {
    127             Log.e(TAG, "Could not bind to Bluetooth AVRCP Controller Service with " + intent);
    128             return false;
    129         }
    130         return true;
    131     }
    132 
    133     /*package*/ void close() {
    134         mServiceListener = null;
    135         IBluetoothManager mgr = mAdapter.getBluetoothManager();
    136         if (mgr != null) {
    137             try {
    138                 mgr.unregisterStateChangeCallback(mBluetoothStateChangeCallback);
    139             } catch (Exception e) {
    140                 Log.e(TAG,"",e);
    141             }
    142         }
    143 
    144         synchronized (mConnection) {
    145             if (mService != null) {
    146                 try {
    147                     mService = null;
    148                     mContext.unbindService(mConnection);
    149                 } catch (Exception re) {
    150                     Log.e(TAG,"",re);
    151                 }
    152             }
    153         }
    154     }
    155 
    156     public void finalize() {
    157         close();
    158     }
    159 
    160     /**
    161      * {@inheritDoc}
    162      */
    163     public List<BluetoothDevice> getConnectedDevices() {
    164         if (VDBG) log("getConnectedDevices()");
    165         if (mService != null && isEnabled()) {
    166             try {
    167                 return mService.getConnectedDevices();
    168             } catch (RemoteException e) {
    169                 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
    170                 return new ArrayList<BluetoothDevice>();
    171             }
    172         }
    173         if (mService == null) Log.w(TAG, "Proxy not attached to service");
    174         return new ArrayList<BluetoothDevice>();
    175     }
    176 
    177     /**
    178      * {@inheritDoc}
    179      */
    180     public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
    181         if (VDBG) log("getDevicesMatchingStates()");
    182         if (mService != null && isEnabled()) {
    183             try {
    184                 return mService.getDevicesMatchingConnectionStates(states);
    185             } catch (RemoteException e) {
    186                 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
    187                 return new ArrayList<BluetoothDevice>();
    188             }
    189         }
    190         if (mService == null) Log.w(TAG, "Proxy not attached to service");
    191         return new ArrayList<BluetoothDevice>();
    192     }
    193 
    194     /**
    195      * {@inheritDoc}
    196      */
    197     public int getConnectionState(BluetoothDevice device) {
    198         if (VDBG) log("getState(" + device + ")");
    199         if (mService != null && isEnabled()
    200             && isValidDevice(device)) {
    201             try {
    202                 return mService.getConnectionState(device);
    203             } catch (RemoteException e) {
    204                 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
    205                 return BluetoothProfile.STATE_DISCONNECTED;
    206             }
    207         }
    208         if (mService == null) Log.w(TAG, "Proxy not attached to service");
    209         return BluetoothProfile.STATE_DISCONNECTED;
    210     }
    211 
    212     public void sendPassThroughCmd(BluetoothDevice device, int keyCode, int keyState) {
    213         if (DBG) Log.d(TAG, "sendPassThroughCmd");
    214         if (mService != null && isEnabled()) {
    215             try {
    216                 mService.sendPassThroughCmd(device, keyCode, keyState);
    217                 return;
    218             } catch (RemoteException e) {
    219                 Log.e(TAG, "Error talking to BT service in sendPassThroughCmd()", e);
    220                 return;
    221             }
    222         }
    223         if (mService == null) Log.w(TAG, "Proxy not attached to service");
    224     }
    225 
    226     private final ServiceConnection mConnection = new ServiceConnection() {
    227         public void onServiceConnected(ComponentName className, IBinder service) {
    228             if (DBG) Log.d(TAG, "Proxy object connected");
    229             mService = IBluetoothAvrcpController.Stub.asInterface(service);
    230 
    231             if (mServiceListener != null) {
    232                 mServiceListener.onServiceConnected(BluetoothProfile.AVRCP_CONTROLLER,
    233                         BluetoothAvrcpController.this);
    234             }
    235         }
    236         public void onServiceDisconnected(ComponentName className) {
    237             if (DBG) Log.d(TAG, "Proxy object disconnected");
    238             mService = null;
    239             if (mServiceListener != null) {
    240                 mServiceListener.onServiceDisconnected(BluetoothProfile.AVRCP_CONTROLLER);
    241             }
    242         }
    243     };
    244 
    245     private boolean isEnabled() {
    246        if (mAdapter.getState() == BluetoothAdapter.STATE_ON) return true;
    247        return false;
    248     }
    249 
    250     private boolean isValidDevice(BluetoothDevice device) {
    251        if (device == null) return false;
    252 
    253        if (BluetoothAdapter.checkBluetoothAddress(device.getAddress())) return true;
    254        return false;
    255     }
    256 
    257     private static void log(String msg) {
    258       Log.d(TAG, msg);
    259     }
    260 }
    261