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.BluetoothDevice;
21 import android.bluetooth.BluetoothGatt;
22 import android.bluetooth.BluetoothGattCharacteristic;
23 import android.bluetooth.BluetoothGattDescriptor;
24 import android.bluetooth.BluetoothGattServer;
25 import android.bluetooth.BluetoothGattServerCallback;
26 import android.bluetooth.BluetoothGattService;
27 import android.bluetooth.BluetoothManager;
28 import android.bluetooth.BluetoothProfile;
29 import android.bluetooth.le.AdvertiseCallback;
30 import android.bluetooth.le.AdvertiseData;
31 import android.bluetooth.le.AdvertiseSettings;
32 import android.bluetooth.le.BluetoothLeAdvertiser;
33 import android.content.Context;
34 import android.content.Intent;
35 import android.os.Build;
36 import android.os.Handler;
37 import android.os.IBinder;
38 import android.os.ParcelUuid;
39 import android.util.Log;
40 import android.widget.Toast;
41 
42 import com.android.cts.verifier.R;
43 
44 import java.util.ArrayList;
45 import java.util.Arrays;
46 import java.util.HashMap;
47 import java.util.LinkedHashMap;
48 import java.util.List;
49 import java.util.Set;
50 import java.util.Timer;
51 import java.util.UUID;
52 
53 public class BleServerService extends Service {
54 
55     public static final boolean DEBUG = true;
56     public static final String TAG = "BleServerService";
57 
58     public static final int COMMAND_ADD_SERVICE = 0;
59     public static final int COMMAND_WRITE_CHARACTERISTIC = 1;
60     public static final int COMMAND_WRITE_DESCRIPTOR = 2;
61 
62     public static final String BLE_BLUETOOTH_MISMATCH_SECURE =
63             "com.android.cts.verifier.bluetooth.BLE_BLUETOOTH_MISMATCH_SECURE";
64     public static final String BLE_BLUETOOTH_MISMATCH_INSECURE =
65             "com.android.cts.verifier.bluetooth.BLE_BLUETOOTH_MISMATCH_INSECURE";
66     public static final String BLE_BLUETOOTH_DISABLED =
67             "com.android.cts.verifier.bluetooth.BLE_BLUETOOTH_DISABLED";
68     public static final String BLE_ACTION_SERVER_SECURE =
69             "com.android.cts.verifier.bluetooth.BLE_ACTION_SERVER_SECURE";
70     public static final String BLE_ACTION_SERVER_NON_SECURE =
71             "com.android.cts.verifier.bluetooth.BLE_ACTION_SERVER_NON_SECURE";
72 
73 
74     public static final String BLE_SERVER_CONNECTED =
75             "com.android.cts.verifier.bluetooth.BLE_SERVER_CONNECTED";
76     public static final String BLE_SERVER_DISCONNECTED =
77             "com.android.cts.verifier.bluetooth.BLE_SERVER_DISCONNECTED";
78     public static final String BLE_SERVICE_ADDED =
79             "com.android.cts.verifier.bluetooth.BLE_SERVICE_ADDED";
80     public static final String BLE_MTU_REQUEST_23BYTES =
81             "com.android.cts.verifier.bluetooth.BLE_MTU_REQUEST_23BYTES";
82     public static final String BLE_MTU_REQUEST_512BYTES =
83             "com.android.cts.verifier.bluetooth.BLE_MTU_REQUEST_512BYTES";
84     public static final String BLE_CHARACTERISTIC_READ_REQUEST =
85             "com.android.cts.verifier.bluetooth.BLE_CHARACTERISTIC_READ_REQUEST";
86     public static final String BLE_CHARACTERISTIC_WRITE_REQUEST =
87             "com.android.cts.verifier.bluetooth.BLE_CHARACTERISTIC_WRITE_REQUEST";
88     public static final String BLE_CHARACTERISTIC_READ_REQUEST_WITHOUT_PERMISSION =
89             "com.android.cts.verifier.bluetooth.BLE_CHARACTERISTIC_READ_REQUEST_WITHOUT_PERMISSION";
90     public static final String BLE_CHARACTERISTIC_WRITE_REQUEST_WITHOUT_PERMISSION =
91             "com.android.cts.verifier.bluetooth.BLE_CHARACTERISTIC_WRITE_REQUEST_WITHOUT_PERMISSION";
92     public static final String BLE_CHARACTERISTIC_READ_REQUEST_NEED_ENCRYPTED =
93             "com.android.cts.verifier.bluetooth.BLE_CHARACTERISTIC_READ_REQUEST_NEED_ENCRYPTED";
94     public static final String BLE_CHARACTERISTIC_WRITE_REQUEST_NEED_ENCRYPTED =
95             "com.android.cts.verifier.bluetooth.BLE_CHARACTERISTIC_WRITE_REQUEST_NEED_ENCRYPTED";
96     public static final String BLE_CHARACTERISTIC_NOTIFICATION_REQUEST =
97             "com.android.cts.verifier.bluetooth.BLE_CHARACTERISTIC_NOTIFICATION_REQUEST";
98     public static final String BLE_CHARACTERISTIC_INDICATE_REQUEST =
99             "com.android.cts.verifier.bluetooth.BLE_CHARACTERISTIC_INDICATE_REQUEST";
100     public static final String BLE_DESCRIPTOR_READ_REQUEST =
101             "com.android.cts.verifier.bluetooth.BLE_DESCRIPTOR_READ_REQUEST";
102     public static final String BLE_DESCRIPTOR_WRITE_REQUEST =
103             "com.android.cts.verifier.bluetooth.BLE_DESCRIPTOR_WRITE_REQUEST";
104     public static final String BLE_DESCRIPTOR_READ_REQUEST_WITHOUT_PERMISSION =
105             "com.android.cts.verifier.bluetooth.BLE_DESCRIPTOR_READ_REQUEST_WITHOUT_PERMISSION";
106     public static final String BLE_DESCRIPTOR_WRITE_REQUEST_WITHOUT_PERMISSION =
107             "com.android.cts.verifier.bluetooth.BLE_DESCRIPTOR_WRITE_REQUEST_WITHOUT_PERMISSION";
108     public static final String BLE_DESCRIPTOR_READ_REQUEST_NEED_ENCRYPTED =
109             "com.android.cts.verifier.bluetooth.BLE_DESCRIPTOR_READ_REQUEST_NEED_ENCRYPTED";
110     public static final String BLE_DESCRIPTOR_WRITE_REQUEST_NEED_ENCRYPTED =
111             "com.android.cts.verifier.bluetooth.BLE_DESCRIPTOR_WRITE_REQUEST_NEED_ENCRYPTED";
112     public static final String BLE_EXECUTE_WRITE =
113             "com.android.cts.verifier.bluetooth.BLE_EXECUTE_WRITE";
114     public static final String BLE_OPEN_FAIL =
115             "com.android.cts.verifier.bluetooth.BLE_OPEN_FAIL";
116     public static final String BLE_RELIABLE_WRITE_BAD_RESP =
117             "com.android.cts.verifier.bluetooth.BLE_RELIABLE_WRITE_BAD_RESP";
118     public static final String BLE_ADVERTISE_UNSUPPORTED =
119             "com.android.cts.verifier.bluetooth.BLE_ADVERTISE_UNSUPPORTED";
120     public static final String BLE_ADD_SERVICE_FAIL =
121             "com.android.cts.verifier.bluetooth.BLE_ADD_SERVICE_FAIL";
122 
123     private static final UUID SERVICE_UUID =
124             UUID.fromString("00009999-0000-1000-8000-00805f9b34fb");
125     private static final UUID CHARACTERISTIC_UUID =
126             UUID.fromString("00009998-0000-1000-8000-00805f9b34fb");
127     private static final UUID CHARACTERISTIC_RESULT_UUID =
128             UUID.fromString("00009974-0000-1000-8000-00805f9b34fb");
129     private static final UUID UPDATE_CHARACTERISTIC_UUID =
130             UUID.fromString("00009997-0000-1000-8000-00805f9b34fb");
131     private static final UUID DESCRIPTOR_UUID =
132             UUID.fromString("00009996-0000-1000-8000-00805f9b34fb");
133     public static final UUID ADV_SERVICE_UUID=
134             UUID.fromString("00003333-0000-1000-8000-00805f9b34fb");
135 
136     private static final UUID SERVICE_UUID_ADDITIONAL =
137             UUID.fromString("00009995-0000-1000-8000-00805f9b34fb");
138     private static final UUID SERVICE_UUID_INCLUDED =
139             UUID.fromString("00009994-0000-1000-8000-00805f9b34fb");
140 
141     // Variable for registration permission of Characteristic
142     private static final UUID CHARACTERISTIC_NO_READ_UUID =
143             UUID.fromString("00009984-0000-1000-8000-00805f9b34fb");
144     private static final UUID CHARACTERISTIC_NO_WRITE_UUID =
145             UUID.fromString("00009983-0000-1000-8000-00805f9b34fb");
146     private static final UUID CHARACTERISTIC_NEED_ENCRYPTED_READ_UUID =
147             UUID.fromString("00009982-0000-1000-8000-00805f9b34fb");
148     private static final UUID CHARACTERISTIC_NEED_ENCRYPTED_WRITE_UUID =
149             UUID.fromString("00009981-0000-1000-8000-00805f9b34fb");
150 
151     // Variable for registration permission of Descriptor
152     private static final UUID DESCRIPTOR_NO_READ_UUID =
153             UUID.fromString("00009973-0000-1000-8000-00805f9b34fb");
154     private static final UUID DESCRIPTOR_NO_WRITE_UUID =
155             UUID.fromString("00009972-0000-1000-8000-00805f9b34fb");
156     private static final UUID DESCRIPTOR_NEED_ENCRYPTED_READ_UUID =
157             UUID.fromString("00009969-0000-1000-8000-00805f9b34fb");
158     private static final UUID DESCRIPTOR_NEED_ENCRYPTED_WRITE_UUID =
159             UUID.fromString("00009968-0000-1000-8000-00805f9b34fb");
160 
161     //  Variable for registration upper limit confirmation of Characteristic
162     private static final UUID UPDATE_CHARACTERISTIC_UUID_1 =
163             UUID.fromString("00009989-0000-1000-8000-00805f9b34fb");
164     private static final UUID UPDATE_CHARACTERISTIC_UUID_2 =
165             UUID.fromString("00009988-0000-1000-8000-00805f9b34fb");
166     private static final UUID UPDATE_CHARACTERISTIC_UUID_3 =
167             UUID.fromString("00009987-0000-1000-8000-00805f9b34fb");
168     private static final UUID UPDATE_CHARACTERISTIC_UUID_4 =
169             UUID.fromString("00009986-0000-1000-8000-00805f9b34fb");
170     private static final UUID UPDATE_CHARACTERISTIC_UUID_5 =
171             UUID.fromString("00009985-0000-1000-8000-00805f9b34fb");
172     private static final UUID UPDATE_CHARACTERISTIC_UUID_6 =
173             UUID.fromString("00009979-0000-1000-8000-00805f9b34fb");
174     private static final UUID UPDATE_CHARACTERISTIC_UUID_7 =
175             UUID.fromString("00009978-0000-1000-8000-00805f9b34fb");
176     private static final UUID UPDATE_CHARACTERISTIC_UUID_8 =
177             UUID.fromString("00009977-0000-1000-8000-00805f9b34fb");
178     private static final UUID UPDATE_CHARACTERISTIC_UUID_9 =
179             UUID.fromString("00009976-0000-1000-8000-00805f9b34fb");
180     private static final UUID UPDATE_CHARACTERISTIC_UUID_10 =
181             UUID.fromString("00009975-0000-1000-8000-00805f9b34fb");
182     private static final UUID UPDATE_CHARACTERISTIC_UUID_11 =
183             UUID.fromString("00009959-0000-1000-8000-00805f9b34fb");
184     private static final UUID UPDATE_CHARACTERISTIC_UUID_12 =
185             UUID.fromString("00009958-0000-1000-8000-00805f9b34fb");
186     private static final UUID UPDATE_CHARACTERISTIC_UUID_13 =
187             UUID.fromString("00009957-0000-1000-8000-00805f9b34fb");
188     private static final UUID UPDATE_CHARACTERISTIC_UUID_14 =
189             UUID.fromString("00009956-0000-1000-8000-00805f9b34fb");
190     private static final UUID UPDATE_CHARACTERISTIC_UUID_15 =
191             UUID.fromString("00009955-0000-1000-8000-00805f9b34fb");
192 
193     private static final UUID UPDATE_DESCRIPTOR_UUID =
194             UUID.fromString("00002902-0000-1000-8000-00805f9b34fb");
195 
196     private static final UUID INDICATE_CHARACTERISTIC_UUID =
197             UUID.fromString("00009971-0000-1000-8000-00805f9b34fb");
198 
199     private static final int CONN_INTERVAL = 150;   // connection interval 150ms
200 
201     // Delay of notification when secure test failed to start.
202     private static final long NOTIFICATION_DELAY_OF_SECURE_TEST_FAILURE = 5 * 1000;
203 
204     public static final String WRITE_VALUE = "SERVER_TEST";
205     private static final String NOTIFY_VALUE = "NOTIFY_TEST";
206     private static final String INDICATE_VALUE = "INDICATE_TEST";
207     public static final String READ_NO_PERMISSION = "READ_NO_CHAR";
208     public static final String WRITE_NO_PERMISSION = "WRITE_NO_CHAR";
209     public static final String DESCRIPTOR_READ_NO_PERMISSION = "READ_NO_DESC";
210     public static final String DESCRIPTOR_WRITE_NO_PERMISSION = "WRITE_NO_DESC";
211 
212     private BluetoothManager mBluetoothManager;
213     private BluetoothGattServer mGattServer;
214     private BluetoothGattService mService;
215     private BluetoothDevice mDevice;
216     private Timer mNotificationTimer;
217     private Handler mHandler;
218     private String mReliableWriteValue;
219     private BluetoothLeAdvertiser mAdvertiser;
220     private boolean mIndicated;
221     private int mNotifyCount;
222     private boolean mSecure;
223     private int mCountMtuChange;
224     private int mMtuSize = -1;
225     private String mMtuTestReceivedData;
226     private Runnable mResetValuesTask;
227     private BluetoothGattService mAdditionalNotificationService;
228 
229     // Task to notify failure of starting secure test.
230     //   Secure test calls BluetoothDevice#createBond() when devices were not paired.
231     //   createBond() causes onConnectionStateChange() twice, and it works as strange sequence.
232     //   At the first onConnectionStateChange(), target device is not paired(bond state is
233     //   BluetoothDevice.BOND_NONE).
234     //   At the second onConnectionStateChange(), target devices is paired(bond state is
235     //   BluetoothDevice.BOND_BONDED).
236     //   CTS Verifier will perform lazy check of bond state.Verifier checks bond state
237     //   after NOTIFICATION_DELAY_OF_SECURE_TEST_FAILURE from the first onConnectionStateChange().
238     private Runnable mNotificationTaskOfSecureTestStartFailure;
239 
240     @Override
onCreate()241     public void onCreate() {
242         super.onCreate();
243 
244         mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
245         mAdvertiser = mBluetoothManager.getAdapter().getBluetoothLeAdvertiser();
246         mGattServer = mBluetoothManager.openGattServer(this, mCallbacks);
247 
248         mService = createService();
249         mAdditionalNotificationService = createAdditionalNotificationService();
250 
251         mDevice = null;
252         mReliableWriteValue = "";
253 
254         mHandler = new Handler();
255         if (!mBluetoothManager.getAdapter().isEnabled()) {
256             notifyBluetoothDisabled();
257         } else if (mGattServer == null) {
258             notifyOpenFail();
259         } else if (mAdvertiser == null) {
260             notifyAdvertiseUnsupported();
261         } else {
262             // start adding services
263             mNotifyCount = 11;
264             mSecure = false;
265             mCountMtuChange = 0;
266             if (!mGattServer.addService(mService)) {
267                 notifyAddServiceFail();
268             }
269         }
270     }
271 
notifyBluetoothDisabled()272     private void notifyBluetoothDisabled() {
273         Intent intent = new Intent(BLE_BLUETOOTH_DISABLED);
274         sendBroadcast(intent);
275     }
276 
notifyMismatchSecure()277     private void notifyMismatchSecure() {
278         Intent intent = new Intent(BLE_BLUETOOTH_MISMATCH_SECURE);
279         sendBroadcast(intent);
280     }
281 
notifyMismatchInsecure()282     private void notifyMismatchInsecure() {
283         /*
284         Intent intent = new Intent(BLE_BLUETOOTH_MISMATCH_INSECURE);
285         sendBroadcast(intent);
286         */
287     }
288 
289     @Override
onStartCommand(Intent intent, int flags, int startId)290     public int onStartCommand(Intent intent, int flags, int startId) {
291         String action = intent.getAction();
292         if (action != null) {
293             switch (action) {
294             case BLE_ACTION_SERVER_SECURE:
295                 mSecure = true;
296                 if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.M) {
297                     showMessage("Skip MTU test.");
298                     mCountMtuChange = 1;
299                     notifyMtuRequest();
300                     mCountMtuChange = 2;
301                     notifyMtuRequest();
302                     mCountMtuChange = 0;
303                 }
304                 break;
305             case BLE_ACTION_SERVER_NON_SECURE:
306                 mSecure = false;
307                 break;
308             }
309         }
310 
311         if (mBluetoothManager.getAdapter().isEnabled() && (mAdvertiser != null)) {
312             startAdvertise();
313         }
314         return START_NOT_STICKY;
315     }
316 
317     @Override
onBind(Intent intent)318     public IBinder onBind(Intent intent) {
319         return null;
320     }
321 
322     @Override
onDestroy()323     public void onDestroy() {
324         super.onDestroy();
325         cancelNotificationTaskOfSecureTestStartFailure();
326         stopAdvertise();
327         if (mGattServer == null) {
328            return;
329         }
330         if (mDevice != null) {
331             mGattServer.cancelConnection(mDevice);
332         }
333         mGattServer.clearServices();
334         mGattServer.close();
335     }
336 
337     /**
338      * Sets default value to characteristic and descriptor.
339      *
340      * Set operation will be done after connection interval.
341      * (If set values immediately, multiple read/write operations may fail.)
342      */
resetValues()343     private synchronized void resetValues() {
344         // cancel pending task
345         if (mResetValuesTask != null) {
346             mHandler.removeCallbacks(mResetValuesTask);
347             mResetValuesTask = null;
348         }
349 
350         // reserve task
351         mResetValuesTask = new Runnable() {
352             @Override
353             public void run() {
354                 getCharacteristic(CHARACTERISTIC_UUID).setValue(WRITE_VALUE.getBytes());
355                 getDescriptor().setValue(WRITE_VALUE.getBytes());
356             }
357         };
358         mHandler.postDelayed(mResetValuesTask, CONN_INTERVAL);
359     }
360 
notifyOpenFail()361     private void notifyOpenFail() {
362         if (DEBUG) {
363             Log.d(TAG, "notifyOpenFail");
364         }
365         Intent intent = new Intent(BLE_OPEN_FAIL);
366         sendBroadcast(intent);
367     }
368 
notifyAddServiceFail()369     private void notifyAddServiceFail() {
370         if (DEBUG) {
371             Log.d(TAG, "notifyAddServiceFail");
372         }
373         Intent intent = new Intent(BLE_ADD_SERVICE_FAIL);
374         sendBroadcast(intent);
375     }
376 
notifyAdvertiseUnsupported()377     private void notifyAdvertiseUnsupported() {
378         if (DEBUG) {
379             Log.d(TAG, "notifyAdvertiseUnsupported");
380         }
381         Intent intent = new Intent(BLE_ADVERTISE_UNSUPPORTED);
382         sendBroadcast(intent);
383     }
384 
notifyConnected()385     private void notifyConnected() {
386         if (DEBUG) {
387             Log.d(TAG, "notifyConnected");
388         }
389         Intent intent = new Intent(BLE_SERVER_CONNECTED);
390         sendBroadcast(intent);
391 
392         resetValues();
393     }
394 
notifyDisconnected()395     private void notifyDisconnected() {
396         if (DEBUG) {
397             Log.d(TAG, "notifyDisconnected");
398         }
399         Intent intent = new Intent(BLE_SERVER_DISCONNECTED);
400         sendBroadcast(intent);
401     }
402 
notifyServiceAdded()403     private void notifyServiceAdded() {
404         if (DEBUG) {
405             Log.d(TAG, "notifyServiceAdded");
406         }
407         Intent intent = new Intent(BLE_SERVICE_ADDED);
408         sendBroadcast(intent);
409     }
410 
notifyMtuRequest()411     private void notifyMtuRequest() {
412         if (DEBUG) {
413             Log.d(TAG, "notifyMtuRequest");
414         }
415         Intent intent;
416         if (mCountMtuChange == 1) {
417             intent = new Intent(BLE_MTU_REQUEST_23BYTES);
418         } else if (mCountMtuChange == 2) {
419             intent = new Intent(BLE_MTU_REQUEST_512BYTES);
420         } else {
421             return; // never occurs
422         }
423         sendBroadcast(intent);
424     }
425 
notifyCharacteristicReadRequest(boolean resetValues)426     private void notifyCharacteristicReadRequest(boolean resetValues) {
427         if (DEBUG) {
428             Log.d(TAG, "notifyCharacteristicReadRequest");
429         }
430         Intent intent = new Intent(BLE_CHARACTERISTIC_READ_REQUEST);
431         sendBroadcast(intent);
432 
433         if (resetValues) {
434             resetValues();
435         }
436     }
437 
notifyCharacteristicWriteRequest()438     private void notifyCharacteristicWriteRequest() {
439         if (DEBUG) {
440             Log.d(TAG, "notifyCharacteristicWriteRequest");
441         }
442         Intent intent = new Intent(BLE_CHARACTERISTIC_WRITE_REQUEST);
443         sendBroadcast(intent);
444 
445         resetValues();
446     }
447 
notifyCharacteristicReadRequestWithoutPermission()448     private void notifyCharacteristicReadRequestWithoutPermission() {
449         if (DEBUG) {
450             Log.d(TAG, "notifyCharacteristicReadRequestWithoutPermission");
451         }
452         Intent intent = new Intent(BLE_CHARACTERISTIC_READ_REQUEST_WITHOUT_PERMISSION);
453         sendBroadcast(intent);
454 
455         resetValues();
456     }
457 
notifyCharacteristicWriteRequestWithoutPermission()458     private void notifyCharacteristicWriteRequestWithoutPermission() {
459         if (DEBUG) {
460             Log.d(TAG, "notifyCharacteristicWriteRequestWithoutPermission");
461         }
462         Intent intent = new Intent(BLE_CHARACTERISTIC_WRITE_REQUEST_WITHOUT_PERMISSION);
463         sendBroadcast(intent);
464 
465         resetValues();
466     }
467 
notifyCharacteristicReadRequestNeedEncrypted()468     private void notifyCharacteristicReadRequestNeedEncrypted() {
469         if (DEBUG) {
470             Log.d(TAG, "notifyCharacteristicReadRequestNeedEncrypted");
471         }
472         Intent intent = new Intent(BLE_CHARACTERISTIC_READ_REQUEST_NEED_ENCRYPTED);
473         sendBroadcast(intent);
474 
475         resetValues();
476     }
477 
notifyCharacteristicWriteRequestNeedEncrypted()478     private void notifyCharacteristicWriteRequestNeedEncrypted() {
479         if (DEBUG) {
480             Log.d(TAG, "notifyCharacteristicWriteRequestNeedEncrypted");
481         }
482         Intent intent = new Intent(BLE_CHARACTERISTIC_WRITE_REQUEST_NEED_ENCRYPTED);
483         sendBroadcast(intent);
484 
485         resetValues();
486     }
487 
notifyCharacteristicNotificationRequest()488     private void notifyCharacteristicNotificationRequest() {
489         if (DEBUG) {
490             Log.d(TAG, "notifyCharacteristicNotificationRequest");
491         }
492         mNotifyCount = 11;
493         Intent intent = new Intent(BLE_CHARACTERISTIC_NOTIFICATION_REQUEST);
494         sendBroadcast(intent);
495 
496         resetValues();
497     }
498 
notifyCharacteristicIndicationRequest()499     private void notifyCharacteristicIndicationRequest() {
500         if (DEBUG) {
501             Log.d(TAG, "notifyCharacteristicIndicationRequest");
502         }
503         Intent intent = new Intent(BLE_CHARACTERISTIC_INDICATE_REQUEST);
504         sendBroadcast(intent);
505 
506         resetValues();
507     }
508 
notifyDescriptorReadRequest()509     private void notifyDescriptorReadRequest() {
510         if (DEBUG) {
511             Log.d(TAG, "notifyDescriptorReadRequest");
512         }
513         Intent intent = new Intent(BLE_DESCRIPTOR_READ_REQUEST);
514         sendBroadcast(intent);
515 
516         resetValues();
517     }
518 
notifyDescriptorWriteRequest()519     private void notifyDescriptorWriteRequest() {
520         if (DEBUG) {
521             Log.d(TAG, "notifyDescriptorWriteRequest");
522         }
523         Intent intent = new Intent(BLE_DESCRIPTOR_WRITE_REQUEST);
524         sendBroadcast(intent);
525 
526         resetValues();
527     }
528 
notifyDescriptorReadRequestWithoutPermission()529     private void notifyDescriptorReadRequestWithoutPermission() {
530         if (DEBUG) {
531             Log.d(TAG, "notifyDescriptorReadRequestWithoutPermission");
532         }
533         Intent intent = new Intent(BLE_DESCRIPTOR_READ_REQUEST_WITHOUT_PERMISSION);
534         sendBroadcast(intent);
535 
536         resetValues();
537     }
538 
notifyDescriptorWriteRequestWithoutPermission()539     private void notifyDescriptorWriteRequestWithoutPermission() {
540         if (DEBUG) {
541             Log.d(TAG, "notifyDescriptorWriteRequestWithoutPermission");
542         }
543         Intent intent = new Intent(BLE_DESCRIPTOR_WRITE_REQUEST_WITHOUT_PERMISSION);
544         sendBroadcast(intent);
545 
546         resetValues();
547     }
548 
notifyDescriptorReadRequestNeedEncrypted()549     private void notifyDescriptorReadRequestNeedEncrypted() {
550         if (DEBUG) {
551             Log.d(TAG, "notifyDescriptorReadRequestNeedEncrypted");
552         }
553         Intent intent = new Intent(BLE_DESCRIPTOR_READ_REQUEST_NEED_ENCRYPTED);
554         sendBroadcast(intent);
555 
556         resetValues();
557     }
558 
notifyDescriptorWriteRequestNeedEncrypted()559     private void notifyDescriptorWriteRequestNeedEncrypted() {
560         if (DEBUG) {
561             Log.d(TAG, "notifyDescriptorWriteRequestNeedEncrypted");
562         }
563         Intent intent = new Intent(BLE_DESCRIPTOR_WRITE_REQUEST_NEED_ENCRYPTED);
564         sendBroadcast(intent);
565 
566         resetValues();
567     }
568 
notifyExecuteWrite()569     private void notifyExecuteWrite() {
570         if (DEBUG) {
571             Log.d(TAG, "notifyExecuteWrite");
572         }
573         Intent intent = new Intent(BLE_EXECUTE_WRITE);
574         sendBroadcast(intent);
575 
576         resetValues();
577     }
578 
notifyReliableWriteBadResp()579     private void notifyReliableWriteBadResp() {
580         if (DEBUG) {
581             Log.d(TAG, "notifyReliableWriteBadResp");
582         }
583         Intent intent = new Intent(BLE_RELIABLE_WRITE_BAD_RESP);
584         sendBroadcast(intent);
585 
586         resetValues();
587     }
588 
getCharacteristic(UUID uuid)589     private BluetoothGattCharacteristic getCharacteristic(UUID uuid) {
590         BluetoothGattCharacteristic characteristic = mService.getCharacteristic(uuid);
591         if (characteristic == null) {
592             showMessage("Characteristic not found");
593         }
594         return characteristic;
595     }
596 
getDescriptor()597     private BluetoothGattDescriptor getDescriptor() {
598         BluetoothGattDescriptor descriptor = null;
599 
600         BluetoothGattCharacteristic characteristic = getCharacteristic(CHARACTERISTIC_UUID);
601         if (characteristic != null) {
602             descriptor = characteristic.getDescriptor(DESCRIPTOR_UUID);
603             if (descriptor == null) {
604                 showMessage("Descriptor not found");
605             }
606         }
607         return descriptor;
608     }
609 
610     /**
611      * Create service for notification test
612      * @return
613      */
createAdditionalNotificationService()614     private BluetoothGattService createAdditionalNotificationService() {
615         BluetoothGattService service =
616                 new BluetoothGattService(SERVICE_UUID_ADDITIONAL, BluetoothGattService.SERVICE_TYPE_PRIMARY);
617 
618         BluetoothGattCharacteristic notiCharacteristic =
619                 new BluetoothGattCharacteristic(UPDATE_CHARACTERISTIC_UUID_1, 0x12, 0x1);
620         BluetoothGattDescriptor descriptor = new BluetoothGattDescriptor(UPDATE_DESCRIPTOR_UUID, 0x11);
621         descriptor.setValue(BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE);
622         notiCharacteristic.addDescriptor(descriptor);
623         notiCharacteristic.setValue(NOTIFY_VALUE);
624         service.addCharacteristic(notiCharacteristic);
625 
626         notiCharacteristic =
627                 new BluetoothGattCharacteristic(UPDATE_CHARACTERISTIC_UUID_2, 0x14, 0x11);
628         descriptor = new BluetoothGattDescriptor(UPDATE_DESCRIPTOR_UUID, 0x11);
629         descriptor.setValue(BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE);
630         notiCharacteristic.addDescriptor(descriptor);
631         notiCharacteristic.setValue(NOTIFY_VALUE);
632         service.addCharacteristic(notiCharacteristic);
633 
634         notiCharacteristic =
635                 new BluetoothGattCharacteristic(UPDATE_CHARACTERISTIC_UUID_3, 0x16, 0x11);
636         descriptor = new BluetoothGattDescriptor(UPDATE_DESCRIPTOR_UUID, 0x11);
637         descriptor.setValue(BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE);
638         notiCharacteristic.addDescriptor(descriptor);
639         notiCharacteristic.setValue(NOTIFY_VALUE);
640         service.addCharacteristic(notiCharacteristic);
641 
642         notiCharacteristic =
643                 new BluetoothGattCharacteristic(UPDATE_CHARACTERISTIC_UUID_4, 0x18, 0x10);
644         descriptor = new BluetoothGattDescriptor(UPDATE_DESCRIPTOR_UUID, 0x11);
645         descriptor.setValue(BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE);
646         notiCharacteristic.addDescriptor(descriptor);
647         notiCharacteristic.setValue(NOTIFY_VALUE);
648         service.addCharacteristic(notiCharacteristic);
649 
650         notiCharacteristic =
651                 new BluetoothGattCharacteristic(UPDATE_CHARACTERISTIC_UUID_5, 0x1C, 0x11);
652         descriptor = new BluetoothGattDescriptor(UPDATE_DESCRIPTOR_UUID, 0x11);
653         descriptor.setValue(BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE);
654         notiCharacteristic.addDescriptor(descriptor);
655         notiCharacteristic.setValue(NOTIFY_VALUE);
656         service.addCharacteristic(notiCharacteristic);
657 
658         notiCharacteristic =
659                 new BluetoothGattCharacteristic(UPDATE_CHARACTERISTIC_UUID_11, 0x3A, 0x11);
660         descriptor = new BluetoothGattDescriptor(UPDATE_DESCRIPTOR_UUID, 0x11);
661         descriptor.setValue(BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE);
662         notiCharacteristic.addDescriptor(descriptor);
663         notiCharacteristic.setValue(NOTIFY_VALUE);
664         service.addCharacteristic(notiCharacteristic);
665 
666         notiCharacteristic =
667                 new BluetoothGattCharacteristic(UPDATE_CHARACTERISTIC_UUID_12, 0x3C, 0x11);
668         descriptor = new BluetoothGattDescriptor(UPDATE_DESCRIPTOR_UUID, 0x11);
669         descriptor.setValue(BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE);
670         notiCharacteristic.addDescriptor(descriptor);
671         notiCharacteristic.setValue(NOTIFY_VALUE);
672         service.addCharacteristic(notiCharacteristic);
673 
674         notiCharacteristic =
675                 new BluetoothGattCharacteristic(UPDATE_CHARACTERISTIC_UUID_13, 0x3E, 0x11);
676         descriptor = new BluetoothGattDescriptor(UPDATE_DESCRIPTOR_UUID, 0x11);
677         descriptor.setValue(BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE);
678         notiCharacteristic.addDescriptor(descriptor);
679         notiCharacteristic.setValue(NOTIFY_VALUE);
680         service.addCharacteristic(notiCharacteristic);
681 
682         notiCharacteristic =
683                 new BluetoothGattCharacteristic(UPDATE_CHARACTERISTIC_UUID_14, 0x10, 0x0);
684         descriptor = new BluetoothGattDescriptor(UPDATE_DESCRIPTOR_UUID, 0x11);
685         descriptor.setValue(BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE);
686         notiCharacteristic.addDescriptor(descriptor);
687         notiCharacteristic.setValue(NOTIFY_VALUE);
688         service.addCharacteristic(notiCharacteristic);
689 
690         notiCharacteristic =
691                 new BluetoothGattCharacteristic(UPDATE_CHARACTERISTIC_UUID_15, 0x30, 0x0);
692         descriptor = new BluetoothGattDescriptor(UPDATE_DESCRIPTOR_UUID, 0x11);
693         descriptor.setValue(BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE);
694         notiCharacteristic.addDescriptor(descriptor);
695         notiCharacteristic.setValue(NOTIFY_VALUE);
696         service.addCharacteristic(notiCharacteristic);
697 
698         return service;
699     }
700 
createService()701     private BluetoothGattService createService() {
702         BluetoothGattService service =
703                 new BluetoothGattService(SERVICE_UUID, BluetoothGattService.SERVICE_TYPE_PRIMARY);
704         BluetoothGattCharacteristic characteristic =
705                 new BluetoothGattCharacteristic(CHARACTERISTIC_UUID, 0x0A, 0x11);
706         characteristic.setValue(WRITE_VALUE.getBytes());
707 
708         BluetoothGattDescriptor descriptor = new BluetoothGattDescriptor(DESCRIPTOR_UUID, 0x11);
709         descriptor.setValue(WRITE_VALUE.getBytes());
710         characteristic.addDescriptor(descriptor);
711 
712         BluetoothGattDescriptor descriptor_permission = new BluetoothGattDescriptor(DESCRIPTOR_NO_READ_UUID, 0x10);
713         characteristic.addDescriptor(descriptor_permission);
714 
715         descriptor_permission = new BluetoothGattDescriptor(DESCRIPTOR_NO_WRITE_UUID, 0x01);
716         characteristic.addDescriptor(descriptor_permission);
717 
718         service.addCharacteristic(characteristic);
719 
720         characteristic =
721                 new BluetoothGattCharacteristic(CHARACTERISTIC_RESULT_UUID, 0x0A, 0x11);
722 
723         BluetoothGattDescriptor descriptor_encrypted = new BluetoothGattDescriptor(DESCRIPTOR_NEED_ENCRYPTED_READ_UUID, 0x02);
724         characteristic.addDescriptor(descriptor_encrypted);
725 
726         descriptor_encrypted = new BluetoothGattDescriptor(DESCRIPTOR_NEED_ENCRYPTED_WRITE_UUID, 0x20);
727         characteristic.addDescriptor(descriptor_encrypted);
728 
729         service.addCharacteristic(characteristic);
730 
731         // Add new Characteristics
732         // Registered the characteristic of read permission for operation confirmation.
733         characteristic =
734                 new BluetoothGattCharacteristic(CHARACTERISTIC_NO_READ_UUID, 0x0A, 0x10);
735         service.addCharacteristic(characteristic);
736 
737         // Registered the characteristic of write permission for operation confirmation.
738         characteristic =
739                 new BluetoothGattCharacteristic(CHARACTERISTIC_NO_WRITE_UUID, 0x0A, 0x01);
740         service.addCharacteristic(characteristic);
741 
742         // Registered the characteristic of authenticate (Encrypted) for operation confirmation.
743         characteristic =
744                 new BluetoothGattCharacteristic(CHARACTERISTIC_NEED_ENCRYPTED_READ_UUID, 0x0A, 0x02);
745         service.addCharacteristic(characteristic);
746 
747         characteristic =
748                 new BluetoothGattCharacteristic(CHARACTERISTIC_NEED_ENCRYPTED_WRITE_UUID, 0x0A, 0x20);
749         service.addCharacteristic(characteristic);
750 
751         // Add new Characteristics(Indicate)
752         BluetoothGattCharacteristic indicateCharacteristic =
753                 new BluetoothGattCharacteristic(INDICATE_CHARACTERISTIC_UUID, 0x2A, 0x11);
754         descriptor = new BluetoothGattDescriptor(UPDATE_DESCRIPTOR_UUID, 0x11);
755         descriptor.setValue(BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE);
756         indicateCharacteristic.addDescriptor(descriptor);
757         indicateCharacteristic.setValue(INDICATE_VALUE);
758         service.addCharacteristic(indicateCharacteristic);
759 
760         // Add new Characteristics(Notify)
761         BluetoothGattCharacteristic notiCharacteristic =
762                 new BluetoothGattCharacteristic(UPDATE_CHARACTERISTIC_UUID, 0x1A, 0x11);
763         descriptor = new BluetoothGattDescriptor(UPDATE_DESCRIPTOR_UUID, 0x11);
764         descriptor.setValue(BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE);
765         notiCharacteristic.addDescriptor(descriptor);
766         notiCharacteristic.setValue(NOTIFY_VALUE);
767         service.addCharacteristic(notiCharacteristic);
768 
769         notiCharacteristic =
770                 new BluetoothGattCharacteristic(UPDATE_CHARACTERISTIC_UUID_6, 0x1E, 0x11);
771         descriptor = new BluetoothGattDescriptor(UPDATE_DESCRIPTOR_UUID, 0x11);
772         descriptor.setValue(BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE);
773         notiCharacteristic.addDescriptor(descriptor);
774         notiCharacteristic.setValue(NOTIFY_VALUE);
775         service.addCharacteristic(notiCharacteristic);
776 
777         notiCharacteristic =
778                 new BluetoothGattCharacteristic(UPDATE_CHARACTERISTIC_UUID_7, 0x32, 0x1);
779         descriptor = new BluetoothGattDescriptor(UPDATE_DESCRIPTOR_UUID, 0x11);
780         descriptor.setValue(BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE);
781         notiCharacteristic.addDescriptor(descriptor);
782         notiCharacteristic.setValue(NOTIFY_VALUE);
783         service.addCharacteristic(notiCharacteristic);
784 
785         notiCharacteristic =
786                 new BluetoothGattCharacteristic(UPDATE_CHARACTERISTIC_UUID_8, 0x34, 0x11);
787         descriptor = new BluetoothGattDescriptor(UPDATE_DESCRIPTOR_UUID, 0x11);
788         descriptor.setValue(BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE);
789         notiCharacteristic.addDescriptor(descriptor);
790         notiCharacteristic.setValue(NOTIFY_VALUE);
791         service.addCharacteristic(notiCharacteristic);
792 
793         notiCharacteristic =
794                 new BluetoothGattCharacteristic(UPDATE_CHARACTERISTIC_UUID_9, 0x36, 0x11);
795         descriptor = new BluetoothGattDescriptor(UPDATE_DESCRIPTOR_UUID, 0x11);
796         descriptor.setValue(BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE);
797         notiCharacteristic.addDescriptor(descriptor);
798         notiCharacteristic.setValue(NOTIFY_VALUE);
799         service.addCharacteristic(notiCharacteristic);
800 
801         notiCharacteristic =
802                 new BluetoothGattCharacteristic(UPDATE_CHARACTERISTIC_UUID_10, 0x38, 0x10);
803         descriptor = new BluetoothGattDescriptor(UPDATE_DESCRIPTOR_UUID, 0x11);
804         descriptor.setValue(BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE);
805         notiCharacteristic.addDescriptor(descriptor);
806         notiCharacteristic.setValue(NOTIFY_VALUE);
807         service.addCharacteristic(notiCharacteristic);
808 
809         return service;
810     }
811 
showMessage(final String msg)812     private void showMessage(final String msg) {
813         mHandler.post(new Runnable() {
814             public void run() {
815                 Toast.makeText(BleServerService.this, msg, Toast.LENGTH_SHORT).show();
816             }
817         });
818     }
819 
onMtuTestDataReceive()820     private void onMtuTestDataReceive() {
821 
822         Log.d(TAG, "onMtuTestDataReceive(" + mCountMtuChange + "):" + mMtuTestReceivedData);
823 
824         // verify
825         if (mMtuTestReceivedData.equals(BleClientService.WRITE_VALUE_512BYTES_FOR_MTU)) {
826 
827             // write back data
828             // MTU test verifies whether the write/read operations go well.
829             BluetoothGattCharacteristic characteristic = getCharacteristic(CHARACTERISTIC_UUID);
830             characteristic.setValue(mMtuTestReceivedData.getBytes());
831 
832             notifyMtuRequest();
833         } else {
834             showMessage(getString(R.string.ble_mtu_fail_message));
835         }
836         mMtuTestReceivedData = "";
837         if (mCountMtuChange >= 2) {
838             // All MTU change tests completed
839             mCountMtuChange = 0;
840         }
841     }
842 
cancelNotificationTaskOfSecureTestStartFailure()843     private synchronized void cancelNotificationTaskOfSecureTestStartFailure() {
844         if (mNotificationTaskOfSecureTestStartFailure != null) {
845             mHandler.removeCallbacks(mNotificationTaskOfSecureTestStartFailure);
846             mNotificationTaskOfSecureTestStartFailure = null;
847         }
848     }
849 
850     private final BluetoothGattServerCallback mCallbacks = new BluetoothGattServerCallback() {
851         @Override
852         public void onConnectionStateChange(BluetoothDevice device, int status, int newState) {
853             if (DEBUG) {
854                 Log.d(TAG, "onConnectionStateChange: newState=" + newState);
855             }
856 
857             if (status == BluetoothGatt.GATT_SUCCESS) {
858                 if (newState == BluetoothProfile.STATE_CONNECTED) {
859                     mDevice = device;
860                     boolean bonded = false;
861                     Set<BluetoothDevice> pairedDevices = mBluetoothManager.getAdapter().getBondedDevices();
862                     if (pairedDevices.size() > 0) {
863                         for (BluetoothDevice target : pairedDevices) {
864                             if (target.getAddress().equals(device.getAddress())) {
865                                 bonded = true;
866                                 break;
867                             }
868                         }
869                     }
870 
871                     if (mSecure && ((device.getBondState() == BluetoothDevice.BOND_NONE) || !bonded)) {
872                         // not pairing and execute Secure Test
873                         cancelNotificationTaskOfSecureTestStartFailure();
874                         /*
875                         mNotificationTaskOfSecureTestStartFailure = new Runnable() {
876                             @Override
877                             public void run() {
878                                 mNotificationTaskOfSecureTestStartFailure = null;
879                                 if (mSecure && (mDevice.getBondState() != BluetoothDevice.BOND_BONDED)) {
880                                     notifyMismatchSecure();
881                                 }
882                             }
883                         };
884                         mHandler.postDelayed(mNotificationTaskOfSecureTestStartFailure,
885                                 NOTIFICATION_DELAY_OF_SECURE_TEST_FAILURE);
886                         */
887                     } else if (!mSecure && ((device.getBondState() != BluetoothDevice.BOND_NONE) || bonded)) {
888                         // already pairing nad execute Insecure Test
889                         /*
890                         notifyMismatchInsecure();
891                         */
892                     } else {
893                         cancelNotificationTaskOfSecureTestStartFailure();
894                         notifyConnected();
895                     }
896                 } else if (status == BluetoothProfile.STATE_DISCONNECTED) {
897                     notifyDisconnected();
898                     mDevice = null;
899                 }
900             }
901         }
902 
903         @Override
904         public void onServiceAdded(int status, BluetoothGattService service) {
905             if (DEBUG) {
906                 Log.d(TAG, "onServiceAdded(): " + service.getUuid());
907                 dumpService(service, 0);
908             }
909             if (status == BluetoothGatt.GATT_SUCCESS) {
910                 UUID uuid = service.getUuid();
911 
912                 if (uuid.equals(mService.getUuid())) {
913                     // create and add nested service
914                     BluetoothGattService includedService =
915                             new BluetoothGattService(SERVICE_UUID_INCLUDED, BluetoothGattService.SERVICE_TYPE_SECONDARY);
916                     BluetoothGattCharacteristic characteristic =
917                         new BluetoothGattCharacteristic(CHARACTERISTIC_UUID, 0x0A, 0x11);
918                     characteristic.setValue(WRITE_VALUE.getBytes());
919                     BluetoothGattDescriptor descriptor = new BluetoothGattDescriptor(DESCRIPTOR_UUID, 0x11);
920                     descriptor.setValue(WRITE_VALUE.getBytes());
921                     characteristic.addDescriptor(descriptor);
922                     includedService.addCharacteristic(characteristic);
923                     mGattServer.addService(includedService);
924                 } else if (uuid.equals(SERVICE_UUID_INCLUDED)) {
925                     mService.addService(service);
926                     mGattServer.addService(mAdditionalNotificationService);
927                 } else if (uuid.equals(mAdditionalNotificationService.getUuid())) {
928                     // all services added
929                     notifyServiceAdded();
930                 } else {
931                     notifyAddServiceFail();
932                 }
933             } else {
934                 notifyAddServiceFail();
935             }
936         }
937 
938         @Override
939         public void onCharacteristicReadRequest(BluetoothDevice device, int requestId, int offset, BluetoothGattCharacteristic characteristic) {
940             if (mGattServer == null) {
941                 if (DEBUG) {
942                     Log.d(TAG, "GattServer is null, return");
943                 }
944                 return;
945             }
946             if (DEBUG) {
947                 Log.d(TAG, "onCharacteristicReadRequest()");
948             }
949 
950             boolean finished = false;
951             byte[] value = null;
952             if (mMtuSize > 0) {
953                 byte[] buf = characteristic.getValue();
954                 if (buf != null) {
955                     int len = Math.min((buf.length - offset), mMtuSize);
956                     if (len > 0) {
957                         value = Arrays.copyOfRange(buf, offset, (offset + len));
958                     }
959                     finished = ((offset + len) >= buf.length);
960                     if (finished) {
961                         Log.d(TAG, "sent whole data: " + (new String(characteristic.getValue())));
962                     }
963                 }
964             } else {
965                 value = characteristic.getValue();
966                 finished = true;
967             }
968 
969             mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, value);
970 
971             UUID uid = characteristic.getUuid();
972             if (uid.equals(CHARACTERISTIC_NEED_ENCRYPTED_READ_UUID)) {
973                 notifyCharacteristicReadRequestNeedEncrypted();
974             } else {
975                 notifyCharacteristicReadRequest(finished);
976             }
977         }
978 
979         @Override
980         public void onCharacteristicWriteRequest(BluetoothDevice device, int requestId,
981                 BluetoothGattCharacteristic characteristic,
982                 boolean preparedWrite, boolean responseNeeded,
983                 int offset, byte[] value) {
984             if (mGattServer == null) {
985                 if (DEBUG) {
986                     Log.d(TAG, "GattServer is null, return");
987                 }
988                 return;
989             }
990             if (DEBUG) {
991                 Log.d(TAG, "onCharacteristicWriteRequest: preparedWrite=" + preparedWrite + ", responseNeeded= " + responseNeeded);
992             }
993 
994             if (characteristic.getUuid().equals(CHARACTERISTIC_RESULT_UUID)) {
995                 String resValue = new String(value);
996                 Log.d(TAG, "CHARACTERISTIC_RESULT_UUID: resValue=" + resValue);
997                 switch (resValue) {
998                     case WRITE_NO_PERMISSION:
999                         notifyCharacteristicWriteRequestWithoutPermission();
1000                         break;
1001                     case READ_NO_PERMISSION:
1002                         notifyCharacteristicReadRequestWithoutPermission();
1003                         break;
1004                     case DESCRIPTOR_WRITE_NO_PERMISSION:
1005                         notifyDescriptorWriteRequestWithoutPermission();
1006                         break;
1007                     case DESCRIPTOR_READ_NO_PERMISSION:
1008                         notifyDescriptorReadRequestWithoutPermission();
1009                         break;
1010                 }
1011                 if (responseNeeded) {
1012                     mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, value);
1013                 }
1014                 return;
1015             }
1016 
1017             // MTU test flow
1018             if (mCountMtuChange > 0) {
1019                 if (preparedWrite) {
1020                     mMtuTestReceivedData += new String(value);
1021                 } else {
1022                     String strValue = new String(value);
1023                     if (mCountMtuChange > 0) {
1024                         mMtuTestReceivedData = strValue;
1025                         onMtuTestDataReceive();
1026                     }
1027                 }
1028                 if (responseNeeded) {
1029                     mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, value);
1030                 }
1031 
1032                 return;
1033             }
1034 
1035             // Reliable write with bad response test flow
1036             String valueStr = new String(value);
1037             if (BleClientService.WRITE_VALUE_BAD_RESP.equals(valueStr)) {
1038                 mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, 0, null);
1039                 notifyReliableWriteBadResp();
1040                 return;
1041             }
1042 
1043             if (preparedWrite) {
1044                 mReliableWriteValue += (new String(value));
1045             } else {
1046                 characteristic.setValue(value);
1047                 // verify
1048                 if (Arrays.equals(BleClientService.WRITE_VALUE.getBytes(), characteristic.getValue())) {
1049                     UUID uid = characteristic.getUuid();
1050                     if (uid.equals(CHARACTERISTIC_NEED_ENCRYPTED_WRITE_UUID)) {
1051                         notifyCharacteristicWriteRequestNeedEncrypted();
1052                     } else {
1053                         notifyCharacteristicWriteRequest();
1054                     }
1055                 } else {
1056                     showMessage("Written data is not correct");
1057                 }
1058             }
1059 
1060             if (responseNeeded) {
1061                 mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, value);
1062             }
1063         }
1064 
1065         @Override
1066         public void onDescriptorReadRequest(BluetoothDevice device, int requestId,
1067                 int offset, BluetoothGattDescriptor descriptor) {
1068             if (mGattServer == null) {
1069                 if (DEBUG) {
1070                     Log.d(TAG, "GattServer is null, return");
1071                 }
1072                 return;
1073             }
1074                 if (DEBUG) {
1075                 Log.d(TAG, "onDescriptorReadRequest(): (descriptor == getDescriptor())="
1076                         + (descriptor == getDescriptor()));
1077             }
1078 
1079             UUID uid = descriptor.getUuid();
1080             if (uid.equals(DESCRIPTOR_NEED_ENCRYPTED_READ_UUID)){
1081                 notifyDescriptorReadRequestNeedEncrypted();
1082             } else {
1083                 notifyDescriptorReadRequest();
1084             }
1085 
1086             byte[] value = descriptor.getValue();
1087             if (value == null) {
1088                 throw new RuntimeException("descriptor data read is null");
1089             }
1090 
1091             mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, value);
1092         }
1093 
1094         @Override
1095         public void onDescriptorWriteRequest(BluetoothDevice device, int requestId,
1096                 BluetoothGattDescriptor descriptor,
1097                 boolean preparedWrite, boolean responseNeeded,
1098                 int offset,  byte[] value) {
1099             if (mGattServer == null) {
1100                 if (DEBUG) {
1101                     Log.d(TAG, "GattServer is null, return");
1102                 }
1103                 return;
1104             }
1105             BluetoothGattCharacteristic characteristic = descriptor.getCharacteristic();
1106             UUID uid = characteristic.getUuid();
1107             if (DEBUG) {
1108                 Log.d(TAG, "onDescriptorWriteRequest: preparedWrite=" + preparedWrite + ", responseNeeded= " + responseNeeded);
1109                 Log.d(TAG, "   characteristic uuid = " + uid);
1110             }
1111 
1112             descriptor.setValue(value);
1113             UUID duid = descriptor.getUuid();
1114             // If there is a written request to the CCCD for Notify.
1115             if (duid.equals(UPDATE_DESCRIPTOR_UUID)) {
1116                 if (Arrays.equals(value, BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE)) {
1117                     mGattServer.notifyCharacteristicChanged(mDevice, descriptor.getCharacteristic(), false);
1118                     mIndicated = false;
1119                 } else if (Arrays.equals(value, BluetoothGattDescriptor.ENABLE_INDICATION_VALUE)) {
1120                     mGattServer.notifyCharacteristicChanged(mDevice, descriptor.getCharacteristic(), true);
1121                     mIndicated = true;
1122                 }
1123             } else if (duid.equals(DESCRIPTOR_NEED_ENCRYPTED_WRITE_UUID)) {
1124                 // verify
1125                 if (Arrays.equals(BleClientService.WRITE_VALUE.getBytes(), descriptor.getValue())) {
1126                     notifyDescriptorWriteRequestNeedEncrypted();
1127                 } else {
1128                     showMessage("Written data is not correct");
1129                 }
1130             } else {
1131                 // verify
1132                 if (Arrays.equals(BleClientService.WRITE_VALUE.getBytes(), descriptor.getValue())) {
1133                     notifyDescriptorWriteRequest();
1134                 } else {
1135                     showMessage("Written data is not correct");
1136                 }
1137             }
1138             if (responseNeeded) {
1139                 mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, value);
1140             }
1141         }
1142 
1143         @Override
1144         public void onExecuteWrite(BluetoothDevice device, int requestId, boolean execute) {
1145             if (mGattServer == null) {
1146                 if (DEBUG) {
1147                     Log.d(TAG, "GattServer is null, return");
1148                 }
1149                 return;
1150             }
1151             if (DEBUG) {
1152                 Log.d(TAG, "onExecuteWrite");
1153             }
1154 
1155             if (execute) {
1156                 if (mCountMtuChange > 0) {
1157                     onMtuTestDataReceive();
1158                 } else {
1159                     // verify
1160                     String str = BleClientService.WRITE_VALUE_507BYTES_FOR_RELIABLE_WRITE
1161                             + BleClientService.WRITE_VALUE_507BYTES_FOR_RELIABLE_WRITE;
1162                     if (str.equals(mReliableWriteValue)) {
1163                         notifyExecuteWrite();
1164                     } else {
1165                         showMessage("Failed to receive data");
1166                         Log.d(TAG, "Failed to receive data:" + mReliableWriteValue);
1167                     }
1168                 }
1169                 mReliableWriteValue = "";
1170             }
1171             mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, 0, null);
1172         }
1173 
1174         @Override
1175         public void onNotificationSent(BluetoothDevice device, int status) {
1176             if (mGattServer == null) {
1177                 if (DEBUG) {
1178                     Log.d(TAG, "GattServer is null, return");
1179                 }
1180                 return;
1181             }
1182             if (DEBUG) {
1183                 Log.d(TAG, "onNotificationSent");
1184             }
1185 
1186             if (status == BluetoothGatt.GATT_SUCCESS) {
1187                 if (mIndicated) {
1188                     notifyCharacteristicIndicationRequest();
1189                 } else {
1190                     mNotifyCount--;
1191                     if (mNotifyCount == 0) {
1192                         notifyCharacteristicNotificationRequest();
1193                     }
1194                 }
1195             }
1196         }
1197 
1198         @Override
1199         public void onMtuChanged(BluetoothDevice device, int mtu) {
1200             if (mGattServer == null) {
1201                 if (DEBUG) {
1202                     Log.d(TAG, "GattServer is null, return");
1203                 }
1204                 return;
1205             }
1206             if (DEBUG) {
1207                 Log.d(TAG, "onMtuChanged");
1208             }
1209 
1210             mMtuSize = mtu;
1211             if (mCountMtuChange == 0) {
1212                 if (mtu != 23) {
1213                     String msg = String.format(getString(R.string.ble_mtu_mismatch_message),
1214                             23, mtu);
1215                     showMessage(msg);
1216                 }
1217             } else if (mCountMtuChange == 1) {
1218                 if (mtu != 512) {
1219                     String msg = String.format(getString(R.string.ble_mtu_mismatch_message),
1220                             512, mtu);
1221                     showMessage(msg);
1222                 }
1223             }
1224             mMtuTestReceivedData = "";
1225             ++mCountMtuChange;
1226         }
1227     };
1228 
startAdvertise()1229     private void startAdvertise() {
1230         if (DEBUG) {
1231             Log.d(TAG, "startAdvertise");
1232         }
1233         AdvertiseData data = new AdvertiseData.Builder()
1234             .addServiceData(new ParcelUuid(ADV_SERVICE_UUID), new byte[]{1,2,3})
1235             .addServiceUuid(new ParcelUuid(ADV_SERVICE_UUID))
1236             .build();
1237         AdvertiseSettings setting = new AdvertiseSettings.Builder()
1238             .setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_LOW_LATENCY)
1239             .setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_MEDIUM)
1240             .setConnectable(true)
1241             .build();
1242         mAdvertiser.startAdvertising(setting, data, mAdvertiseCallback);
1243     }
1244 
stopAdvertise()1245     private void stopAdvertise() {
1246         if (DEBUG) {
1247             Log.d(TAG, "stopAdvertise");
1248         }
1249         if (mAdvertiser != null) {
1250             mAdvertiser.stopAdvertising(mAdvertiseCallback);
1251         }
1252     }
1253 
1254     private final AdvertiseCallback mAdvertiseCallback = new AdvertiseCallback(){
1255         @Override
1256         public void onStartFailure(int errorCode) {
1257             // Implementation for API Test.
1258             super.onStartFailure(errorCode);
1259             if (DEBUG) {
1260                 Log.d(TAG, "onStartFailure");
1261             }
1262 
1263             if (errorCode == ADVERTISE_FAILED_FEATURE_UNSUPPORTED) {
1264                 notifyAdvertiseUnsupported();
1265             } else {
1266                 notifyOpenFail();
1267             }
1268         }
1269 
1270         @Override
1271         public void onStartSuccess(AdvertiseSettings settingsInEffect) {
1272             // Implementation for API Test.
1273             super.onStartSuccess(settingsInEffect);
1274             if (DEBUG) {
1275                 Log.d(TAG, "onStartSuccess");
1276             }
1277         }
1278     };
1279 
dumpService(BluetoothGattService service, int level)1280     /*protected*/ static void dumpService(BluetoothGattService service, int level) {
1281         String indent = "";
1282         for (int i = 0; i < level; ++i) {
1283             indent += "  ";
1284         }
1285 
1286         Log.d(TAG, indent + "[service]");
1287         Log.d(TAG, indent + "UUID: " + service.getUuid());
1288         Log.d(TAG, indent + "  [characteristics]");
1289         for (BluetoothGattCharacteristic ch : service.getCharacteristics()) {
1290             Log.d(TAG, indent + "    UUID: " + ch.getUuid());
1291             Log.d(TAG, indent + "      properties: " + String.format("0x%02X", ch.getProperties()));
1292             Log.d(TAG, indent + "      permissions: " + String.format("0x%02X", ch.getPermissions()));
1293             Log.d(TAG, indent + "      [descriptors]");
1294             for (BluetoothGattDescriptor d : ch.getDescriptors()) {
1295                 Log.d(TAG, indent + "        UUID: " + d.getUuid());
1296                 Log.d(TAG, indent + "          permissions: " + String.format("0x%02X", d.getPermissions()));
1297             }
1298         }
1299 
1300         if (service.getIncludedServices() != null) {
1301             Log.d(TAG, indent + "  [included services]");
1302             for (BluetoothGattService s : service.getIncludedServices()) {
1303                 dumpService(s, level+1);
1304             }
1305         }
1306     }
1307 
1308 }
1309 
1310