title: Android bluetooth low energy characteristic value
body: <p>I have this code on android app that I have edited but I'm having a problem on getting the characteristic value to set on <code>mHumidity</code> (<code>TextView</code>). the value being display is something like <code>android.bluetooth.BluetoothGatt@4780c</code> something like that. But my expected value is 0 or 1 from a button pushed on my BLE device</p>
  
  <pre><code>/**
   * Created by Dave Smith
   * Double Encore, Inc.
   * MainActivity
   */
  public class MainActivity extends Activity implements BluetoothAdapter.LeScanCallback {
          private static final String TAG = "BluetoothGattActivity";
  
          private static final String DEVICE_NAME = "Light";
  
          /* Humidity Service */
          private static final UUID HUMIDITY_SERVICE = UUID.fromString("29e70001-9227-e097-3473-09a5cc69a43a");
          private static final UUID HUMIDITY_DATA_CHAR = UUID.fromString("29e70002-9227-e097-3473-09a5cc69a43a");
          private static final UUID HUMIDITY_CONFIG_CHAR = UUID.fromString("29e70003-9227-e097-3473-09a5cc69a43a");
  
          /* Client Configuration Descriptor */
          private static final UUID CONFIG_DESCRIPTOR = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb");
  
  
      private BluetoothAdapter mBluetoothAdapter;
      private SparseArray&lt;BluetoothDevice&gt; mDevices;
  
      private BluetoothGatt mConnectedGatt;
  
      private TextView mTemperature, mHumidity, mPressure;
  
      private ProgressDialog mProgress;
  
      @Override
      protected void onCreate(Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);
          requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
          setContentView(R.layout.activity_main);
          setProgressBarIndeterminate(true);
          /*
           * We are going to display the results in some text fields
           */
      //    mTemperature = (TextView) findViewById(R.id.text_temperature);
          mHumidity = (TextView) findViewById(R.id.text_humidity);
      //    mPressure = (TextView) findViewById(R.id.text_pressure);
          /*
           * Bluetooth in Android 4.3 is accessed via the BluetoothManager, rather than
           * the old static BluetoothAdapter.getInstance()
           */
          BluetoothManager manager = (BluetoothManager) getSystemService(BLUETOOTH_SERVICE);
          mBluetoothAdapter = manager.getAdapter();
  
          mDevices = new SparseArray&lt;BluetoothDevice&gt;();
  
          /*
           * A progress dialog will be needed while the connection process is
           * taking place
           */
          mProgress = new ProgressDialog(this);
          mProgress.setIndeterminate(true);
          mProgress.setCancelable(false);
      }
  
      @Override
      protected void onResume() {
          super.onResume();
          /*
           * We need to enforce that Bluetooth is first enabled, and take the
           * user to settings to enable it if they have not done so.
           */
          if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) {
              //Bluetooth is disabled
              Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
              startActivity(enableBtIntent);
              finish();
              return;
          }
  
          /*
           * Check for Bluetooth LE Support.  In production, our manifest entry will keep this
           * from installing on these devices, but this will allow test devices or other
           * sideloads to report whether or not the feature exists.
           */
          if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
              Toast.makeText(this, "No LE Support.", Toast.LENGTH_SHORT).show();
              finish();
              return;
          }
  
          clearDisplayValues();
      }
  
      @Override
      protected void onPause() {
          super.onPause();
          //Make sure dialog is hidden
          mProgress.dismiss();
          //Cancel any scans in progress
          mHandler.removeCallbacks(mStopRunnable);
          mHandler.removeCallbacks(mStartRunnable);
          mBluetoothAdapter.stopLeScan(this);
      }
  
      @Override
      protected void onStop() {
          super.onStop();
          //Disconnect from any active tag connection
          if (mConnectedGatt != null) {
              mConnectedGatt.disconnect();
              mConnectedGatt = null;
          }
      }
  
      @Override
      public boolean onCreateOptionsMenu(Menu menu) {
          // Add the "scan" option to the menu
          getMenuInflater().inflate(R.menu.main, menu);
          //Add any device elements we've discovered to the overflow menu
          for (int i=0; i &lt; mDevices.size(); i++) {
              BluetoothDevice device = mDevices.valueAt(i);
              menu.add(0, mDevices.keyAt(i), 0, device.getName());
          }
  
          return true;
      }
  
      @Override
      public boolean onOptionsItemSelected(MenuItem item) {
          switch (item.getItemId()) {
              case R.id.action_scan:
                  mDevices.clear();
                  startScan();
                  return true;
              default:
                  //Obtain the discovered device to connect with
                  BluetoothDevice device = mDevices.get(item.getItemId());
                  Log.i(TAG, "Connecting to "+device.getName());
                  /*
                   * Make a connection with the device using the special LE-specific
                   * connectGatt() method, passing in a callback for GATT events
                   */
                  mConnectedGatt = device.connectGatt(this, false, mGattCallback);
                  //Display progress UI
                  mHandler.sendMessage(Message.obtain(null, MSG_PROGRESS, "Connecting to "+device.getName()+"..."));
                  return super.onOptionsItemSelected(item);
          }
      }
  
      private void clearDisplayValues() {
          //mTemperature.setText("---");
          mHumidity.setText("---");
  
      }
  
  
      private Runnable mStopRunnable = new Runnable() {
          @Override
          public void run() {
              stopScan();
          }
      };
      private Runnable mStartRunnable = new Runnable() {
          @Override
          public void run() {
              startScan();
          }
      };
  
      private void startScan() {
          mBluetoothAdapter.startLeScan(this);
          setProgressBarIndeterminateVisibility(true);
  
          mHandler.postDelayed(mStopRunnable, 2500);
      }
  
      private void stopScan() {
          mBluetoothAdapter.stopLeScan(this);
          setProgressBarIndeterminateVisibility(false);
      }
  
      /* BluetoothAdapter.LeScanCallback */
  
      @Override
      public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) {
          Log.i(TAG, "New LE Device: " + device.getName() + " @ " + rssi);
          /*
           * We are looking for SensorTag devices only, so validate the name
           * that each device reports before adding it to our collection
           */
          if (DEVICE_NAME.equals(device.getName())) {
              mDevices.put(device.hashCode(), device);
              //Update the overflow menu
              invalidateOptionsMenu();
          }
      }
  
      /*
       * In this callback, we've created a bit of a state machine to enforce that only
       * one characteristic be read or written at a time until all of our sensors
       * are enabled and we are registered to get notifications.
       */
  
      private BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
  
  
          private void readNextSensor(BluetoothGatt gatt) {
              BluetoothGattCharacteristic characteristic;
                     Log.d(TAG, "Reading humidity");
                      characteristic = gatt.getService(HUMIDITY_SERVICE).getCharacteristic(HUMIDITY_DATA_CHAR);
              mHandler.sendEmptyMessage(MSG_DISMISS);
              Log.i(TAG, "All Sensors Enabled");
              gatt.readCharacteristic(characteristic);
          }
  
          /*
           * Enable notification of changes on the data characteristic for each sensor
           * by writing the ENABLE_NOTIFICATION_VALUE flag to that characteristic's
           * configuration descriptor.
           */
          private void setNotifyNextSensor(BluetoothGatt gatt) {
              BluetoothGattCharacteristic characteristic;
                      Log.d(TAG, "Set notify humidity");
                      characteristic = gatt.getService(HUMIDITY_SERVICE).getCharacteristic(HUMIDITY_DATA_CHAR);
              mHandler.sendEmptyMessage(MSG_DISMISS);
              Log.i(TAG, "All Sensors Enabled");
              //Enable local notifications
              gatt.setCharacteristicNotification(characteristic, true);
              //Enabled remote notifications
              BluetoothGattDescriptor desc = characteristic.getDescriptor(CONFIG_DESCRIPTOR);
              desc.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
              gatt.writeDescriptor(desc);
          }
  
  
  
          /* OK */
  
          @Override
          public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
              Log.d(TAG, "Connection State Change: "+status+" -&gt; "+connectionState(newState));
              if (status == BluetoothGatt.GATT_SUCCESS &amp;&amp; newState == BluetoothProfile.STATE_CONNECTED) {
                  /*
                   * Once successfully connected, we must next discover all the services on the
                   * device before we can read and write their characteristics.
                   */
                  gatt.discoverServices();
                  mHandler.sendMessage(Message.obtain(null, MSG_PROGRESS, "Discovering Services..."));
              } else if (status == BluetoothGatt.GATT_SUCCESS &amp;&amp; newState == BluetoothProfile.STATE_DISCONNECTED) {
                  /*
                   * If at any point we disconnect, send a message to clear the weather values
                   * out of the UI
                   */
                  mHandler.sendEmptyMessage(MSG_CLEAR);
              } else if (status != BluetoothGatt.GATT_SUCCESS) {
                  /*
                   * If there is a failure at any stage, simply disconnect
                   */
                  gatt.disconnect();
              }
          }
  
          @Override
          public void onServicesDiscovered(BluetoothGatt gatt, int status) {
              Log.d(TAG, "Services Discovered: "+status);
              mHandler.sendMessage(Message.obtain(null, MSG_PROGRESS, "Enabling Sensors..."));
              /*
               * With services discovered, we are going to reset our state machine and start
               * working through the sensors we need to enable
              */
           //  enableNextSensor(gatt);
          readNextSensor(gatt);
          }
  
          @Override
          public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
              //For each read, pass the data up to the UI thread to update the display
              if (HUMIDITY_DATA_CHAR.equals(characteristic.getUuid())) {
                  mHandler.sendMessage(Message.obtain(null, MSG_HUMIDITY, characteristic));
              }
  
              //After reading the initial value, next we enable notifications
              setNotifyNextSensor(gatt);
          }
  
          @Override
          public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
              //After writing the enable flag, next we read the initial value
              readNextSensor(gatt);
          }
  
          @Override
          public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
              /*
               * After notifications are enabled, all updates from the device on characteristic
               * value changes will be posted here.  Similar to read, we hand these up to the
               * UI thread to update the display.
               */
  
              if (HUMIDITY_DATA_CHAR.equals(characteristic.getUuid())) {
                  mHandler.sendMessage(Message.obtain(null, MSG_HUMIDITY, characteristic));
              }
  
          }
  
          @Override
          public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
              //Once notifications are enabled, we move to the next sensor and start over with enable
  
               readNextSensor(gatt);
          }
  
          @Override
          public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {
              Log.d(TAG, "Remote RSSI: "+rssi);
          }
  
          private String connectionState(int status) {
              switch (status) {
                  case BluetoothProfile.STATE_CONNECTED:
                      return "Connected";
                  case BluetoothProfile.STATE_DISCONNECTED:
                      return "Disconnected";
                  case BluetoothProfile.STATE_CONNECTING:
                      return "Connecting";
                  case BluetoothProfile.STATE_DISCONNECTING:
                      return "Disconnecting";
                  default:
                      return String.valueOf(status);
              }
          }
      };
  
      /*
       * We have a Handler to process event results on the main thread
       */
      private static final int MSG_HUMIDITY = 101;
      private static final int MSG_PROGRESS = 201;
      private static final int MSG_DISMISS = 202;
      private static final int MSG_CLEAR = 301;
      private Handler mHandler = new Handler() {
          @Override
          public void handleMessage(Message msg) {
              BluetoothGattCharacteristic characteristic;
              switch (msg.what) {
                  case MSG_HUMIDITY:
                      characteristic = (BluetoothGattCharacteristic) msg.obj;
                      if (characteristic.getValue() == null) {
                          Log.w(TAG, "Error obtaining humidity value");
                          return;
                      }
                      updateHumidityValues(characteristic);
                      break;
                  case MSG_PROGRESS:
                      mProgress.setMessage((String) msg.obj);
                      if (!mProgress.isShowing()) {
                          mProgress.show();
                      }
                      break;
                  case MSG_DISMISS:
                      mProgress.hide();
                      break;
                  case MSG_CLEAR:
                      clearDisplayValues();
                      break;
              }
          }
      };
  
      /* Methods to extract sensor data and update the UI */
  
      private void updateHumidityValues(BluetoothGattCharacteristic characteristic) {
  
          mHumidity.setText(String.valueOf(characteristic));
  
      }
  }
  //         double humidity = SensorTagData.extractHumidity(characteristic);
  //         mHumidity.setText(String.format("%.0f%%", humidity));
  </code></pre>