@Override
    public final void onCharacteristicChanged(
        final BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic) {
      final String data = ParserUtils.parse(characteristic);

      if (isBatteryLevelCharacteristic(characteristic)) {
        Logger.i(
            mLogSession,
            "Notification received from " + characteristic.getUuid() + ", value: " + data);
        final int batteryValue =
            characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, 0);
        Logger.a(mLogSession, "Battery level received: " + batteryValue + "%");
        mCallbacks.onBatteryValueReceived(batteryValue);
      } else {
        final BluetoothGattDescriptor cccd =
            characteristic.getDescriptor(CLIENT_CHARACTERISTIC_CONFIG_DESCRIPTOR_UUID);
        final boolean notifications =
            cccd == null
                || cccd.getValue() == null
                || cccd.getValue().length != 2
                || cccd.getValue()[0] == 0x01;

        if (notifications) {
          Logger.i(
              mLogSession,
              "Notification received from " + characteristic.getUuid() + ", value: " + data);
          onCharacteristicNotified(gatt, characteristic);
        } else { // indications
          Logger.i(
              mLogSession,
              "Indication received from " + characteristic.getUuid() + ", value: " + data);
          onCharacteristicIndicated(gatt, characteristic);
        }
      }
    }
    @Override
    public final void onDescriptorWrite(
        final BluetoothGatt gatt, final BluetoothGattDescriptor descriptor, final int status) {
      if (status == BluetoothGatt.GATT_SUCCESS) {
        Logger.i(
            mLogSession,
            "Data written to descr. "
                + descriptor.getUuid()
                + ", value: "
                + ParserUtils.parse(descriptor));

        if (isServiceChangedCCCD(descriptor)) {
          Logger.a(mLogSession, "Service Changed notifications enabled");
          if (!readBatteryLevel()) nextRequest();
        } else if (isBatteryLevelCCCD(descriptor)) {
          final byte[] value = descriptor.getValue();
          if (value != null && value.length > 0 && value[0] == 0x01) {
            Logger.a(mLogSession, "Battery Level notifications enabled");
            nextRequest();
          } else Logger.a(mLogSession, "Battery Level notifications disabled");
        } else {
          nextRequest();
        }
      } else if (status == BluetoothGatt.GATT_INSUFFICIENT_AUTHENTICATION) {
        if (gatt.getDevice().getBondState() != BluetoothDevice.BOND_NONE) {
          DebugLogger.w(TAG, ERROR_AUTH_ERROR_WHILE_BONDED);
          mCallbacks.onError(ERROR_AUTH_ERROR_WHILE_BONDED, status);
        }
      } else {
        DebugLogger.e(TAG, "onDescriptorWrite error " + status);
        onError(ERROR_WRITE_DESCRIPTOR, status);
      }
    }
  public JSONObject asJSONObject(BluetoothGatt gatt) {

    JSONObject json = asJSONObject();

    try {
      JSONArray servicesArray = new JSONArray();
      JSONArray characteristicsArray = new JSONArray();
      json.put("services", servicesArray);
      json.put("characteristics", characteristicsArray);

      if (connected && gatt != null) {
        for (BluetoothGattService service : gatt.getServices()) {
          servicesArray.put(UUIDHelper.uuidToString(service.getUuid()));

          for (BluetoothGattCharacteristic characteristic : service.getCharacteristics()) {
            JSONObject characteristicsJSON = new JSONObject();
            characteristicsArray.put(characteristicsJSON);

            characteristicsJSON.put("service", UUIDHelper.uuidToString(service.getUuid()));
            characteristicsJSON.put(
                "characteristic", UUIDHelper.uuidToString(characteristic.getUuid()));
            // characteristicsJSON.put("instanceId", characteristic.getInstanceId());

            characteristicsJSON.put("properties", Helper.decodeProperties(characteristic));
            // characteristicsJSON.put("propertiesValue", characteristic.getProperties());

            if (characteristic.getPermissions() > 0) {
              characteristicsJSON.put("permissions", Helper.decodePermissions(characteristic));
              // characteristicsJSON.put("permissionsValue", characteristic.getPermissions());
            }

            JSONArray descriptorsArray = new JSONArray();

            for (BluetoothGattDescriptor descriptor : characteristic.getDescriptors()) {
              JSONObject descriptorJSON = new JSONObject();
              descriptorJSON.put("uuid", UUIDHelper.uuidToString(descriptor.getUuid()));
              descriptorJSON.put("value", descriptor.getValue()); // always blank

              if (descriptor.getPermissions() > 0) {
                descriptorJSON.put("permissions", Helper.decodePermissions(descriptor));
                // descriptorJSON.put("permissionsValue", descriptor.getPermissions());
              }
              descriptorsArray.put(descriptorJSON);
            }
            if (descriptorsArray.length() > 0) {
              characteristicsJSON.put("descriptors", descriptorsArray);
            }
          }
        }
      }
    } catch (JSONException e) { // TODO better error handling
      e.printStackTrace();
    }

    return json;
  }
  private void displayGattServices(List<BluetoothGattService> gattServices) {
    if (gattServices == null) return;

    for (BluetoothGattService gattService : gattServices) {
      // -----Service的字段信息-----//
      int type = gattService.getType();
      Log.e(TAG, "-->service type:" + Utils.getServiceType(type));
      Log.e(TAG, "-->includedServices size:" + gattService.getIncludedServices().size());
      Log.e(TAG, "-->service uuid:" + gattService.getUuid());

      // -----Characteristics的字段信息-----//
      List<BluetoothGattCharacteristic> gattCharacteristics = gattService.getCharacteristics();
      for (final BluetoothGattCharacteristic gattCharacteristic : gattCharacteristics) {
        Log.e(TAG, "---->char uuid:" + gattCharacteristic.getUuid());

        int permission = gattCharacteristic.getPermissions();
        Log.e(TAG, "---->char permission:" + Utils.getCharPermission(permission));

        int property = gattCharacteristic.getProperties();
        Log.e(TAG, "---->char property:" + Utils.getCharPropertie(property));

        byte[] data = gattCharacteristic.getValue();
        if (data != null && data.length > 0) {
          Log.e(TAG, "---->char value:" + Utils.bytesToHexString(data));
        }

        if (gattService.getUuid().toString().equals(UUID_KEY_SERVICE)) { // 如果是温度计的service
          // UUID_KEY_DATA是可以跟蓝牙模块串口通信的Characteristic
          if (gattCharacteristic.getUuid().toString().equals(UUID_KEY_DATA_RECIV)) {
            // 测试读取当前Characteristic数据,会触发mOnDataAvailable.onCharacteristicRead()
            mHandler.postDelayed(
                new Runnable() {
                  @Override
                  public void run() {
                    mBLE_reciv.readCharacteristic(gattCharacteristic);
                  }
                },
                500);

            // 接受Characteristic被写的通知,收到蓝牙模块的数据后会触发mOnDataAvailable.onCharacteristicWrite()
            mBLE_reciv.setCharacteristicNotification(gattCharacteristic, true);
            BluetoothGattDescriptor localBluetoothGattDescriptor =
                gattCharacteristic.getDescriptor(UUID.fromString(CCC));
            localBluetoothGattDescriptor.setValue(
                BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
            mBluetoothGatt.writeDescriptor(localBluetoothGattDescriptor);
            appState.gattCharacteristic_reciv_dianzichen = gattCharacteristic;
            // 设置数据内容
            //            			gattCharacteristic.setValue("0");
            // 往蓝牙模块写入数据
            //            			appState.mBLE_reciv_dianzichen.writeCharacteristic(gattCharacteristic);
          }

          // UUID_KEY_DATA是可以跟蓝牙模块串口通信的Characteristic
          if (gattCharacteristic.getUuid().toString().equals(UUID_KEY_DATA_SEND)) {
            // 测试读取当前Characteristic数据,会触发mOnDataAvailable.onCharacteristicRead()
            mHandler.postDelayed(
                new Runnable() {
                  @Override
                  public void run() {
                    mBLE_send.readCharacteristic(gattCharacteristic);
                    // Log.i("info", "appState.mBLE_send_dianzichen 尝试读数据");
                  }
                },
                500);

            // 接受Characteristic被写的通知,收到蓝牙模块的数据后会触发mOnDataAvailable.onCharacteristicWrite()
            mBLE_send.setCharacteristicNotification(gattCharacteristic, true);
            // 设置数据内容
            // gattCharacteristic.setValue("send data->");
            // 往蓝牙模块写入数据
            // mBLE_send.writeCharacteristic(gattCharacteristic);

            if (!appState.firstActivityRunning) {
              appState.gattCharacteristic_send_dianzichen = gattCharacteristic;

              appState.file.write2SDFromInput("inurse/", "Dianzichen.txt", appState.deviceAddress);

              Intent it = new Intent(this, DianzichenActivity.class);
              startActivityForResult(it, 0); // 配合onActivityResult,当FirstActivity退出时获得一个0值,然后自己也退出
              //            				moveTaskToBack(true); //这一句是整个程序返回桌面
              appState.firstActivityRunning = true;
            }
          }
        } // 结束 if ( gattService.getUuid().toString().equals(UUID_KEY_SERVICE) )

        // -----Descriptors的字段信息-----//
        List<BluetoothGattDescriptor> gattDescriptors = gattCharacteristic.getDescriptors();
        for (BluetoothGattDescriptor gattDescriptor : gattDescriptors) {
          Log.e(TAG, "-------->desc uuid:" + gattDescriptor.getUuid());
          int descPermission = gattDescriptor.getPermissions();
          Log.e(TAG, "-------->desc permission:" + Utils.getDescPermission(descPermission));

          byte[] desData = gattDescriptor.getValue();
          if (desData != null && desData.length > 0) {
            Log.e(TAG, "-------->desc value:" + Utils.bytesToHexString(data));
          }

          // soloman 接收的uuid要设置CCC通知enable,并回写到BluetoothGatt
          //					if (gattDescriptor.getUuid().toString().equals(CCC)){
          //						gattDescriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
          //						mBluetoothGatt.writeDescriptor(gattDescriptor);
          //					}
        }
      }
    } //
  }