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