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.Context;
     20 import android.os.Binder;
     21 import android.os.IBinder;
     22 import android.os.RemoteException;
     23 import android.util.Log;
     24 
     25 import java.util.ArrayList;
     26 import java.util.List;
     27 
     28 /**
     29  * This class provides the public APIs to control the Bluetooth AVRCP Controller. It currently
     30  * supports player information, playback support and track metadata.
     31  *
     32  * <p>BluetoothAvrcpController is a proxy object for controlling the Bluetooth AVRCP
     33  * Service via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get
     34  * the BluetoothAvrcpController proxy object.
     35  *
     36  * {@hide}
     37  */
     38 public final class BluetoothAvrcpController implements BluetoothProfile {
     39     private static final String TAG = "BluetoothAvrcpController";
     40     private static final boolean DBG = false;
     41     private static final boolean VDBG = false;
     42 
     43     /**
     44      * Intent used to broadcast the change in connection state of the AVRCP Controller
     45      * profile.
     46      *
     47      * <p>This intent will have 3 extras:
     48      * <ul>
     49      * <li> {@link #EXTRA_STATE} - The current state of the profile. </li>
     50      * <li> {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile.</li>
     51      * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li>
     52      * </ul>
     53      *
     54      * <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of
     55      * {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING},
     56      * {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}.
     57      *
     58      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
     59      * receive.
     60      */
     61     public static final String ACTION_CONNECTION_STATE_CHANGED =
     62             "android.bluetooth.avrcp-controller.profile.action.CONNECTION_STATE_CHANGED";
     63 
     64     /**
     65      * Intent used to broadcast the change in player application setting state on AVRCP AG.
     66      *
     67      * <p>This intent will have the following extras:
     68      * <ul>
     69      * <li> {@link #EXTRA_PLAYER_SETTING} - {@link BluetoothAvrcpPlayerSettings} containing the
     70      * most recent player setting. </li>
     71      * </ul>
     72      */
     73     public static final String ACTION_PLAYER_SETTING =
     74             "android.bluetooth.avrcp-controller.profile.action.PLAYER_SETTING";
     75 
     76     public static final String EXTRA_PLAYER_SETTING =
     77             "android.bluetooth.avrcp-controller.profile.extra.PLAYER_SETTING";
     78 
     79     private BluetoothAdapter mAdapter;
     80     private final BluetoothProfileConnector<IBluetoothAvrcpController> mProfileConnector =
     81             new BluetoothProfileConnector(this, BluetoothProfile.AVRCP_CONTROLLER,
     82                     "BluetoothAvrcpController", IBluetoothAvrcpController.class.getName()) {
     83                 @Override
     84                 public IBluetoothAvrcpController getServiceInterface(IBinder service) {
     85                     return IBluetoothAvrcpController.Stub.asInterface(
     86                             Binder.allowBlocking(service));
     87                 }
     88     };
     89 
     90     /**
     91      * Create a BluetoothAvrcpController proxy object for interacting with the local
     92      * Bluetooth AVRCP service.
     93      */
     94     /*package*/ BluetoothAvrcpController(Context context, ServiceListener listener) {
     95         mAdapter = BluetoothAdapter.getDefaultAdapter();
     96         mProfileConnector.connect(context, listener);
     97     }
     98 
     99     /*package*/ void close() {
    100         mProfileConnector.disconnect();
    101     }
    102 
    103     private IBluetoothAvrcpController getService() {
    104         return mProfileConnector.getService();
    105     }
    106 
    107     @Override
    108     public void finalize() {
    109         close();
    110     }
    111 
    112     /**
    113      * {@inheritDoc}
    114      */
    115     @Override
    116     public List<BluetoothDevice> getConnectedDevices() {
    117         if (VDBG) log("getConnectedDevices()");
    118         final IBluetoothAvrcpController service =
    119                 getService();
    120         if (service != null && isEnabled()) {
    121             try {
    122                 return service.getConnectedDevices();
    123             } catch (RemoteException e) {
    124                 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
    125                 return new ArrayList<BluetoothDevice>();
    126             }
    127         }
    128         if (service == null) Log.w(TAG, "Proxy not attached to service");
    129         return new ArrayList<BluetoothDevice>();
    130     }
    131 
    132     /**
    133      * {@inheritDoc}
    134      */
    135     @Override
    136     public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
    137         if (VDBG) log("getDevicesMatchingStates()");
    138         final IBluetoothAvrcpController service =
    139                 getService();
    140         if (service != null && isEnabled()) {
    141             try {
    142                 return service.getDevicesMatchingConnectionStates(states);
    143             } catch (RemoteException e) {
    144                 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
    145                 return new ArrayList<BluetoothDevice>();
    146             }
    147         }
    148         if (service == null) Log.w(TAG, "Proxy not attached to service");
    149         return new ArrayList<BluetoothDevice>();
    150     }
    151 
    152     /**
    153      * {@inheritDoc}
    154      */
    155     @Override
    156     public int getConnectionState(BluetoothDevice device) {
    157         if (VDBG) log("getState(" + device + ")");
    158         final IBluetoothAvrcpController service =
    159                 getService();
    160         if (service != null && isEnabled() && isValidDevice(device)) {
    161             try {
    162                 return service.getConnectionState(device);
    163             } catch (RemoteException e) {
    164                 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
    165                 return BluetoothProfile.STATE_DISCONNECTED;
    166             }
    167         }
    168         if (service == null) Log.w(TAG, "Proxy not attached to service");
    169         return BluetoothProfile.STATE_DISCONNECTED;
    170     }
    171 
    172     /**
    173      * Gets the player application settings.
    174      *
    175      * @return the {@link BluetoothAvrcpPlayerSettings} or {@link null} if there is an error.
    176      */
    177     public BluetoothAvrcpPlayerSettings getPlayerSettings(BluetoothDevice device) {
    178         if (DBG) Log.d(TAG, "getPlayerSettings");
    179         BluetoothAvrcpPlayerSettings settings = null;
    180         final IBluetoothAvrcpController service =
    181                 getService();
    182         if (service != null && isEnabled()) {
    183             try {
    184                 settings = service.getPlayerSettings(device);
    185             } catch (RemoteException e) {
    186                 Log.e(TAG, "Error talking to BT service in getMetadata() " + e);
    187                 return null;
    188             }
    189         }
    190         return settings;
    191     }
    192 
    193     /**
    194      * Sets the player app setting for current player.
    195      * returns true in case setting is supported by remote, false otherwise
    196      */
    197     public boolean setPlayerApplicationSetting(BluetoothAvrcpPlayerSettings plAppSetting) {
    198         if (DBG) Log.d(TAG, "setPlayerApplicationSetting");
    199         final IBluetoothAvrcpController service =
    200                 getService();
    201         if (service != null && isEnabled()) {
    202             try {
    203                 return service.setPlayerApplicationSetting(plAppSetting);
    204             } catch (RemoteException e) {
    205                 Log.e(TAG, "Error talking to BT service in setPlayerApplicationSetting() " + e);
    206                 return false;
    207             }
    208         }
    209         if (service == null) Log.w(TAG, "Proxy not attached to service");
    210         return false;
    211     }
    212 
    213     /**
    214      * Send Group Navigation Command to Remote.
    215      * possible keycode values: next_grp, previous_grp defined above
    216      */
    217     public void sendGroupNavigationCmd(BluetoothDevice device, int keyCode, int keyState) {
    218         Log.d(TAG, "sendGroupNavigationCmd dev = " + device + " key " + keyCode + " State = "
    219                 + keyState);
    220         final IBluetoothAvrcpController service =
    221                 getService();
    222         if (service != null && isEnabled()) {
    223             try {
    224                 service.sendGroupNavigationCmd(device, keyCode, keyState);
    225                 return;
    226             } catch (RemoteException e) {
    227                 Log.e(TAG, "Error talking to BT service in sendGroupNavigationCmd()", e);
    228                 return;
    229             }
    230         }
    231         if (service == null) Log.w(TAG, "Proxy not attached to service");
    232     }
    233 
    234     private boolean isEnabled() {
    235         return mAdapter.getState() == BluetoothAdapter.STATE_ON;
    236     }
    237 
    238     private static boolean isValidDevice(BluetoothDevice device) {
    239         return device != null && BluetoothAdapter.checkBluetoothAddress(device.getAddress());
    240     }
    241 
    242     private static void log(String msg) {
    243         Log.d(TAG, msg);
    244     }
    245 }
    246