BluetoothPbapClient.java revision 0a17db1cc5942ea000ca87bb72853de57a15ec64
1/* 2 * Copyright (C) 2016 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 17package android.bluetooth; 18 19import java.util.List; 20import java.util.ArrayList; 21import android.content.ComponentName; 22import android.content.Context; 23import android.content.Intent; 24import android.content.ServiceConnection; 25import android.os.RemoteException; 26import android.os.Binder; 27import android.os.IBinder; 28import android.util.Log; 29 30/** 31 * This class provides the APIs to control the Bluetooth PBAP Client Profile. 32 *@hide 33 */ 34public final class BluetoothPbapClient implements BluetoothProfile { 35 36 private static final String TAG = "BluetoothPbapClient"; 37 private static final boolean DBG = false; 38 private static final boolean VDBG = false; 39 40 public static final String ACTION_CONNECTION_STATE_CHANGED = 41 "android.bluetooth.pbap.profile.action.CONNECTION_STATE_CHANGED"; 42 43 private IBluetoothPbapClient mService; 44 private final Context mContext; 45 private ServiceListener mServiceListener; 46 private BluetoothAdapter mAdapter; 47 48 /** There was an error trying to obtain the state */ 49 public static final int STATE_ERROR = -1; 50 51 public static final int RESULT_FAILURE = 0; 52 public static final int RESULT_SUCCESS = 1; 53 /** Connection canceled before completion. */ 54 public static final int RESULT_CANCELED = 2; 55 56 final private IBluetoothStateChangeCallback mBluetoothStateChangeCallback = 57 new IBluetoothStateChangeCallback.Stub() { 58 public void onBluetoothStateChange(boolean up) { 59 if (DBG) { 60 Log.d(TAG, "onBluetoothStateChange: PBAP CLIENT up=" + up); 61 } 62 if (!up) { 63 if (VDBG) { 64 Log.d(TAG,"Unbinding service..."); 65 } 66 synchronized (mConnection) { 67 try { 68 mService = null; 69 mContext.unbindService(mConnection); 70 } catch (Exception re) { 71 Log.e(TAG,"",re); 72 } 73 } 74 } else { 75 synchronized (mConnection) { 76 try { 77 if (mService == null) { 78 if (VDBG) { 79 Log.d(TAG,"Binding service..."); 80 } 81 doBind(); 82 } 83 } catch (Exception re) { 84 Log.e(TAG,"",re); 85 } 86 } 87 } 88 } 89 }; 90 91 /** 92 * Create a BluetoothPbapClient proxy object. 93 */ 94 BluetoothPbapClient(Context context, ServiceListener l) { 95 if (DBG) { 96 Log.d(TAG, "Create BluetoothPbapClient proxy object"); 97 } 98 mContext = context; 99 mServiceListener = l; 100 mAdapter = BluetoothAdapter.getDefaultAdapter(); 101 IBluetoothManager mgr = mAdapter.getBluetoothManager(); 102 if (mgr != null) { 103 try { 104 mgr.registerStateChangeCallback(mBluetoothStateChangeCallback); 105 } catch (RemoteException e) { 106 Log.e(TAG,"",e); 107 } 108 } 109 doBind(); 110 } 111 112 private boolean doBind() { 113 Intent intent = new Intent(IBluetoothPbapClient.class.getName()); 114 ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0); 115 intent.setComponent(comp); 116 if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0, 117 android.os.Process.myUserHandle())) { 118 Log.e(TAG, "Could not bind to Bluetooth PBAP Client Service with " + intent); 119 return false; 120 } 121 return true; 122 } 123 124 protected void finalize() throws Throwable { 125 try { 126 close(); 127 } finally { 128 super.finalize(); 129 } 130 } 131 132 /** 133 * Close the connection to the backing service. 134 * Other public functions of BluetoothPbapClient will return default error 135 * results once close() has been called. Multiple invocations of close() 136 * are ok. 137 */ 138 public synchronized void close() { 139 IBluetoothManager mgr = mAdapter.getBluetoothManager(); 140 if (mgr != null) { 141 try { 142 mgr.unregisterStateChangeCallback(mBluetoothStateChangeCallback); 143 } catch (Exception e) { 144 Log.e(TAG,"",e); 145 } 146 } 147 148 synchronized (mConnection) { 149 if (mService != null) { 150 try { 151 mService = null; 152 mContext.unbindService(mConnection); 153 } catch (Exception re) { 154 Log.e(TAG,"",re); 155 } 156 } 157 } 158 mServiceListener = null; 159 } 160 161 /** 162 * Initiate connection. 163 * Upon successful connection to remote PBAP server the Client will 164 * attempt to automatically download the users phonebook and call log. 165 * 166 * @param device a remote device we want connect to 167 * @return <code>true</code> if command has been issued successfully; 168 * <code>false</code> otherwise; 169 */ 170 public boolean connect(BluetoothDevice device) { 171 if (DBG) { 172 log("connect(" + device + ") for PBAP Client."); 173 } 174 if (mService != null && isEnabled() && isValidDevice(device)) { 175 try { 176 return mService.connect(device); 177 } catch (RemoteException e) { 178 Log.e(TAG, Log.getStackTraceString(new Throwable())); 179 return false; 180 } 181 } 182 if (mService == null) { 183 Log.w(TAG, "Proxy not attached to service"); 184 } 185 return false; 186 } 187 188 /** 189 * Initiate disconnect. 190 * 191 * @param device Remote Bluetooth Device 192 * @return false on error, 193 * true otherwise 194 */ 195 public boolean disconnect(BluetoothDevice device) { 196 if (DBG) { 197 log("disconnect(" + device + ")" + new Exception() ); 198 } 199 if (mService != null && isEnabled() && isValidDevice(device)) { 200 try { 201 mService.disconnect(device); 202 return true; 203 } catch (RemoteException e) { 204 Log.e(TAG, Log.getStackTraceString(new Throwable())); 205 return false; 206 } 207 } 208 if (mService == null) { 209 Log.w(TAG, "Proxy not attached to service"); 210 } 211 return false; 212 } 213 214 /** 215 * Get the list of connected devices. 216 * Currently at most one. 217 * 218 * @return list of connected devices 219 */ 220 @Override 221 public List<BluetoothDevice> getConnectedDevices() { 222 if (DBG) { 223 log("getConnectedDevices()"); 224 } 225 if (mService != null && isEnabled()) { 226 try { 227 return mService.getConnectedDevices(); 228 } catch (RemoteException e) { 229 Log.e(TAG, Log.getStackTraceString(new Throwable())); 230 return new ArrayList<BluetoothDevice>(); 231 } 232 } 233 if (mService == null) { 234 Log.w(TAG, "Proxy not attached to service"); 235 } 236 return new ArrayList<BluetoothDevice>(); 237 } 238 239 /** 240 * Get the list of devices matching specified states. Currently at most one. 241 * 242 * @return list of matching devices 243 */ 244 @Override 245 public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { 246 if (DBG) { 247 log("getDevicesMatchingStates()"); 248 } 249 if (mService != null && isEnabled()) { 250 try { 251 return mService.getDevicesMatchingConnectionStates(states); 252 } catch (RemoteException e) { 253 Log.e(TAG, Log.getStackTraceString(new Throwable())); 254 return new ArrayList<BluetoothDevice>(); 255 } 256 } 257 if (mService == null) { 258 Log.w(TAG, "Proxy not attached to service"); 259 } 260 return new ArrayList<BluetoothDevice>(); 261 } 262 263 /** 264 * Get connection state of device 265 * 266 * @return device connection state 267 */ 268 @Override 269 public int getConnectionState(BluetoothDevice device) { 270 if (DBG) { 271 log("getConnectionState(" + device + ")"); 272 } 273 if (mService != null && isEnabled() && isValidDevice(device)) { 274 try { 275 return mService.getConnectionState(device); 276 } catch (RemoteException e) { 277 Log.e(TAG, Log.getStackTraceString(new Throwable())); 278 return BluetoothProfile.STATE_DISCONNECTED; 279 } 280 } 281 if (mService == null) { 282 Log.w(TAG, "Proxy not attached to service"); 283 } 284 return BluetoothProfile.STATE_DISCONNECTED; 285 } 286 287 private final ServiceConnection mConnection = new ServiceConnection() { 288 public void onServiceConnected(ComponentName className, IBinder service) { 289 if (DBG) { 290 log("Proxy object connected"); 291 } 292 mService = IBluetoothPbapClient.Stub.asInterface(Binder.allowBlocking(service)); 293 if (mServiceListener != null) { 294 mServiceListener.onServiceConnected(BluetoothProfile.PBAP_CLIENT, BluetoothPbapClient.this); 295 } 296 } 297 public void onServiceDisconnected(ComponentName className) { 298 if (DBG) { 299 log("Proxy object disconnected"); 300 } 301 mService = null; 302 if (mServiceListener != null) { 303 mServiceListener.onServiceDisconnected(BluetoothProfile.PBAP_CLIENT); 304 } 305 } 306 }; 307 308 private static void log(String msg) { 309 Log.d(TAG, msg); 310 } 311 312 private boolean isEnabled() { 313 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); 314 if (adapter != null && adapter.getState() == BluetoothAdapter.STATE_ON) { 315 return true; 316 } 317 log("Bluetooth is Not enabled"); 318 return false; 319 } 320 321 private boolean isValidDevice(BluetoothDevice device) { 322 if (device == null) { 323 return false; 324 } 325 if (BluetoothAdapter.checkBluetoothAddress(device.getAddress())) { 326 return true; 327 } 328 return false; 329 } 330 331 /** 332 * Set priority of the profile 333 * 334 * <p> The device should already be paired. 335 * Priority can be one of {@link #PRIORITY_ON} or 336 * {@link #PRIORITY_OFF}, 337 * 338 * @param device Paired bluetooth device 339 * @param priority 340 * @return true if priority is set, false on error 341 */ 342 public boolean setPriority(BluetoothDevice device, int priority) { 343 if (DBG) { 344 log("setPriority(" + device + ", " + priority + ")"); 345 } 346 if (mService != null && isEnabled() && 347 isValidDevice(device)) { 348 if (priority != BluetoothProfile.PRIORITY_OFF && 349 priority != BluetoothProfile.PRIORITY_ON) { 350 return false; 351 } 352 try { 353 return mService.setPriority(device, priority); 354 } catch (RemoteException e) { 355 Log.e(TAG, Log.getStackTraceString(new Throwable())); 356 return false; 357 } 358 } 359 if (mService == null) { 360 Log.w(TAG, "Proxy not attached to service"); 361 } 362 return false; 363 } 364 365 /** 366 * Get the priority of the profile. 367 * 368 * <p> The priority can be any of: 369 * {@link #PRIORITY_AUTO_CONNECT}, {@link #PRIORITY_OFF}, 370 * {@link #PRIORITY_ON}, {@link #PRIORITY_UNDEFINED} 371 * 372 * @param device Bluetooth device 373 * @return priority of the device 374 */ 375 public int getPriority(BluetoothDevice device) { 376 if (VDBG) { 377 log("getPriority(" + device + ")"); 378 } 379 if (mService != null && isEnabled() && isValidDevice(device)) { 380 try { 381 return mService.getPriority(device); 382 } catch (RemoteException e) { 383 Log.e(TAG, Log.getStackTraceString(new Throwable())); 384 return PRIORITY_OFF; 385 } 386 } 387 if (mService == null) { 388 Log.w(TAG, "Proxy not attached to service"); 389 } 390 return PRIORITY_OFF; 391 } 392} 393