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