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 */ BluetoothAvrcpController(Context context, ServiceListener listener)94 /*package*/ BluetoothAvrcpController(Context context, ServiceListener listener) { 95 mAdapter = BluetoothAdapter.getDefaultAdapter(); 96 mProfileConnector.connect(context, listener); 97 } 98 close()99 /*package*/ void close() { 100 mProfileConnector.disconnect(); 101 } 102 getService()103 private IBluetoothAvrcpController getService() { 104 return mProfileConnector.getService(); 105 } 106 107 @Override finalize()108 public void finalize() { 109 close(); 110 } 111 112 /** 113 * {@inheritDoc} 114 */ 115 @Override getConnectedDevices()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 getDevicesMatchingConnectionStates(int[] states)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 getConnectionState(BluetoothDevice device)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 */ getPlayerSettings(BluetoothDevice device)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 */ setPlayerApplicationSetting(BluetoothAvrcpPlayerSettings plAppSetting)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 */ sendGroupNavigationCmd(BluetoothDevice device, int keyCode, int keyState)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 isEnabled()234 private boolean isEnabled() { 235 return mAdapter.getState() == BluetoothAdapter.STATE_ON; 236 } 237 isValidDevice(BluetoothDevice device)238 private static boolean isValidDevice(BluetoothDevice device) { 239 return device != null && BluetoothAdapter.checkBluetoothAddress(device.getAddress()); 240 } 241 log(String msg)242 private static void log(String msg) { 243 Log.d(TAG, msg); 244 } 245 } 246