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