1 /* 2 * Copyright (C) 2013 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.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.annotation.RequiresFeature; 22 import android.annotation.RequiresNoPermission; 23 import android.annotation.RequiresPermission; 24 import android.annotation.SystemService; 25 import android.app.ActivityThread; 26 import android.app.AppGlobals; 27 import android.bluetooth.annotations.RequiresBluetoothConnectPermission; 28 import android.bluetooth.annotations.RequiresLegacyBluetoothPermission; 29 import android.content.Attributable; 30 import android.content.AttributionSource; 31 import android.content.Context; 32 import android.content.pm.PackageManager; 33 import android.os.RemoteException; 34 import android.util.Log; 35 36 import java.util.ArrayList; 37 import java.util.List; 38 39 /** 40 * High level manager used to obtain an instance of an {@link BluetoothAdapter} 41 * and to conduct overall Bluetooth Management. 42 * <p> 43 * Use {@link android.content.Context#getSystemService(java.lang.String)} 44 * with {@link Context#BLUETOOTH_SERVICE} to create an {@link BluetoothManager}, 45 * then call {@link #getAdapter} to obtain the {@link BluetoothAdapter}. 46 * </p> 47 * <div class="special reference"> 48 * <h3>Developer Guides</h3> 49 * <p> 50 * For more information about using BLUETOOTH, read the <a href= 51 * "{@docRoot}guide/topics/connectivity/bluetooth.html">Bluetooth</a> developer 52 * guide. 53 * </p> 54 * </div> 55 * 56 * @see Context#getSystemService 57 * @see BluetoothAdapter#getDefaultAdapter() 58 */ 59 @SystemService(Context.BLUETOOTH_SERVICE) 60 @RequiresFeature(PackageManager.FEATURE_BLUETOOTH) 61 public final class BluetoothManager { 62 private static final String TAG = "BluetoothManager"; 63 private static final boolean DBG = false; 64 65 private final AttributionSource mAttributionSource; 66 private final BluetoothAdapter mAdapter; 67 68 /** 69 * @hide 70 */ BluetoothManager(Context context)71 public BluetoothManager(Context context) { 72 mAttributionSource = resolveAttributionSource(context); 73 mAdapter = BluetoothAdapter.createAdapter(mAttributionSource); 74 } 75 76 /** {@hide} */ resolveAttributionSource(@ullable Context context)77 public static @NonNull AttributionSource resolveAttributionSource(@Nullable Context context) { 78 AttributionSource res = null; 79 if (context != null) { 80 res = context.getAttributionSource(); 81 } 82 if (res == null) { 83 res = ActivityThread.currentAttributionSource(); 84 } 85 if (res == null) { 86 int uid = android.os.Process.myUid(); 87 if (uid == android.os.Process.ROOT_UID) { 88 uid = android.os.Process.SYSTEM_UID; 89 } 90 try { 91 res = new AttributionSource(uid, 92 AppGlobals.getPackageManager().getPackagesForUid(uid)[0], null); 93 } catch (RemoteException ignored) { 94 } 95 } 96 if (res == null) { 97 throw new IllegalStateException("Failed to resolve AttributionSource"); 98 } 99 return res; 100 } 101 102 /** 103 * Get the BLUETOOTH Adapter for this device. 104 * 105 * @return the BLUETOOTH Adapter 106 */ 107 @RequiresNoPermission getAdapter()108 public BluetoothAdapter getAdapter() { 109 return mAdapter; 110 } 111 112 /** 113 * Get the current connection state of the profile to the remote device. 114 * 115 * <p>This is not specific to any application configuration but represents 116 * the connection state of the local Bluetooth adapter for certain profile. 117 * This can be used by applications like status bar which would just like 118 * to know the state of Bluetooth. 119 * 120 * @param device Remote bluetooth device. 121 * @param profile GATT or GATT_SERVER 122 * @return State of the profile connection. One of {@link BluetoothProfile#STATE_CONNECTED}, 123 * {@link BluetoothProfile#STATE_CONNECTING}, {@link BluetoothProfile#STATE_DISCONNECTED}, 124 * {@link BluetoothProfile#STATE_DISCONNECTING} 125 */ 126 @RequiresLegacyBluetoothPermission 127 @RequiresBluetoothConnectPermission 128 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) getConnectionState(BluetoothDevice device, int profile)129 public int getConnectionState(BluetoothDevice device, int profile) { 130 if (DBG) Log.d(TAG, "getConnectionState()"); 131 132 List<BluetoothDevice> connectedDevices = getConnectedDevices(profile); 133 for (BluetoothDevice connectedDevice : connectedDevices) { 134 if (device.equals(connectedDevice)) { 135 return BluetoothProfile.STATE_CONNECTED; 136 } 137 } 138 139 return BluetoothProfile.STATE_DISCONNECTED; 140 } 141 142 /** 143 * Get connected devices for the specified profile. 144 * 145 * <p> Return the set of devices which are in state {@link BluetoothProfile#STATE_CONNECTED} 146 * 147 * <p>This is not specific to any application configuration but represents 148 * the connection state of Bluetooth for this profile. 149 * This can be used by applications like status bar which would just like 150 * to know the state of Bluetooth. 151 * 152 * @param profile GATT or GATT_SERVER 153 * @return List of devices. The list will be empty on error. 154 */ 155 @RequiresLegacyBluetoothPermission 156 @RequiresBluetoothConnectPermission 157 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) getConnectedDevices(int profile)158 public List<BluetoothDevice> getConnectedDevices(int profile) { 159 if (DBG) Log.d(TAG, "getConnectedDevices"); 160 return getDevicesMatchingConnectionStates(profile, new int[] { 161 BluetoothProfile.STATE_CONNECTED 162 }); 163 } 164 165 /** 166 * Get a list of devices that match any of the given connection 167 * states. 168 * 169 * <p> If none of the devices match any of the given states, 170 * an empty list will be returned. 171 * 172 * <p>This is not specific to any application configuration but represents 173 * the connection state of the local Bluetooth adapter for this profile. 174 * This can be used by applications like status bar which would just like 175 * to know the state of the local adapter. 176 * 177 * @param profile GATT or GATT_SERVER 178 * @param states Array of states. States can be one of {@link BluetoothProfile#STATE_CONNECTED}, 179 * {@link BluetoothProfile#STATE_CONNECTING}, {@link BluetoothProfile#STATE_DISCONNECTED}, 180 * {@link BluetoothProfile#STATE_DISCONNECTING}, 181 * @return List of devices. The list will be empty on error. 182 */ 183 @RequiresLegacyBluetoothPermission 184 @RequiresBluetoothConnectPermission 185 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) getDevicesMatchingConnectionStates(int profile, int[] states)186 public List<BluetoothDevice> getDevicesMatchingConnectionStates(int profile, int[] states) { 187 if (DBG) Log.d(TAG, "getDevicesMatchingConnectionStates"); 188 189 if (profile != BluetoothProfile.GATT && profile != BluetoothProfile.GATT_SERVER) { 190 throw new IllegalArgumentException("Profile not supported: " + profile); 191 } 192 193 List<BluetoothDevice> devices = new ArrayList<BluetoothDevice>(); 194 195 try { 196 IBluetoothManager managerService = mAdapter.getBluetoothManager(); 197 IBluetoothGatt iGatt = managerService.getBluetoothGatt(); 198 if (iGatt == null) return devices; 199 devices = Attributable.setAttributionSource( 200 iGatt.getDevicesMatchingConnectionStates(states, mAttributionSource), 201 mAttributionSource); 202 } catch (RemoteException e) { 203 Log.e(TAG, "", e); 204 } 205 206 return devices; 207 } 208 209 /** 210 * Open a GATT Server 211 * The callback is used to deliver results to Caller, such as connection status as well 212 * as the results of any other GATT server operations. 213 * The method returns a BluetoothGattServer instance. You can use BluetoothGattServer 214 * to conduct GATT server operations. 215 * 216 * @param context App context 217 * @param callback GATT server callback handler that will receive asynchronous callbacks. 218 * @return BluetoothGattServer instance 219 */ 220 @RequiresBluetoothConnectPermission 221 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) openGattServer(Context context, BluetoothGattServerCallback callback)222 public BluetoothGattServer openGattServer(Context context, 223 BluetoothGattServerCallback callback) { 224 225 return (openGattServer(context, callback, BluetoothDevice.TRANSPORT_AUTO)); 226 } 227 228 /** 229 * Open a GATT Server 230 * The callback is used to deliver results to Caller, such as connection status as well 231 * as the results of any other GATT server operations. 232 * The method returns a BluetoothGattServer instance. You can use BluetoothGattServer 233 * to conduct GATT server operations. 234 * 235 * @param context App context 236 * @param callback GATT server callback handler that will receive asynchronous callbacks. 237 * @param eatt_support idicates if server should use eatt channel for notifications. 238 * @return BluetoothGattServer instance 239 * @hide 240 */ 241 @RequiresBluetoothConnectPermission 242 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) openGattServer(Context context, BluetoothGattServerCallback callback, boolean eatt_support)243 public BluetoothGattServer openGattServer(Context context, 244 BluetoothGattServerCallback callback, boolean eatt_support) { 245 return (openGattServer(context, callback, BluetoothDevice.TRANSPORT_AUTO, eatt_support)); 246 } 247 248 /** 249 * Open a GATT Server 250 * The callback is used to deliver results to Caller, such as connection status as well 251 * as the results of any other GATT server operations. 252 * The method returns a BluetoothGattServer instance. You can use BluetoothGattServer 253 * to conduct GATT server operations. 254 * 255 * @param context App context 256 * @param callback GATT server callback handler that will receive asynchronous callbacks. 257 * @param transport preferred transport for GATT connections to remote dual-mode devices {@link 258 * BluetoothDevice#TRANSPORT_AUTO} or {@link BluetoothDevice#TRANSPORT_BREDR} or {@link 259 * BluetoothDevice#TRANSPORT_LE} 260 * @return BluetoothGattServer instance 261 * @hide 262 */ 263 @RequiresBluetoothConnectPermission 264 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) openGattServer(Context context, BluetoothGattServerCallback callback, int transport)265 public BluetoothGattServer openGattServer(Context context, 266 BluetoothGattServerCallback callback, int transport) { 267 return (openGattServer(context, callback, transport, false)); 268 } 269 270 /** 271 * Open a GATT Server 272 * The callback is used to deliver results to Caller, such as connection status as well 273 * as the results of any other GATT server operations. 274 * The method returns a BluetoothGattServer instance. You can use BluetoothGattServer 275 * to conduct GATT server operations. 276 * 277 * @param context App context 278 * @param callback GATT server callback handler that will receive asynchronous callbacks. 279 * @param transport preferred transport for GATT connections to remote dual-mode devices {@link 280 * BluetoothDevice#TRANSPORT_AUTO} or {@link BluetoothDevice#TRANSPORT_BREDR} or {@link 281 * BluetoothDevice#TRANSPORT_LE} 282 * @param eatt_support idicates if server should use eatt channel for notifications. 283 * @return BluetoothGattServer instance 284 * @hide 285 */ 286 @RequiresBluetoothConnectPermission 287 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) openGattServer(Context context, BluetoothGattServerCallback callback, int transport, boolean eatt_support)288 public BluetoothGattServer openGattServer(Context context, 289 BluetoothGattServerCallback callback, int transport, boolean eatt_support) { 290 if (context == null || callback == null) { 291 throw new IllegalArgumentException("null parameter: " + context + " " + callback); 292 } 293 294 // TODO(Bluetooth) check whether platform support BLE 295 // Do the check here or in GattServer? 296 297 try { 298 IBluetoothManager managerService = mAdapter.getBluetoothManager(); 299 IBluetoothGatt iGatt = managerService.getBluetoothGatt(); 300 if (iGatt == null) { 301 Log.e(TAG, "Fail to get GATT Server connection"); 302 return null; 303 } 304 BluetoothGattServer mGattServer = 305 new BluetoothGattServer(iGatt, transport, mAdapter); 306 Boolean regStatus = mGattServer.registerCallback(callback, eatt_support); 307 return regStatus ? mGattServer : null; 308 } catch (RemoteException e) { 309 Log.e(TAG, "", e); 310 return null; 311 } 312 } 313 } 314