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