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