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