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 com.android.cts.verifier.bluetooth;
18 
19 import android.app.Service;
20 import android.bluetooth.BluetoothAdapter;
21 import android.bluetooth.BluetoothDevice;
22 import android.bluetooth.BluetoothGatt;
23 import android.bluetooth.BluetoothGattCallback;
24 import android.bluetooth.BluetoothGattCharacteristic;
25 import android.bluetooth.BluetoothGattDescriptor;
26 import android.bluetooth.BluetoothGattService;
27 import android.bluetooth.BluetoothManager;
28 import android.bluetooth.BluetoothProfile;
29 import android.bluetooth.le.BluetoothLeScanner;
30 import android.bluetooth.le.ScanCallback;
31 import android.bluetooth.le.ScanFilter;
32 import android.bluetooth.le.ScanResult;
33 import android.bluetooth.le.ScanSettings;
34 import android.content.BroadcastReceiver;
35 import android.content.Context;
36 import android.content.Intent;
37 import android.content.IntentFilter;
38 import android.os.Build;
39 import android.os.Handler;
40 import android.os.IBinder;
41 import android.os.ParcelUuid;
42 import android.text.TextUtils;
43 import android.util.Log;
44 import android.widget.Toast;
45 
46 import com.android.cts.verifier.R;
47 
48 import java.util.Arrays;
49 import java.util.List;
50 import java.util.Set;
51 import java.util.UUID;
52 
53 public class BleClientService extends Service {
54 
55     public static final boolean DEBUG = true;
56     public static final String TAG = "BleClientService";
57 
58     // Android N (2016 July 15, currently) BluetoothGatt#disconnect() does not work correct.
59     // (termination signal will not be sent)
60     // This flag switches to turn Bluetooth off instead of BluetoothGatt#disconnect().
61     // If true, test will turn Bluetooth off. Otherwise, will call BluetoothGatt#disconnect().
62     public static final boolean DISCONNECT_BY_TURN_BT_OFF_ON = (Build.VERSION.SDK_INT > Build.VERSION_CODES.M);
63 
64     // for Version 1 test
65 //    private static final int TRANSPORT_MODE_FOR_SECURE_CONNECTION = BluetoothDevice.TRANSPORT_AUTO;
66     // for Version 2 test
67     private static final int TRANSPORT_MODE_FOR_SECURE_CONNECTION = BluetoothDevice.TRANSPORT_LE;
68 
69     public static final int COMMAND_CONNECT = 0;
70     public static final int COMMAND_DISCONNECT = 1;
71     public static final int COMMAND_DISCOVER_SERVICE = 2;
72     public static final int COMMAND_READ_RSSI = 3;
73     public static final int COMMAND_WRITE_CHARACTERISTIC = 4;
74     public static final int COMMAND_WRITE_CHARACTERISTIC_BAD_RESP = 5;
75     public static final int COMMAND_READ_CHARACTERISTIC = 6;
76     public static final int COMMAND_WRITE_DESCRIPTOR = 7;
77     public static final int COMMAND_READ_DESCRIPTOR = 8;
78     public static final int COMMAND_SET_NOTIFICATION = 9;
79     public static final int COMMAND_BEGIN_WRITE = 10;
80     public static final int COMMAND_EXECUTE_WRITE = 11;
81     public static final int COMMAND_ABORT_RELIABLE = 12;
82     public static final int COMMAND_SCAN_START = 13;
83     public static final int COMMAND_SCAN_STOP = 14;
84 
85     public static final String BLE_BLUETOOTH_MISMATCH_SECURE =
86             "com.android.cts.verifier.bluetooth.BLE_BLUETOOTH_MISMATCH_SECURE";
87     public static final String BLE_BLUETOOTH_MISMATCH_INSECURE =
88             "com.android.cts.verifier.bluetooth.BLE_BLUETOOTH_MISMATCH_INSECURE";
89     public static final String BLE_BLUETOOTH_DISABLED =
90             "com.android.cts.verifier.bluetooth.BLE_BLUETOOTH_DISABLED";
91     public static final String BLE_BLUETOOTH_CONNECTED =
92             "com.android.cts.verifier.bluetooth.BLE_BLUETOOTH_CONNECTED";
93     public static final String BLE_BLUETOOTH_DISCONNECTED =
94             "com.android.cts.verifier.bluetooth.BLE_BLUETOOTH_DISCONNECTED";
95     public static final String BLE_SERVICES_DISCOVERED =
96             "com.android.cts.verifier.bluetooth.BLE_SERVICES_DISCOVERED";
97     public static final String BLE_MTU_CHANGED_23BYTES =
98             "com.android.cts.verifier.bluetooth.BLE_MTU_CHANGED_23BYTES";
99     public static final String BLE_MTU_CHANGED_512BYTES =
100             "com.android.cts.verifier.bluetooth.BLE_MTU_CHANGED_512BYTES";
101     public static final String BLE_CHARACTERISTIC_READ =
102             "com.android.cts.verifier.bluetooth.BLE_CHARACTERISTIC_READ";
103     public static final String BLE_CHARACTERISTIC_WRITE =
104             "com.android.cts.verifier.bluetooth.BLE_CHARACTERISTIC_WRITE";
105     public static final String BLE_CHARACTERISTIC_CHANGED =
106             "com.android.cts.verifier.bluetooth.BLE_CHARACTERISTIC_CHANGED";
107     public static final String BLE_CHARACTERISTIC_INDICATED =
108             "com.android.cts.verifier.bluetooth.BLE_CHARACTERISTIC_INDICATED";
109     public static final String BLE_DESCRIPTOR_READ =
110             "com.android.cts.verifier.bluetooth.BLE_DESCRIPTOR_READ";
111     public static final String BLE_DESCRIPTOR_WRITE =
112             "com.android.cts.verifier.bluetooth.BLE_DESCRIPTOR_WRITE";
113     public static final String BLE_RELIABLE_WRITE_COMPLETED =
114             "com.android.cts.verifier.bluetooth.BLE_RELIABLE_WRITE_COMPLETED";
115     public static final String BLE_RELIABLE_WRITE_BAD_RESP_COMPLETED =
116             "com.android.cts.verifier.bluetooth.BLE_RELIABLE_WRITE_BAD_RESP_COMPLETED";
117     public static final String BLE_READ_REMOTE_RSSI =
118             "com.android.cts.verifier.bluetooth.BLE_READ_REMOTE_RSSI";
119     public static final String BLE_ON_SERVICE_CHANGED =
120             "com.android.cts.verifier.bluetooth.BLE_ON_SERVICE_CHANGED";
121     public static final String BLE_CHARACTERISTIC_READ_NOPERMISSION =
122             "com.android.cts.verifier.bluetooth.BLE_CHARACTERISTIC_READ_NOPERMISSION";
123     public static final String BLE_CHARACTERISTIC_WRITE_NOPERMISSION =
124             "com.android.cts.verifier.bluetooth.BLE_CHARACTERISTIC_WRITE_NOPERMISSION";
125     public static final String BLE_DESCRIPTOR_READ_NOPERMISSION =
126             "com.android.cts.verifier.bluetooth.BLE_DESCRIPTOR_READ_NOPERMISSION";
127     public static final String BLE_DESCRIPTOR_WRITE_NOPERMISSION =
128             "com.android.cts.verifier.bluetooth.BLE_DESCRIPTOR_WRITE_NOPERMISSION";
129     public static final String BLE_CHARACTERISTIC_READ_NEED_ENCRYPTED =
130             "com.android.cts.verifier.bluetooth.BLE_CHARACTERISTIC_READ_NEED_ENCRYPTED";
131     public static final String BLE_CHARACTERISTIC_WRITE_NEED_ENCRYPTED =
132             "com.android.cts.verifier.bluetooth.BLE_CHARACTERISTIC_WRITE_NEED_ENCRYPTED";
133     public static final String BLE_DESCRIPTOR_READ_NEED_ENCRYPTED =
134             "com.android.cts.verifier.bluetooth.BLE_DESCRIPTOR_READ_NEED_ENCRYPTED";
135     public static final String BLE_DESCRIPTOR_WRITE_NEED_ENCRYPTED =
136             "com.android.cts.verifier.bluetooth.BLE_DESCRIPTOR_WRITE_NEED_ENCRYPTED";
137     public static final String BLE_CLIENT_ERROR =
138             "com.android.cts.verifier.bluetooth.BLE_CLIENT_ERROR";
139 
140     public static final String EXTRA_COMMAND =
141             "com.android.cts.verifier.bluetooth.EXTRA_COMMAND";
142     public static final String EXTRA_WRITE_VALUE =
143             "com.android.cts.verifier.bluetooth.EXTRA_WRITE_VALUE";
144     public static final String EXTRA_BOOL =
145             "com.android.cts.verifier.bluetooth.EXTRA_BOOL";
146 
147 
148     // Literal for Client Action
149     public static final String BLE_CLIENT_ACTION_CLIENT_CONNECT =
150             "com.android.cts.verifier.bluetooth.BLE_CLIENT_ACTION_CLIENT_CONNECT";
151     public static final String BLE_CLIENT_ACTION_CLIENT_CONNECT_SECURE =
152             "com.android.cts.verifier.bluetooth.BLE_CLIENT_ACTION_CLIENT_CONNECT_SECURE";
153     public static final String BLE_CLIENT_ACTION_BLE_DISCOVER_SERVICE =
154             "com.android.cts.verifier.bluetooth.BLE_CLIENT_ACTION_BLE_DISCOVER_SERVICE";
155     public static final String BLE_CLIENT_ACTION_REQUEST_MTU_23 =
156             "com.android.cts.verifier.bluetooth.BLE_CLIENT_ACTION_REQUEST_MTU_23";
157     public static final String BLE_CLIENT_ACTION_REQUEST_MTU_512 =
158             "com.android.cts.verifier.bluetooth.BLE_CLIENT_ACTION_REQUEST_MTU_512";
159     public static final String BLE_CLIENT_ACTION_READ_CHARACTERISTIC =
160             "com.android.cts.verifier.bluetooth.BLE_CLIENT_ACTION_READ_CHARACTERISTIC";
161     public static final String BLE_CLIENT_ACTION_WRITE_CHARACTERISTIC =
162             "com.android.cts.verifier.bluetooth.BLE_CLIENT_ACTION_WRITE_CHARACTERISTIC";
163     public static final String BLE_CLIENT_ACTION_RELIABLE_WRITE =
164             "com.android.cts.verifier.bluetooth.BLE_CLIENT_ACTION_RELIABLE_WRITE";
165     public static final String BLE_CLIENT_ACTION_RELIABLE_WRITE_BAD_RESP =
166             "com.android.cts.verifier.bluetooth.BLE_CLIENT_ACTION_RELIABLE_WRITE_BAD_RESP";
167     public static final String BLE_CLIENT_ACTION_NOTIFY_CHARACTERISTIC =
168             "com.android.cts.verifier.bluetooth.BLE_CLIENT_ACTION_NOTIFY_CHARACTERISTIC";
169     public static final String BLE_CLIENT_ACTION_INDICATE_CHARACTERISTIC =
170             "com.android.cts.verifier.bluetooth.BLE_CLIENT_ACTION_INDICATE_CHARACTERISTIC";
171     public static final String BLE_CLIENT_ACTION_READ_DESCRIPTOR =
172             "com.android.cts.verifier.bluetooth.BLE_CLIENT_ACTION_READ_DESCRIPTOR";
173     public static final String BLE_CLIENT_ACTION_WRITE_DESCRIPTOR =
174             "com.android.cts.verifier.bluetooth.BLE_CLIENT_ACTION_WRITE_DESCRIPTOR";
175     public static final String BLE_CLIENT_ACTION_READ_RSSI =
176             "com.android.cts.verifier.bluetooth.BLE_CLIENT_ACTION_READ_RSSI";
177     public static final String BLE_CLIENT_ACTION_TRIGGER_SERVICE_CHANGED =
178             "com.android.cts.verifier.bluetooth.BLE_CLIENT_ACTION_TRIGGER_SERVICE_CHANGED";
179     public static final String BLE_CLIENT_ACTION_CLIENT_DISCONNECT =
180             "com.android.cts.verifier.bluetooth.BLE_CLIENT_ACTION_CLIENT_DISCONNECT";
181     public static final String BLE_CLIENT_ACTION_READ_CHARACTERISTIC_NO_PERMISSION =
182             "com.android.cts.verifier.bluetooth.BLE_CLIENT_ACTION_READ_CHARACTERISTIC_NO_PERMISSION";
183     public static final String BLE_CLIENT_ACTION_WRITE_CHARACTERISTIC_NO_PERMISSION =
184             "com.android.cts.verifier.bluetooth.BLE_CLIENT_ACTION_WRITE_CHARACTERISTIC_NO_PERMISSION";
185     public static final String BLE_CLIENT_ACTION_READ_DESCRIPTOR_NO_PERMISSION =
186             "com.android.cts.verifier.bluetooth.BLE_CLIENT_ACTION_READ_DESCRIPTOR_NO_PERMISSION";
187     public static final String BLE_CLIENT_ACTION_WRITE_DESCRIPTOR_NO_PERMISSION =
188             "com.android.cts.verifier.bluetooth.BLE_CLIENT_ACTION_WRITE_DESCRIPTOR_NO_PERMISSION";
189     public static final String BLE_CLIENT_ACTION_READ_AUTHENTICATED_CHARACTERISTIC =
190             "com.android.cts.verifier.bluetooth.BLE_CLIENT_ACTION_READ_AUTHENTICATED_CHARACTERISTIC";
191     public static final String BLE_CLIENT_ACTION_WRITE_AUTHENTICATED_CHARACTERISTIC =
192             "com.android.cts.verifier.bluetooth.BLE_CLIENT_ACTION_WRITE_AUTHENTICATED_CHARACTERISTIC";
193     public static final String BLE_CLIENT_ACTION_READ_AUTHENTICATED_DESCRIPTOR =
194             "com.android.cts.verifier.bluetooth.BLE_CLIENT_ACTION_READ_AUTHENTICATED_DESCRIPTOR";
195     public static final String BLE_CLIENT_ACTION_WRITE_AUTHENTICATED_DESCRIPTOR =
196             "com.android.cts.verifier.bluetooth.BLE_CLIENT_ACTION_WRITE_AUTHENTICATED_DESCRIPTOR";
197 
198     public static final String EXTRA_CHARACTERISTIC_VALUE =
199             "com.android.cts.verifier.bluetooth.EXTRA_CHARACTERISTIC_VALUE";
200     public static final String EXTRA_DESCRIPTOR_VALUE =
201             "com.android.cts.verifier.bluetooth.EXTRA_DESCRIPTOR_VALUE";
202     public static final String EXTRA_RSSI_VALUE =
203             "com.android.cts.verifier.bluetooth.EXTRA_RSSI_VALUE";
204     public static final String EXTRA_ERROR_MESSAGE =
205             "com.android.cts.verifier.bluetooth.EXTRA_ERROR_MESSAGE";
206 
207     public static final String WRITE_VALUE_512BYTES_FOR_MTU = createTestData(512);
208     public static final String WRITE_VALUE_507BYTES_FOR_RELIABLE_WRITE = createTestData(507);
209 
210     private static final UUID SERVICE_UUID =
211             UUID.fromString("00009999-0000-1000-8000-00805f9b34fb");
212     private static final UUID CHARACTERISTIC_UUID =
213             UUID.fromString("00009998-0000-1000-8000-00805f9b34fb");
214     private static final UUID CHARACTERISTIC_RESULT_UUID =
215             UUID.fromString("00009974-0000-1000-8000-00805f9b34fb");
216     private static final UUID UPDATE_CHARACTERISTIC_UUID =
217             UUID.fromString("00009997-0000-1000-8000-00805f9b34fb");
218     private static final UUID DESCRIPTOR_UUID =
219             UUID.fromString("00009996-0000-1000-8000-00805f9b34fb");
220 
221     private static final UUID SERVICE_UUID_ADDITIONAL =
222             UUID.fromString("00009995-0000-1000-8000-00805f9b34fb");
223 
224     // Literal for registration permission of Characteristic
225     private static final UUID CHARACTERISTIC_NO_READ_UUID =
226             UUID.fromString("00009984-0000-1000-8000-00805f9b34fb");
227     private static final UUID CHARACTERISTIC_NO_WRITE_UUID =
228             UUID.fromString("00009983-0000-1000-8000-00805f9b34fb");
229     private static final UUID CHARACTERISTIC_NEED_ENCRYPTED_READ_UUID =
230             UUID.fromString("00009982-0000-1000-8000-00805f9b34fb");
231     private static final UUID CHARACTERISTIC_NEED_ENCRYPTED_WRITE_UUID =
232             UUID.fromString("00009981-0000-1000-8000-00805f9b34fb");
233 
234     // Literal for registration permission of Descriptor
235     private static final UUID DESCRIPTOR_NO_READ_UUID =
236             UUID.fromString("00009973-0000-1000-8000-00805f9b34fb");
237     private static final UUID DESCRIPTOR_NO_WRITE_UUID =
238             UUID.fromString("00009972-0000-1000-8000-00805f9b34fb");
239     private static final UUID DESCRIPTOR_NEED_ENCRYPTED_READ_UUID =
240             UUID.fromString("00009969-0000-1000-8000-00805f9b34fb");
241     private static final UUID DESCRIPTOR_NEED_ENCRYPTED_WRITE_UUID =
242             UUID.fromString("00009968-0000-1000-8000-00805f9b34fb");
243 
244     //  Literal for registration upper limit confirmation of Characteristic
245     private static final UUID UPDATE_CHARACTERISTIC_UUID_1 =
246             UUID.fromString("00009989-0000-1000-8000-00805f9b34fb");
247     private static final UUID UPDATE_CHARACTERISTIC_UUID_2 =
248             UUID.fromString("00009988-0000-1000-8000-00805f9b34fb");
249     private static final UUID UPDATE_CHARACTERISTIC_UUID_3 =
250             UUID.fromString("00009987-0000-1000-8000-00805f9b34fb");
251     private static final UUID UPDATE_CHARACTERISTIC_UUID_4 =
252             UUID.fromString("00009986-0000-1000-8000-00805f9b34fb");
253     private static final UUID UPDATE_CHARACTERISTIC_UUID_5 =
254             UUID.fromString("00009985-0000-1000-8000-00805f9b34fb");
255     private static final UUID UPDATE_CHARACTERISTIC_UUID_6 =
256             UUID.fromString("00009979-0000-1000-8000-00805f9b34fb");
257     private static final UUID UPDATE_CHARACTERISTIC_UUID_7 =
258             UUID.fromString("00009978-0000-1000-8000-00805f9b34fb");
259     private static final UUID UPDATE_CHARACTERISTIC_UUID_8 =
260             UUID.fromString("00009977-0000-1000-8000-00805f9b34fb");
261     private static final UUID UPDATE_CHARACTERISTIC_UUID_9 =
262             UUID.fromString("00009976-0000-1000-8000-00805f9b34fb");
263     private static final UUID UPDATE_CHARACTERISTIC_UUID_10 =
264             UUID.fromString("00009975-0000-1000-8000-00805f9b34fb");
265     private static final UUID UPDATE_CHARACTERISTIC_UUID_11 =
266             UUID.fromString("00009959-0000-1000-8000-00805f9b34fb");
267     private static final UUID UPDATE_CHARACTERISTIC_UUID_12 =
268             UUID.fromString("00009958-0000-1000-8000-00805f9b34fb");
269     private static final UUID UPDATE_CHARACTERISTIC_UUID_13 =
270             UUID.fromString("00009957-0000-1000-8000-00805f9b34fb");
271     private static final UUID UPDATE_CHARACTERISTIC_UUID_14 =
272             UUID.fromString("00009956-0000-1000-8000-00805f9b34fb");
273     private static final UUID UPDATE_CHARACTERISTIC_UUID_15 =
274             UUID.fromString("00009955-0000-1000-8000-00805f9b34fb");
275 
276     private static final UUID SERVICE_CHANGED_CONTROL_CHARACTERISTIC_UUID =
277         UUID.fromString("00009949-0000-1000-8000-00805f9b34fb");
278 
279     private static final UUID UPDATE_DESCRIPTOR_UUID =
280             UUID.fromString("00002902-0000-1000-8000-00805f9b34fb");
281 
282     private static final UUID INDICATE_CHARACTERISTIC_UUID =
283             UUID.fromString("00009971-0000-1000-8000-00805f9b34fb");
284 
285     public static final String WRITE_VALUE = "CLIENT_TEST";
286     private static final String NOTIFY_VALUE = "NOTIFY_TEST";
287     public static final String WRITE_VALUE_BAD_RESP = "BAD_RESP_TEST";
288     public static final String SERVICE_CHANGED_VALUE = "CLIENT_SVC_CHG";
289 
290     // current test category
291     private String mCurrentAction;
292 
293     private BluetoothManager mBluetoothManager;
294     private BluetoothAdapter mBluetoothAdapter;
295     private BluetoothDevice mDevice;
296     private BluetoothGatt mBluetoothGatt;
297     private BluetoothLeScanner mScanner;
298     private Handler mHandler;
299     private Context mContext;
300     private boolean mSecure;
301     private int mNotifyCount;
302     private boolean mValidityService;
303     private ReliableWriteState mExecReliableWrite;
304     private byte[] mBuffer;
305 
306     // Handler for communicating task with peer.
307     private TestTaskQueue mTaskQueue;
308 
309     // Lock for synchronization during notification request test.
310     private final Object mRequestNotificationLock = new Object();
311 
312     // Lock for triggering service changed event on server side.
313     private final Object mServiceChangedLock = new Object();
314     private static final int SERVICE_CHANGED_FLAG_INIT = 0x00;
315     private static final int SERVICE_CHANGED_FLAG_TRIGGER_ACTION = 0x01;
316     private static final int SERVICE_CHANGED_FLAG_ON_SERVICE_CHANGED = 0x02;
317     private static final int SERVICE_CHANGED_FLAG_ALL = 0x03;
318     private static final int SERVOCE_CHANGED_FLAG_IGNORE = 0xFF;
319     private int mServiceChangedFlag;
320 
321     private enum ReliableWriteState {
322         RELIABLE_WRITE_NONE,
323         RELIABLE_WRITE_WRITE_1ST_DATA,
324         RELIABLE_WRITE_WRITE_2ND_DATA,
325         RELIABLE_WRITE_EXECUTE,
326         RELIABLE_WRITE_BAD_RESP
327     }
328 
329     @Override
onCreate()330     public void onCreate() {
331         super.onCreate();
332 
333         registerReceiver(mBondStatusReceiver, new IntentFilter(BluetoothDevice.ACTION_BOND_STATE_CHANGED));
334 
335         mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
336         mBluetoothAdapter = mBluetoothManager.getAdapter();
337         mScanner = mBluetoothAdapter.getBluetoothLeScanner();
338         mHandler = new Handler();
339         mContext = this;
340         mNotifyCount = 0;
341 
342         mTaskQueue = new TestTaskQueue(getClass().getName() + "_taskHandlerThread");
343     }
344 
345     @Override
onStartCommand(final Intent intent, int flags, int startId)346     public int onStartCommand(final Intent intent, int flags, int startId) {
347         if (!mBluetoothAdapter.isEnabled()) {
348             notifyBluetoothDisabled();
349         } else {
350             mTaskQueue.addTask(new Runnable() {
351                 @Override
352                 public void run() {
353                     onTestFinish(intent.getAction());
354                 }
355             }, 1500);
356         }
357         return START_NOT_STICKY;
358     }
359 
onTestFinish(String action)360     private void onTestFinish(String action) {
361         mCurrentAction = action;
362         if (mCurrentAction != null) {
363             switch (mCurrentAction) {
364                 case BLE_CLIENT_ACTION_CLIENT_CONNECT_SECURE:
365                     mSecure = true;
366                     mExecReliableWrite = ReliableWriteState.RELIABLE_WRITE_NONE;
367                     startScan();
368                     break;
369                 case BLE_CLIENT_ACTION_CLIENT_CONNECT:
370                     mExecReliableWrite = ReliableWriteState.RELIABLE_WRITE_NONE;
371                     startScan();
372                     break;
373                 case BLE_CLIENT_ACTION_BLE_DISCOVER_SERVICE:
374                     if (mBluetoothGatt != null && mBleState == BluetoothProfile.STATE_CONNECTED) {
375                         mBluetoothGatt.discoverServices();
376                     } else {
377                         showMessage("Bluetooth LE not cnnected.");
378                     }
379                     break;
380                 case BLE_CLIENT_ACTION_REQUEST_MTU_23:
381                 case BLE_CLIENT_ACTION_REQUEST_MTU_512: // fall through
382                     requestMtu();
383                     break;
384                 case BLE_CLIENT_ACTION_READ_CHARACTERISTIC:
385                     readCharacteristic(CHARACTERISTIC_UUID);
386                     break;
387                 case BLE_CLIENT_ACTION_WRITE_CHARACTERISTIC:
388                     writeCharacteristic(CHARACTERISTIC_UUID, WRITE_VALUE);
389                     break;
390                 case BLE_CLIENT_ACTION_RELIABLE_WRITE:
391                 case BLE_CLIENT_ACTION_RELIABLE_WRITE_BAD_RESP: // fall through
392                     mTaskQueue.addTask(new Runnable() {
393                         @Override
394                         public void run() {
395                             reliableWrite();
396                         }
397                     });
398                 break;
399                 case BLE_CLIENT_ACTION_INDICATE_CHARACTERISTIC:
400                     setNotification(INDICATE_CHARACTERISTIC_UUID, true);
401                     break;
402                 case BLE_CLIENT_ACTION_NOTIFY_CHARACTERISTIC:
403                     // Registered the notify to characteristics in the service
404                     mTaskQueue.addTask(new Runnable() {
405                         @Override
406                         public void run() {
407                             mNotifyCount = 16;
408                             setNotification(UPDATE_CHARACTERISTIC_UUID, true);
409                             waitForDisableNotificationCompletion();
410                             setNotification(SERVICE_UUID_ADDITIONAL, UPDATE_CHARACTERISTIC_UUID_1, true);
411                             waitForDisableNotificationCompletion();
412                             setNotification(SERVICE_UUID_ADDITIONAL, UPDATE_CHARACTERISTIC_UUID_2, true);
413                             waitForDisableNotificationCompletion();
414                             setNotification(SERVICE_UUID_ADDITIONAL, UPDATE_CHARACTERISTIC_UUID_3, true);
415                             waitForDisableNotificationCompletion();
416                             setNotification(SERVICE_UUID_ADDITIONAL, UPDATE_CHARACTERISTIC_UUID_4, true);
417                             waitForDisableNotificationCompletion();
418                             setNotification(SERVICE_UUID_ADDITIONAL, UPDATE_CHARACTERISTIC_UUID_5, true);
419                             waitForDisableNotificationCompletion();
420                             setNotification(UPDATE_CHARACTERISTIC_UUID_6, true);
421                             waitForDisableNotificationCompletion();
422                             setNotification(UPDATE_CHARACTERISTIC_UUID_7, true);
423                             waitForDisableNotificationCompletion();
424                             setNotification(UPDATE_CHARACTERISTIC_UUID_8, true);
425                             waitForDisableNotificationCompletion();
426                             setNotification(UPDATE_CHARACTERISTIC_UUID_9, true);
427                             waitForDisableNotificationCompletion();
428                             setNotification(UPDATE_CHARACTERISTIC_UUID_10, true);
429                             waitForDisableNotificationCompletion();
430                             setNotification(SERVICE_UUID_ADDITIONAL, UPDATE_CHARACTERISTIC_UUID_11, true);
431                             waitForDisableNotificationCompletion();
432                             setNotification(SERVICE_UUID_ADDITIONAL, UPDATE_CHARACTERISTIC_UUID_12, true);
433                             waitForDisableNotificationCompletion();
434                             setNotification(SERVICE_UUID_ADDITIONAL, UPDATE_CHARACTERISTIC_UUID_13, true);
435                             waitForDisableNotificationCompletion();
436                             setNotification(SERVICE_UUID_ADDITIONAL, UPDATE_CHARACTERISTIC_UUID_14, true);
437                             waitForDisableNotificationCompletion();
438                             setNotification(SERVICE_UUID_ADDITIONAL, UPDATE_CHARACTERISTIC_UUID_15, true);
439                             waitForDisableNotificationCompletion();
440                         }
441                     });
442                 break;
443                 case BLE_CLIENT_ACTION_READ_DESCRIPTOR:
444                     readDescriptor(DESCRIPTOR_UUID);
445                     break;
446                 case BLE_CLIENT_ACTION_WRITE_DESCRIPTOR:
447                     writeDescriptor(DESCRIPTOR_UUID, WRITE_VALUE);
448                     break;
449                 case BLE_CLIENT_ACTION_READ_RSSI:
450                     if (mBluetoothGatt != null) {
451                         mBluetoothGatt.readRemoteRssi();
452                     }
453                     break;
454                 case BLE_CLIENT_ACTION_CLIENT_DISCONNECT:
455                     if (mBluetoothGatt != null) {
456                         mBluetoothGatt.disconnect();
457                     }
458                     break;
459                 case BLE_CLIENT_ACTION_READ_CHARACTERISTIC_NO_PERMISSION:
460                     readCharacteristic(CHARACTERISTIC_NO_READ_UUID);
461                     break;
462                 case BLE_CLIENT_ACTION_WRITE_CHARACTERISTIC_NO_PERMISSION:
463                     writeCharacteristic(CHARACTERISTIC_NO_WRITE_UUID, WRITE_VALUE);
464                     break;
465                 case BLE_CLIENT_ACTION_READ_DESCRIPTOR_NO_PERMISSION:
466                     readDescriptor(DESCRIPTOR_NO_READ_UUID);
467                     break;
468                 case BLE_CLIENT_ACTION_WRITE_DESCRIPTOR_NO_PERMISSION:
469                     writeDescriptor(DESCRIPTOR_NO_WRITE_UUID, WRITE_VALUE);
470                     break;
471                 case BLE_CLIENT_ACTION_READ_AUTHENTICATED_CHARACTERISTIC:
472                     readCharacteristic(CHARACTERISTIC_NEED_ENCRYPTED_READ_UUID);
473                     break;
474                 case BLE_CLIENT_ACTION_WRITE_AUTHENTICATED_CHARACTERISTIC:
475                     writeCharacteristic(CHARACTERISTIC_NEED_ENCRYPTED_WRITE_UUID, WRITE_VALUE);
476                     break;
477                 case BLE_CLIENT_ACTION_READ_AUTHENTICATED_DESCRIPTOR:
478                     readDescriptor(CHARACTERISTIC_RESULT_UUID, DESCRIPTOR_NEED_ENCRYPTED_READ_UUID);
479                     break;
480                 case BLE_CLIENT_ACTION_WRITE_AUTHENTICATED_DESCRIPTOR:
481                     writeDescriptor(CHARACTERISTIC_RESULT_UUID, DESCRIPTOR_NEED_ENCRYPTED_WRITE_UUID, WRITE_VALUE);
482                     break;
483                 case BLE_CLIENT_ACTION_TRIGGER_SERVICE_CHANGED:
484                     initializeServiceChangedEvent();
485                     writeCharacteristic(SERVICE_CHANGED_CONTROL_CHARACTERISTIC_UUID, WRITE_VALUE);
486                     break;
487             }
488         }
489     }
490 
491     @Override
onBind(Intent intent)492     public IBinder onBind(Intent intent) {
493         return null;
494     }
495 
496     @Override
onDestroy()497     public void onDestroy() {
498         super.onDestroy();
499         if (mBluetoothGatt != null) {
500             mBluetoothGatt.disconnect();
501             mBluetoothGatt.close();
502             mBluetoothGatt = null;
503         }
504         stopScan();
505         unregisterReceiver(mBondStatusReceiver);
506 
507         mTaskQueue.quit();
508     }
509 
connectGatt(BluetoothDevice device, Context context, boolean autoConnect, boolean isSecure, BluetoothGattCallback callback)510     public static BluetoothGatt connectGatt(BluetoothDevice device, Context context, boolean autoConnect, boolean isSecure, BluetoothGattCallback callback) {
511         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
512             if (isSecure) {
513                 if (TRANSPORT_MODE_FOR_SECURE_CONNECTION == BluetoothDevice.TRANSPORT_AUTO) {
514                     Toast.makeText(context, "connectGatt(transport=AUTO)", Toast.LENGTH_SHORT).show();
515                 } else {
516                     Toast.makeText(context, "connectGatt(transport=LE)", Toast.LENGTH_SHORT).show();
517                 }
518                 return device.connectGatt(context, autoConnect, callback, TRANSPORT_MODE_FOR_SECURE_CONNECTION);
519             } else {
520                 Toast.makeText(context, "connectGatt(transport=LE)", Toast.LENGTH_SHORT).show();
521                 return device.connectGatt(context, autoConnect, callback, BluetoothDevice.TRANSPORT_LE);
522             }
523         } else {
524             Toast.makeText(context, "connectGatt", Toast.LENGTH_SHORT).show();
525             return device.connectGatt(context, autoConnect, callback);
526         }
527     }
528 
requestMtu()529     private void requestMtu() {
530         if (mBluetoothGatt != null) {
531             // MTU request test does not work on Android 6.0 in secure mode.
532             // (BluetoothDevice#createBond() does not work on Android 6.0.
533             //  So devices can't establish Bluetooth LE pairing.)
534             boolean mtuTestExecutable = true;
535             if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.M) {
536                 mtuTestExecutable = !mSecure;
537             }
538 
539             if (mtuTestExecutable) {
540                 int mtu = 0;
541                 if (BLE_CLIENT_ACTION_REQUEST_MTU_23.equals(mCurrentAction)) {
542                     mtu = 23;
543                 } else if (BLE_CLIENT_ACTION_REQUEST_MTU_512.equals(mCurrentAction)) {
544                     mtu = 512;
545                 } else {
546                     throw new IllegalStateException("unexpected action: " + mCurrentAction);
547                 }
548                 mBluetoothGatt.requestMtu(mtu);
549             } else {
550                 showMessage("Skip MTU test.");
551                 notifyMtuChanged();
552             }
553         }
554     }
555 
writeCharacteristic(BluetoothGattCharacteristic characteristic, String writeValue)556     private void writeCharacteristic(BluetoothGattCharacteristic characteristic, String writeValue) {
557         if (characteristic != null) {
558             characteristic.setValue(writeValue);
559             mBluetoothGatt.writeCharacteristic(characteristic);
560         }
561     }
562 
writeCharacteristic(UUID uid, String writeValue)563     private void writeCharacteristic(UUID uid, String writeValue) {
564         BluetoothGattCharacteristic characteristic = getCharacteristic(uid);
565         if (characteristic != null){
566             writeCharacteristic(characteristic, writeValue);
567         }
568     }
569 
readCharacteristic(UUID uuid)570     private void readCharacteristic(UUID uuid) {
571         BluetoothGattCharacteristic characteristic = getCharacteristic(uuid);
572         if (characteristic != null) {
573             mBluetoothGatt.readCharacteristic(characteristic);
574         }
575     }
576 
writeDescriptor(UUID uid, String writeValue)577     private void writeDescriptor(UUID uid, String writeValue) {
578         BluetoothGattDescriptor descriptor = getDescriptor(uid);
579         if (descriptor != null) {
580             descriptor.setValue(writeValue.getBytes());
581             mBluetoothGatt.writeDescriptor(descriptor);
582         }
583     }
584 
readDescriptor(UUID uuid)585     private void readDescriptor(UUID uuid) {
586         BluetoothGattDescriptor descriptor = getDescriptor(uuid);
587         if (descriptor != null) {
588             mBluetoothGatt.readDescriptor(descriptor);
589         }
590     }
591 
writeDescriptor(UUID cuid, UUID duid, String writeValue)592     private void writeDescriptor(UUID cuid, UUID duid, String writeValue) {
593         BluetoothGattDescriptor descriptor = getDescriptor(cuid, duid);
594         if (descriptor != null) {
595             descriptor.setValue(writeValue.getBytes());
596             mBluetoothGatt.writeDescriptor(descriptor);
597         }
598     }
599 
readDescriptor(UUID cuid, UUID duid)600     private void readDescriptor(UUID cuid, UUID duid) {
601         BluetoothGattDescriptor descriptor = getDescriptor(cuid, duid);
602         if (descriptor != null) {
603             mBluetoothGatt.readDescriptor(descriptor);
604         }
605     }
606 
notifyDisableNotificationCompletion()607     private void notifyDisableNotificationCompletion() {
608         synchronized (mRequestNotificationLock) {
609             mRequestNotificationLock.notify();
610         }
611     }
612 
waitForDisableNotificationCompletion()613     private void waitForDisableNotificationCompletion() {
614         synchronized (mRequestNotificationLock) {
615             try {
616                 mRequestNotificationLock.wait();
617             } catch (InterruptedException e) {
618                 Log.e(TAG, "Error in waitForDisableNotificationCompletion" + e);
619             }
620         }
621     }
622 
initializeServiceChangedEvent()623     private void initializeServiceChangedEvent() {
624         synchronized (mServiceChangedLock) {
625             mServiceChangedFlag = SERVICE_CHANGED_FLAG_INIT;
626         }
627     }
628 
sendServiceChangedEventIfReady(int flag)629     private void sendServiceChangedEventIfReady(int flag) {
630         boolean shouldSend = false;
631         synchronized (mServiceChangedLock) {
632             mServiceChangedFlag |= flag;
633             if (mServiceChangedFlag == SERVICE_CHANGED_FLAG_ALL) {
634                 mServiceChangedFlag |= SERVOCE_CHANGED_FLAG_IGNORE;
635                 shouldSend = true;
636             }
637         }
638 
639         if (shouldSend) {
640             writeCharacteristic(getCharacteristic(CHARACTERISTIC_RESULT_UUID),
641                 SERVICE_CHANGED_VALUE);
642             notifyServiceChanged();
643         }
644     }
645 
setNotification(BluetoothGattCharacteristic characteristic, boolean enable)646     private void setNotification(BluetoothGattCharacteristic characteristic, boolean enable) {
647         if (characteristic != null) {
648             mBluetoothGatt.setCharacteristicNotification(characteristic, enable);
649             BluetoothGattDescriptor descriptor = characteristic.getDescriptor(UPDATE_DESCRIPTOR_UUID);
650             if (enable) {
651                 if (characteristic.getUuid().equals(INDICATE_CHARACTERISTIC_UUID)) {
652                     descriptor.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE);
653                 } else {
654                     descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
655                 }
656             } else {
657                 descriptor.setValue(BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE);
658             }
659             mBluetoothGatt.writeDescriptor(descriptor);
660         }
661     }
662 
setNotification(UUID serviceUid, UUID characteristicUid, boolean enable)663     private void setNotification(UUID serviceUid, UUID characteristicUid,  boolean enable) {
664         BluetoothGattCharacteristic characteristic = getCharacteristic(serviceUid, characteristicUid);
665         if (characteristic != null) {
666             setNotification(characteristic, enable);
667         }
668     }
669 
setNotification(UUID uid, boolean enable)670     private void setNotification(UUID uid, boolean enable) {
671         BluetoothGattCharacteristic characteristic = getCharacteristic(uid);
672         if (characteristic != null) {
673            setNotification(characteristic, enable);
674         }
675     }
676 
notifyError(String message)677     private void notifyError(String message) {
678         showMessage(message);
679         Log.i(TAG, message);
680 
681         Intent intent = new Intent(BLE_CLIENT_ERROR);
682         sendBroadcast(intent);
683     }
684 
notifyMismatchSecure()685     private void notifyMismatchSecure() {
686         Intent intent = new Intent(BLE_BLUETOOTH_MISMATCH_SECURE);
687         sendBroadcast(intent);
688     }
689 
notifyMismatchInsecure()690     private void notifyMismatchInsecure() {
691         Intent intent = new Intent(BLE_BLUETOOTH_MISMATCH_INSECURE);
692         sendBroadcast(intent);
693     }
694 
notifyBluetoothDisabled()695     private void notifyBluetoothDisabled() {
696         Intent intent = new Intent(BLE_BLUETOOTH_DISABLED);
697         sendBroadcast(intent);
698     }
699 
notifyConnected()700     private void notifyConnected() {
701         showMessage("Bluetooth LE connected");
702         Intent intent = new Intent(BLE_BLUETOOTH_CONNECTED);
703         sendBroadcast(intent);
704     }
705 
notifyDisconnected()706     private void notifyDisconnected() {
707         showMessage("Bluetooth LE disconnected");
708         Intent intent = new Intent(BLE_BLUETOOTH_DISCONNECTED);
709         sendBroadcast(intent);
710     }
711 
notifyServicesDiscovered()712     private void notifyServicesDiscovered() {
713         showMessage("Service discovered");
714         Intent intent = new Intent(BLE_SERVICES_DISCOVERED);
715         sendBroadcast(intent);
716     }
717 
notifyMtuChanged()718     private void notifyMtuChanged() {
719         Intent intent;
720         if (BLE_CLIENT_ACTION_REQUEST_MTU_23.equals(mCurrentAction)) {
721             intent = new Intent(BLE_MTU_CHANGED_23BYTES);
722         } else if (BLE_CLIENT_ACTION_REQUEST_MTU_512.equals(mCurrentAction)) {
723             intent = new Intent(BLE_MTU_CHANGED_512BYTES);
724         } else {
725             throw new IllegalStateException("unexpected action: " + mCurrentAction);
726         }
727         sendBroadcast(intent);
728     }
729 
notifyCharacteristicRead(String value)730     private void notifyCharacteristicRead(String value) {
731         showMessage("Characteristic read: " + value);
732         Intent intent = new Intent(BLE_CHARACTERISTIC_READ);
733         intent.putExtra(EXTRA_CHARACTERISTIC_VALUE, value);
734         sendBroadcast(intent);
735     }
736 
notifyCharacteristicWrite(String value)737     private void notifyCharacteristicWrite(String value) {
738         showMessage("Characteristic write: " + value);
739         Intent intent = new Intent(BLE_CHARACTERISTIC_WRITE);
740         sendBroadcast(intent);
741     }
742 
notifyCharacteristicReadNoPermission()743     private void notifyCharacteristicReadNoPermission() {
744         showMessage("Characteristic not read: No Permission");
745         Intent intent = new Intent(BLE_CHARACTERISTIC_READ_NOPERMISSION);
746         sendBroadcast(intent);
747     }
748 
notifyCharacteristicWriteNoPermission(String value)749     private void notifyCharacteristicWriteNoPermission(String value) {
750         showMessage("Characteristic write: No Permission");
751         Intent intent = new Intent(BLE_CHARACTERISTIC_WRITE_NOPERMISSION);
752         sendBroadcast(intent);
753     }
754 
notifyCharacteristicReadNeedEncrypted(String value)755     private void notifyCharacteristicReadNeedEncrypted(String value) {
756         showMessage("Characteristic read with encrypted: " + value);
757         Intent intent = new Intent(BLE_CHARACTERISTIC_READ_NEED_ENCRYPTED);
758         sendBroadcast(intent);
759     }
760 
notifyCharacteristicWriteNeedEncrypted(String value)761     private void notifyCharacteristicWriteNeedEncrypted(String value) {
762         showMessage("Characteristic write with encrypted: " + value);
763         Intent intent = new Intent(BLE_CHARACTERISTIC_WRITE_NEED_ENCRYPTED);
764         sendBroadcast(intent);
765     }
766 
notifyCharacteristicChanged()767     private void notifyCharacteristicChanged() {
768         showMessage("Characteristic changed");
769         Intent intent = new Intent(BLE_CHARACTERISTIC_CHANGED);
770         sendBroadcast(intent);
771     }
772 
notifyCharacteristicIndicated()773     private void notifyCharacteristicIndicated() {
774         showMessage("Characteristic Indicated");
775         Intent intent = new Intent(BLE_CHARACTERISTIC_INDICATED);
776         sendBroadcast(intent);
777     }
778 
notifyDescriptorRead(String value)779     private void notifyDescriptorRead(String value) {
780         showMessage("Descriptor read: " + value);
781         Intent intent = new Intent(BLE_DESCRIPTOR_READ);
782         intent.putExtra(EXTRA_DESCRIPTOR_VALUE, value);
783         sendBroadcast(intent);
784     }
785 
notifyDescriptorWrite(String value)786     private void notifyDescriptorWrite(String value) {
787         showMessage("Descriptor write: " + value);
788         Intent intent = new Intent(BLE_DESCRIPTOR_WRITE);
789         sendBroadcast(intent);
790     }
791 
notifyDescriptorReadNoPermission()792     private void notifyDescriptorReadNoPermission() {
793         showMessage("Descriptor read: No Permission");
794         Intent intent = new Intent(BLE_DESCRIPTOR_READ_NOPERMISSION);
795         sendBroadcast(intent);
796     }
797 
notifyDescriptorWriteNoPermission()798     private void notifyDescriptorWriteNoPermission() {
799         showMessage("Descriptor write: NoPermission");
800         Intent intent = new Intent(BLE_DESCRIPTOR_WRITE_NOPERMISSION);
801         sendBroadcast(intent);
802     }
803 
notifyDescriptorReadNeedEncrypted(String value)804     private void notifyDescriptorReadNeedEncrypted(String value) {
805         showMessage("Descriptor read with encrypted: " + value);
806         Intent intent = new Intent(BLE_DESCRIPTOR_READ_NEED_ENCRYPTED);
807         sendBroadcast(intent);
808     }
809 
notifyDescriptorWriteNeedEncrypted(String value)810     private void notifyDescriptorWriteNeedEncrypted(String value) {
811         showMessage("Descriptor write with encrypted: " + value);
812         Intent intent = new Intent(BLE_DESCRIPTOR_WRITE_NEED_ENCRYPTED);
813         sendBroadcast(intent);
814     }
815 
notifyReliableWriteCompleted()816     private void notifyReliableWriteCompleted() {
817         showMessage("Reliable write complete");
818         Intent intent = new Intent(BLE_RELIABLE_WRITE_COMPLETED);
819         sendBroadcast(intent);
820     }
821 
notifyReliableWriteBadRespCompleted(String err)822     private void notifyReliableWriteBadRespCompleted(String err) {
823         showMessage("Reliable write(bad response) complete");
824         Intent intent = new Intent(BLE_RELIABLE_WRITE_BAD_RESP_COMPLETED);
825         if (err != null) {
826             intent.putExtra(EXTRA_ERROR_MESSAGE, err);
827         }
828         sendBroadcast(intent);
829     }
830 
notifyReadRemoteRssi(int rssi)831     private void notifyReadRemoteRssi(int rssi) {
832         showMessage("Remote rssi read: " + rssi);
833         Intent intent = new Intent(BLE_READ_REMOTE_RSSI);
834         intent.putExtra(EXTRA_RSSI_VALUE, rssi);
835         sendBroadcast(intent);
836     }
837 
notifyServiceChanged()838     private void notifyServiceChanged() {
839         showMessage("Remote service changed");
840         Intent intent = new Intent(BLE_ON_SERVICE_CHANGED);
841         sendBroadcast(intent);
842     }
843 
getService(UUID serverUid)844     private BluetoothGattService getService(UUID serverUid) {
845         BluetoothGattService service = null;
846 
847         if (mBluetoothGatt != null) {
848             service = mBluetoothGatt.getService(serverUid);
849             if (service == null) {
850                 showMessage("Service not found");
851             }
852         }
853         return service;
854     }
855 
getService()856     private BluetoothGattService getService() {
857         BluetoothGattService service = null;
858 
859         if (mBluetoothGatt != null) {
860             service = mBluetoothGatt.getService(SERVICE_UUID);
861             if (service == null) {
862                 showMessage("Service not found");
863             }
864         }
865         return service;
866     }
867 
getCharacteristic(UUID serverUid, UUID characteristicUid)868     private BluetoothGattCharacteristic getCharacteristic(UUID serverUid, UUID characteristicUid) {
869         BluetoothGattCharacteristic characteristic = null;
870 
871         BluetoothGattService service = getService(serverUid);
872         if (service != null) {
873             characteristic = service.getCharacteristic(characteristicUid);
874             if (characteristic == null) {
875                 showMessage("Characteristic not found");
876             }
877         }
878         return characteristic;
879     }
getCharacteristic(UUID uuid)880     private BluetoothGattCharacteristic getCharacteristic(UUID uuid) {
881         BluetoothGattCharacteristic characteristic = null;
882 
883         BluetoothGattService service = getService();
884         if (service != null) {
885             characteristic = service.getCharacteristic(uuid);
886             if (characteristic == null) {
887                 showMessage("Characteristic not found");
888             }
889         }
890         return characteristic;
891     }
892 
getDescriptor(UUID uid)893     private BluetoothGattDescriptor getDescriptor(UUID uid) {
894         BluetoothGattDescriptor descriptor = null;
895 
896         BluetoothGattCharacteristic characteristic = getCharacteristic(CHARACTERISTIC_UUID);
897         if (characteristic != null) {
898             descriptor = characteristic.getDescriptor(uid);
899             if (descriptor == null) {
900                 showMessage("Descriptor not found");
901             }
902         }
903         return descriptor;
904     }
905 
getDescriptor(UUID cuid, UUID duid)906     private BluetoothGattDescriptor getDescriptor(UUID cuid, UUID duid) {
907         BluetoothGattDescriptor descriptor = null;
908 
909         BluetoothGattCharacteristic characteristic = getCharacteristic(cuid);
910         if (characteristic != null) {
911             descriptor = characteristic.getDescriptor(duid);
912             if (descriptor == null) {
913                 showMessage("Descriptor not found");
914             }
915         }
916         return descriptor;
917     }
918 
showMessage(final String msg)919     private void showMessage(final String msg) {
920         mHandler.post(new Runnable() {
921             public void run() {
922                 Toast.makeText(BleClientService.this, msg, Toast.LENGTH_SHORT).show();
923             }
924         });
925     }
926 
sleep(int millis)927     private void sleep(int millis) {
928         try {
929             Thread.sleep(millis);
930         } catch (InterruptedException e) {
931             Log.e(TAG, "Error in thread sleep", e);
932         }
933     }
934 
reliableWrite()935     private void reliableWrite() {
936         // aborting test
937         mBluetoothGatt.beginReliableWrite();
938         sleep(1000);
939         mBluetoothGatt.abortReliableWrite();
940 
941         // writing test
942         sleep(2000);
943         mBluetoothGatt.beginReliableWrite();
944         sleep(1000);
945 
946         if (BLE_CLIENT_ACTION_RELIABLE_WRITE.equals(mCurrentAction)) {
947             mExecReliableWrite = ReliableWriteState.RELIABLE_WRITE_WRITE_1ST_DATA;
948             writeCharacteristic(CHARACTERISTIC_UUID, WRITE_VALUE_507BYTES_FOR_RELIABLE_WRITE);
949         } else {
950             mExecReliableWrite = ReliableWriteState.RELIABLE_WRITE_BAD_RESP;
951             writeCharacteristic(CHARACTERISTIC_UUID, WRITE_VALUE_BAD_RESP);
952         }
953     }
954 
955     private int mBleState = BluetoothProfile.STATE_DISCONNECTED;
956     private final BluetoothGattCallback mGattCallbacks = new BluetoothGattCallback() {
957         @Override
958         public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
959             if (DEBUG) Log.d(TAG, "onConnectionStateChange: status= " + status + ", newState= " + newState);
960             if (status == BluetoothGatt.GATT_SUCCESS) {
961                 if (newState == BluetoothProfile.STATE_CONNECTED) {
962                     mBleState = newState;
963                     int bond = gatt.getDevice().getBondState();
964                     boolean bonded = false;
965                     BluetoothDevice target = gatt.getDevice();
966                     Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices();
967                     if (pairedDevices.size() > 0) {
968                         for (BluetoothDevice device : pairedDevices) {
969                             if (device.getAddress().equals(target.getAddress())) {
970                                 bonded = true;
971                                 break;
972                             }
973                         }
974                     }
975                     if (mSecure && ((bond == BluetoothDevice.BOND_NONE) || !bonded)) {
976                         // not pairing and execute Secure Test
977                         mBluetoothGatt.disconnect();
978                         notifyMismatchSecure();
979                     } else if (!mSecure && ((bond != BluetoothDevice.BOND_NONE) || bonded)) {
980                         // already pairing nad execute Insecure Test
981                         mBluetoothGatt.disconnect();
982                         notifyMismatchInsecure();
983                     } else {
984                         notifyConnected();
985                     }
986                 } else if (status == BluetoothProfile.STATE_DISCONNECTED) {
987                     mBleState = newState;
988                     mSecure = false;
989                     mBluetoothGatt.close();
990                     notifyDisconnected();
991                 }
992             } else {
993                 showMessage("Failed to connect: " + status + " , newState = " + newState);
994                 mBluetoothGatt.close();
995                 mBluetoothGatt = null;
996             }
997         }
998 
999         @Override
1000         public void onServicesDiscovered(BluetoothGatt gatt, int status) {
1001             if (DEBUG){
1002                 Log.d(TAG, "onServiceDiscovered");
1003             }
1004             if ((status == BluetoothGatt.GATT_SUCCESS) && (mBluetoothGatt.getService(SERVICE_UUID) != null)) {
1005                 notifyServicesDiscovered();
1006             }
1007         }
1008 
1009         @Override
1010         public void onMtuChanged(BluetoothGatt gatt, int mtu, int status) {
1011             super.onMtuChanged(gatt, mtu, status);
1012             if (DEBUG){
1013                 Log.d(TAG, "onMtuChanged");
1014             }
1015             if (status == BluetoothGatt.GATT_SUCCESS) {
1016                 // verify MTU size
1017                 int requestedMtu;
1018                 if (BLE_CLIENT_ACTION_REQUEST_MTU_23.equals(mCurrentAction)) {
1019                     requestedMtu = 23;
1020                 } else if (BLE_CLIENT_ACTION_REQUEST_MTU_512.equals(mCurrentAction)) {
1021                     requestedMtu = 512;
1022                 } else {
1023                     throw new IllegalStateException("unexpected action: " + mCurrentAction);
1024                 }
1025                 if (mtu != requestedMtu) {
1026                     String msg = String.format(getString(R.string.ble_mtu_mismatch_message),
1027                             requestedMtu, mtu);
1028                     showMessage(msg);
1029                 }
1030 
1031                 // test writing characteristic
1032                 writeCharacteristic(CHARACTERISTIC_UUID, WRITE_VALUE_512BYTES_FOR_MTU);
1033             } else {
1034                 notifyError("Failed to request mtu: " + status);
1035             }
1036         }
1037 
1038         @Override
1039         public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, final int status) {
1040             String value = characteristic.getStringValue(0);
1041             final UUID uid = characteristic.getUuid();
1042             if (DEBUG) {
1043                 Log.d(TAG, "onCharacteristicWrite: characteristic.val=" + value + " status=" + status);
1044             }
1045 
1046             if (BLE_CLIENT_ACTION_TRIGGER_SERVICE_CHANGED.equals(mCurrentAction)) {
1047                 sendServiceChangedEventIfReady(SERVICE_CHANGED_FLAG_TRIGGER_ACTION);
1048             } else if (BLE_CLIENT_ACTION_REQUEST_MTU_512.equals(mCurrentAction) ||
1049                     BLE_CLIENT_ACTION_REQUEST_MTU_23.equals(mCurrentAction)) {
1050                 if (status == BluetoothGatt.GATT_SUCCESS) {
1051                     notifyMtuChanged();
1052                 } else {
1053                     notifyError("Failed to write characteristic: " + status + " : " + uid);
1054                 }
1055             } else {
1056                 switch (mExecReliableWrite) {
1057                     case RELIABLE_WRITE_NONE:
1058                         if (status == BluetoothGatt.GATT_SUCCESS) {
1059                             if (characteristic.getUuid().equals(CHARACTERISTIC_NEED_ENCRYPTED_WRITE_UUID)) {
1060                                 notifyCharacteristicWriteNeedEncrypted(value);
1061                             } else if (!characteristic.getUuid().equals(CHARACTERISTIC_RESULT_UUID)) {
1062                                 // verify
1063                                 if (Arrays.equals(BleClientService.WRITE_VALUE.getBytes(), characteristic.getValue())) {
1064                                     notifyCharacteristicWrite(value);
1065                                 } else {
1066                                     notifyError("Written data is not correct");
1067                                 }
1068                             }
1069                         } else if (status == BluetoothGatt.GATT_WRITE_NOT_PERMITTED) {
1070                             if (uid.equals(CHARACTERISTIC_NO_WRITE_UUID)) {
1071                                 writeCharacteristic(getCharacteristic(CHARACTERISTIC_RESULT_UUID), BleServerService.WRITE_NO_PERMISSION);
1072                                 notifyCharacteristicWriteNoPermission(value);
1073                             } else {
1074                                 notifyError("Not Permission Write: " + status + " : " + uid);
1075                             }
1076                         } else if (status == BluetoothGatt.GATT_INSUFFICIENT_AUTHENTICATION) {
1077                             notifyError("Not Authentication Write: " + status + " : " + uid);
1078                         } else {
1079                             notifyError("Failed to write characteristic: " + status + " : " + uid);
1080                         }
1081                         break;
1082                     case RELIABLE_WRITE_WRITE_1ST_DATA:
1083                         // verify
1084                         if (WRITE_VALUE_507BYTES_FOR_RELIABLE_WRITE.equals(value)) {
1085                             // write next data
1086                             mExecReliableWrite = ReliableWriteState.RELIABLE_WRITE_WRITE_2ND_DATA;
1087                             writeCharacteristic(CHARACTERISTIC_UUID, WRITE_VALUE_507BYTES_FOR_RELIABLE_WRITE);
1088                         } else {
1089                             notifyError("Failed to write characteristic: " + status + " : " + uid);
1090                         }
1091                         break;
1092                     case RELIABLE_WRITE_WRITE_2ND_DATA:
1093                         // verify
1094                         if (WRITE_VALUE_507BYTES_FOR_RELIABLE_WRITE.equals(value)) {
1095                             // execute write
1096                             mTaskQueue.addTask(new Runnable() {
1097                                 @Override
1098                                 public void run() {
1099                                     mExecReliableWrite = ReliableWriteState.RELIABLE_WRITE_EXECUTE;
1100                                     if (!mBluetoothGatt.executeReliableWrite()) {
1101                                         notifyError("reliable write failed");
1102                                     }
1103                                 }
1104                             }, 1000);
1105                         } else {
1106                             notifyError("Failed to write characteristic: " + status + " : " + uid);
1107                         }
1108                         break;
1109                     case RELIABLE_WRITE_BAD_RESP:
1110                         mExecReliableWrite = ReliableWriteState.RELIABLE_WRITE_NONE;
1111                         // verify response
1112                         //   Server sends empty response for this test.
1113                         //   Response must be empty.
1114                         String err = null;
1115                         if (!TextUtils.isEmpty(value)) {
1116                             err = "response is not empty";
1117                             showMessage(err);
1118                         }
1119                         // finish reliable write
1120                         final String errValue = err;
1121                         mTaskQueue.addTask(new Runnable() {
1122                             @Override
1123                             public void run() {
1124                                 mBluetoothGatt.abortReliableWrite();
1125                                 notifyReliableWriteBadRespCompleted(errValue);
1126                             }
1127                         }, 1000);
1128                         break;
1129                 }
1130             }
1131         }
1132 
1133         @Override
1134         public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
1135             UUID uid = characteristic.getUuid();
1136             if (DEBUG) {
1137                 Log.d(TAG, "onCharacteristicRead: status=" + status);
1138             }
1139             if (status == BluetoothGatt.GATT_SUCCESS) {
1140                 String value = characteristic.getStringValue(0);
1141                 if (characteristic.getUuid().equals(CHARACTERISTIC_NEED_ENCRYPTED_READ_UUID)) {
1142                     notifyCharacteristicReadNeedEncrypted(value);
1143                 } else {
1144                     // verify
1145                     if (BleServerService.WRITE_VALUE.equals(value)) {
1146                         notifyCharacteristicRead(value);
1147                     } else {
1148                         notifyError("Read data is not correct");
1149                     }
1150                 }
1151             } else if (status == BluetoothGatt.GATT_READ_NOT_PERMITTED) {
1152                 if (uid.equals(CHARACTERISTIC_NO_READ_UUID)) {
1153                     writeCharacteristic(getCharacteristic(CHARACTERISTIC_RESULT_UUID), BleServerService.READ_NO_PERMISSION);
1154                     notifyCharacteristicReadNoPermission();
1155                 } else {
1156                     notifyError("Not Permission Read: " + status + " : " + uid);
1157                 }
1158             } else if(status == BluetoothGatt.GATT_INSUFFICIENT_AUTHENTICATION) {
1159                 notifyError("Not Authentication Read: " + status + " : " + uid);
1160             } else {
1161                 notifyError("Failed to read characteristic: " + status + " : " + uid);
1162             }
1163         }
1164 
1165         @Override
1166         public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
1167             if (DEBUG) {
1168                 Log.d(TAG, "onDescriptorWrite");
1169             }
1170             UUID uid = descriptor.getUuid();
1171             if ((status == BluetoothGatt.GATT_SUCCESS)) {
1172                 if (uid.equals(UPDATE_DESCRIPTOR_UUID)) {
1173                     Log.d(TAG, "write in update descriptor.");
1174                     if (descriptor.getValue() == BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE) {
1175                         notifyDisableNotificationCompletion();
1176                     }
1177                 } else if (uid.equals(DESCRIPTOR_UUID)) {
1178                     // verify
1179                     if (Arrays.equals(WRITE_VALUE.getBytes(), descriptor.getValue())) {
1180                         notifyDescriptorWrite(new String(descriptor.getValue()));
1181                     } else {
1182                         notifyError("Written data is not correct");
1183                     }
1184                 } else if (uid.equals(DESCRIPTOR_NEED_ENCRYPTED_WRITE_UUID)) {
1185                     notifyDescriptorWriteNeedEncrypted(new String(descriptor.getValue()));
1186                 }
1187             } else if (status == BluetoothGatt.GATT_WRITE_NOT_PERMITTED) {
1188                 if (uid.equals(DESCRIPTOR_NO_WRITE_UUID)) {
1189                     writeCharacteristic(getCharacteristic(CHARACTERISTIC_RESULT_UUID), BleServerService.DESCRIPTOR_WRITE_NO_PERMISSION);
1190                     notifyDescriptorWriteNoPermission();
1191                 } else {
1192                     notifyError("Not Permission Write: " + status + " : " + descriptor.getUuid());
1193                 }
1194             } else {
1195                 notifyError("Failed to write descriptor");
1196             }
1197         }
1198 
1199         @Override
1200         public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
1201             if (DEBUG) {
1202                 Log.d(TAG, "onDescriptorRead");
1203             }
1204 
1205             UUID uid = descriptor.getUuid();
1206             if ((status == BluetoothGatt.GATT_SUCCESS)) {
1207                 if ((uid != null) && (uid.equals(DESCRIPTOR_UUID))) {
1208                     // verify
1209                     if (Arrays.equals(BleServerService.WRITE_VALUE.getBytes(), descriptor.getValue())) {
1210                         notifyDescriptorRead(new String(descriptor.getValue()));
1211                     } else {
1212                         notifyError("Read data is not correct");
1213                     }
1214                 } else if (uid.equals(DESCRIPTOR_NEED_ENCRYPTED_READ_UUID)) {
1215                     notifyDescriptorReadNeedEncrypted(new String(descriptor.getValue()));
1216                 }
1217             } else if (status == BluetoothGatt.GATT_READ_NOT_PERMITTED) {
1218                 if (uid.equals(DESCRIPTOR_NO_READ_UUID)) {
1219                     writeCharacteristic(getCharacteristic(CHARACTERISTIC_RESULT_UUID), BleServerService.DESCRIPTOR_READ_NO_PERMISSION);
1220                     notifyDescriptorReadNoPermission();
1221                 } else {
1222                     notifyError("Not Permission Read: " + status + " : " + descriptor.getUuid());
1223                 }
1224             } else {
1225                 notifyError("Failed to read descriptor: " + status);
1226             }
1227         }
1228 
1229         @Override
1230         public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
1231             UUID uid = characteristic.getUuid();
1232             if (DEBUG) {
1233                 Log.d(TAG, "onCharacteristicChanged: " + uid);
1234             }
1235             if (uid != null) {
1236                 if (uid.equals(INDICATE_CHARACTERISTIC_UUID)) {
1237                     setNotification(characteristic, false);
1238                     notifyCharacteristicIndicated();
1239                 } else {
1240                     mNotifyCount--;
1241                     setNotification(characteristic, false);
1242                     if (mNotifyCount == 0) {
1243                         notifyCharacteristicChanged();
1244                     }
1245                 }
1246             }
1247         }
1248 
1249         @Override
1250         public void onReliableWriteCompleted(BluetoothGatt gatt, int status) {
1251             if (DEBUG) {
1252                 Log.d(TAG, "onReliableWriteComplete: " + status);
1253             }
1254 
1255             if (mExecReliableWrite != ReliableWriteState.RELIABLE_WRITE_NONE) {
1256                 if (status == BluetoothGatt.GATT_SUCCESS) {
1257                     notifyReliableWriteCompleted();
1258                 } else {
1259                     notifyError("Failed to complete reliable write: " + status);
1260                 }
1261                 mExecReliableWrite = ReliableWriteState.RELIABLE_WRITE_NONE;
1262             }
1263         }
1264 
1265         @Override
1266         public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {
1267             if (DEBUG) {
1268                 Log.d(TAG, "onReadRemoteRssi");
1269             }
1270             if (status == BluetoothGatt.GATT_SUCCESS) {
1271                 notifyReadRemoteRssi(rssi);
1272             } else {
1273                 notifyError("Failed to read remote rssi");
1274             }
1275         }
1276 
1277         @Override
1278         public void onServiceChanged(BluetoothGatt gatt) {
1279             if (DEBUG) {
1280                 Log.d(TAG, "onServiceChanged");
1281             }
1282 
1283             if (BLE_CLIENT_ACTION_TRIGGER_SERVICE_CHANGED.equals(mCurrentAction)) {
1284                 sendServiceChangedEventIfReady(SERVICE_CHANGED_FLAG_ON_SERVICE_CHANGED);
1285             }
1286         }
1287     };
1288 
1289     private final ScanCallback mScanCallback = new ScanCallback() {
1290         @Override
1291         public void onScanResult(int callbackType, ScanResult result) {
1292             if (mBluetoothGatt == null) {
1293                 // verify the validity of the advertisement packet.
1294                 mValidityService = false;
1295                 List<ParcelUuid> uuids = result.getScanRecord().getServiceUuids();
1296                 for (ParcelUuid uuid : uuids) {
1297                     if (uuid.getUuid().equals(BleServerService.ADV_SERVICE_UUID)) {
1298                         mValidityService = true;
1299                         break;
1300                     }
1301                 }
1302                 if (mValidityService) {
1303                     stopScan();
1304 
1305                     BluetoothDevice device = result.getDevice();
1306                     if (mSecure) {
1307                         if (device.getBondState() != BluetoothDevice.BOND_BONDED) {
1308                             if (!device.createBond()) {
1309                                 notifyError("Failed to call create bond");
1310                             }
1311                         } else {
1312                             mBluetoothGatt = connectGatt(result.getDevice(), mContext, false, mSecure, mGattCallbacks);
1313                         }
1314                     } else {
1315                         mBluetoothGatt = connectGatt(result.getDevice(), mContext, false, mSecure, mGattCallbacks);
1316                     }
1317                 } else {
1318                     notifyError("There is no validity to Advertise servie.");
1319                 }
1320             }
1321         }
1322     };
1323 
startScan()1324     private void startScan() {
1325         if (DEBUG) Log.d(TAG, "startScan");
1326         List<ScanFilter> filter = Arrays.asList(new ScanFilter.Builder().setServiceUuid(
1327                 new ParcelUuid(BleServerService.ADV_SERVICE_UUID)).build());
1328         ScanSettings setting = new ScanSettings.Builder()
1329                 .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY).build();
1330         mScanner.startScan(filter, setting, mScanCallback);
1331     }
1332 
stopScan()1333     private void stopScan() {
1334         if (DEBUG) Log.d(TAG, "stopScan");
1335         if (mScanner != null) {
1336             mScanner.stopScan(mScanCallback);
1337         }
1338     }
1339 
createTestData(int length)1340     private static String createTestData(int length) {
1341         StringBuilder builder = new StringBuilder();
1342         builder.append("REQUEST_MTU");
1343         int len = length - builder.length();
1344         for (int i = 0; i < len; ++i) {
1345             builder.append(""+(i%10));
1346         }
1347         return builder.toString();
1348     }
1349 
1350     private final BroadcastReceiver mBondStatusReceiver = new BroadcastReceiver() {
1351         @Override
1352         public void onReceive(Context context, Intent intent) {
1353             if (intent.getAction().equals(BluetoothDevice.ACTION_BOND_STATE_CHANGED)) {
1354                 BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
1355                 int state = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, BluetoothDevice.BOND_NONE);
1356                 switch (state) {
1357                     case BluetoothDevice.BOND_BONDED:
1358                         if ((mBluetoothGatt == null) &&
1359                             (device.getType() != BluetoothDevice.DEVICE_TYPE_CLASSIC)) {
1360                             if (DEBUG) {
1361                                 Log.d(TAG, "onReceive:BOND_BONDED: calling connectGatt device="
1362                                              + device + ", mSecure=" + mSecure);
1363                             }
1364                             mBluetoothGatt = connectGatt(device, mContext, false, mSecure,
1365                                                          mGattCallbacks);
1366                         }
1367                         break;
1368                     case BluetoothDevice.BOND_NONE:
1369                         notifyError("Failed to create bond.");
1370                         break;
1371                     case BluetoothDevice.BOND_BONDING:
1372                     default:    // fall through
1373                         // wait for next state
1374                         break;
1375                 }
1376             }
1377         }
1378     };
1379 }
1380