title: What are the steps to get notified by Bluetooth Low Energy (BLE) device?
body: <p>I am working on a Bluetooth Low Energy (BLE) app. I have a BLE device (scale) which measures weight. I am able to connect with this device. But I am not getting how to read data (weight value) from it.</p>
  
  <p>I want to know if my app is connected to any BLE device, so what are the steps to get notified by device in order to get updated data.</p>
  
  <p>Okay, following is the for my Activity which I am using..</p>
  
  <pre><code>public class BlogBLEActivity extends Activity implements OnItemClickListener
  {
      private final static String TAG = BlogBLEActivity.class.getSimpleName();
  
      private BluetoothAdapter bluetoothAdapter;
      BluetoothManager bluetoothManager;
  
      boolean hasBleFeature = false;
  
      TextView tvMessage;
      int messageId = R.string.doesnt_support_ble;
      int colorId = android.R.color.holo_red_light;
  
      private boolean mScanning;
      private Handler handler = new Handler();
  
      private static final long SCAN_PERIOD = 10000;
      private static final int REQUEST_ENABLE_BT = 1209;
  
      ListView listView;
      ArrayList&lt;BluetoothDevice&gt; listDevices;
  
      BleDeviceAdapter bleDeviceAdapter;
  
      TextView tvHumidity;
      TextView tvTemperature;
      TextView tvPressure;
  
      boolean isConnected = false;
  
      @Override
      protected void onCreate(Bundle savedInstanceState)
      {
          super.onCreate(savedInstanceState);
          setContentView(R.layout.blog_ble);
  
          initParameters();
          initViews();
  
          scanLeDevice(true);
      }
  
      @SuppressLint("NewApi")
      void initParameters()
      {
          hasBleFeature = getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE);
          Log.i(TAG, "hasBleFeature : " + hasBleFeature);
  
          if (hasBleFeature)
          {
              messageId = R.string.supports_ble;
              colorId = android.R.color.holo_blue_light; 
          } else
          {
              messageId = R.string.doesnt_support_ble;
              colorId = android.R.color.holo_red_light;
          }
  
          bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
          bluetoothAdapter = bluetoothManager.getAdapter();// BluetoothAdapter.getDefaultAdapter();
  
          if (bluetoothAdapter == null || !bluetoothAdapter.isEnabled())
          {
              Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
              startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
          }
  
          listDevices = new ArrayList&lt;BluetoothDevice&gt;();
          bleDeviceAdapter = new BleDeviceAdapter(this, listDevices);
      }
  
      void initViews()
      {
          tvHumidity = (TextView) findViewById(R.id.blog_ble_tv_humidity);
          tvTemperature = (TextView) findViewById(R.id.blog_ble_tv_temprature);
          tvPressure = (TextView) findViewById(R.id.blog_ble_tv_pressure);
  
          tvMessage = (TextView) findViewById(R.id.blog_ble_tv_message);
          tvMessage.setText(getResources().getString(messageId));
          tvMessage.setTextColor(getResources().getColor(colorId));
  
          listView = (ListView) findViewById(R.id.blog_ble_list_view);
          listView.setAdapter(bleDeviceAdapter);
          listView.setOnItemClickListener(this);
      }
  
      @SuppressLint("NewApi")
      void scanLeDevice(final boolean enable)
      {
          if (enable)
          {
              handler.postDelayed(new Runnable()
              {
                  @SuppressLint("NewApi")
                  @Override
                  public void run()
                  {
                      mScanning = false;
                      bluetoothAdapter.stopLeScan(leScanCallback);
                  }
              }, SCAN_PERIOD);
  
              mScanning = false;
              bluetoothAdapter.startLeScan(leScanCallback);
          } else
          {
              mScanning = false;
              bluetoothAdapter.stopLeScan(leScanCallback);
          }
      }
  
      @SuppressLint("NewApi")
      private BluetoothAdapter.LeScanCallback leScanCallback = new BluetoothAdapter.LeScanCallback()
      {
          @Override
          public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord)
          {
              runOnUiThread(new Runnable()
              {
                  @Override
                  public void run()
                  {
                      if (device != null)
                      {
                          bleDeviceAdapter.add(device);
                          bleDeviceAdapter.notifyDataSetChanged();
                      }
                  }
              });
          }
      };
  
      class BleDeviceAdapter extends ArrayAdapter&lt;BluetoothDevice&gt;
      {
          public BleDeviceAdapter(Context context, List&lt;BluetoothDevice&gt; objects)
          {
              super(context, R.layout.row_ble_device, R.id.row_ble_device_tv_name, objects);
          }
  
          @SuppressLint("NewApi")
          @Override
          public View getView(int position, View convertView, ViewGroup parent)
          {
              View row = super.getView(position, convertView, parent);
              ViewHolder holder = (ViewHolder) row.getTag();
              if (holder == null)
              {
                  holder = new ViewHolder(row);
                  row.setTag(holder);
              }
  
              BluetoothDevice device = getDevice(position);
              holder.tvName.setText("" + device.getName());
  
              Log.i(TAG, "" + device.getName());
              return row;
          }
      }
  
      BluetoothDevice getDevice(int position)
      {
          return (BluetoothDevice) listView.getAdapter().getItem(position);
      }
  
      @SuppressLint("NewApi")
      @Override
      public void onItemClick(AdapterView&lt;?&gt; arg0, View arg1, int position, long arg3)
      {
          BluetoothDevice device = getDevice(position);
          Toast.makeText(this, "" + device.getName(), Toast.LENGTH_SHORT).show();
          BluetoothGatt connectGatt = device.connectGatt(this, false, mGattCallback);
  
      }
  
      /* Client Configuration Descriptor */
      private static final UUID CONFIG_DESCRIPTOR = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb");
  
      private static final UUID KITCHEN_SCALE_SERVICE = UUID.fromString("0000780a-0000-1000-8000-00805f9b34fb");
      private static final UUID KITCHEN_SCALE_FEATURE_CHAR = UUID.fromString("00008aa0-0000-1000-8000-00805f9b34fb");
      private static final UUID KITCHEN_SCALE_MEASUREMENT_CHAR = UUID.fromString("00008aa1-0000-1000-8000-00805f9b34fb");
      private static final UUID KITCHEN_SCALE_INTERMEDIATE_CHAR = UUID.fromString("00008aa2-0000-1000-8000-00805f9b34fb");
  
      /*
       * 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.
       */
      @SuppressLint("NewApi")
      private BluetoothGattCallback mGattCallback = new BluetoothGattCallback()
      {
  
          /* State Machine Tracking */
          private int mState = 0;
  
          private void reset()
          {
              mState = 0;
          }
  
          private void advance()
          {
              mState++;
          }
  
          /*
           * Send an enable command to each sensor by writing a configuration
           * characteristic. This is specific to the SensorTag to keep power low
           * by disabling sensors you aren't using.
           */
          private void enableNextSensor(BluetoothGatt gatt)
          {
              BluetoothGattCharacteristic characteristic;
              switch (mState)
              {
              case 0:
                  Log.i(TAG, "Enabling weight scale");
                  characteristic = gatt.getService(KITCHEN_SCALE_SERVICE).getCharacteristic(KITCHEN_SCALE_FEATURE_CHAR);
                  Log.i(TAG, "Feature Properties : "+characteristic.getProperties());
                  characteristic.setValue(new byte[]
                  { 0x09 });
                  break;
  
              default:
                  mHandler.sendEmptyMessage(MSG_DISMISS);
                  Log.i(TAG, "All Sensors Enabled");
                  return;
              }
  
              gatt.writeCharacteristic(characteristic);
          }
  
          /*
           * Read the data characteristic's value for each sensor explicitly
           */
          private void readNextSensor(BluetoothGatt gatt)
          {
              BluetoothGattCharacteristic characteristic;
              switch (mState)
              {
              case 0:
                  Log.i(TAG, "Reading weight cal");
                  characteristic = gatt.getService(KITCHEN_SCALE_SERVICE).getCharacteristic(KITCHEN_SCALE_MEASUREMENT_CHAR);
                  break;
  
              default:
                  mHandler.sendEmptyMessage(MSG_DISMISS);
                  Log.i(TAG, "All Sensors Enabled");
                  return;
              }
  
              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;
              switch (mState)
              {
              case 0:
                  Log.i(TAG, "Set notify weight ");
                  characteristic = gatt.getService(KITCHEN_SCALE_SERVICE).getCharacteristic(KITCHEN_SCALE_MEASUREMENT_CHAR);
                  break;
  
              default:
                  mHandler.sendEmptyMessage(MSG_DISMISS);
                  Log.i(TAG, "All Sensors Enabled");
                  return;
              }
  
              // 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);
          }
  
          @Override
          public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState)
          {
              Log.i(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.i(TAG, "Services Discovered: " + status);
              if (status == BluetoothGatt.GATT_SUCCESS)
              {
                  Log.i(TAG, "No of services discovered: " + gatt.getServices().size());
                  mHandler.sendMessage(Message.obtain(null, MSG_PROGRESS, "No of services discovered: " + gatt.getServices().size()));
  
                  List&lt;BluetoothGattService&gt; services = gatt.getServices();
                  for (BluetoothGattService bluetoothGattService : services)
                  {
                      UUID uuid = bluetoothGattService.getUuid();
                      Log.e(TAG, ""+uuid.toString());
                      List&lt;BluetoothGattCharacteristic&gt; characteristics = bluetoothGattService.getCharacteristics();
                      for (BluetoothGattCharacteristic bluetoothGattCharacteristic : characteristics)
                      {
                          UUID uuidC = bluetoothGattCharacteristic.getUuid();
                          Log.i(TAG, "Gatt Properties : "+bluetoothGattCharacteristic.getProperties());
                          Log.i(TAG, ""+uuidC.toString());
                          CharacteristicHelper helper = new CharacteristicHelper(bluetoothGattCharacteristic);
                          Log.i(TAG, "isRead : "+helper.isRead());
                          Log.i(TAG, "isWrite : "+helper.isWrite());
                          Log.i(TAG, "isNotify : "+helper.isNotify());
                          Log.i(TAG, "isWriteNoResponse : "+helper.isWriteNoResponse());
                      }
                  }
              }
              // 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
               */
               reset();
               enableNextSensor(gatt);
          }
  
          @Override
          public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status)
          {
              Log.i(TAG, "onCharacteristicRead");
              // For each read, pass the data up to the UI thread to update the
              // display
              /**methodToUpdateUI().*/
  
              // After reading the initial value, next we enable notifications
              setNotifyNextSensor(gatt);
          }
  
          @Override
          public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status)
          {
              Log.i(TAG, "onCharacteristicWrite");
              // After writing the enable flag, next we read the initial value
              readNextSensor(gatt);
          }
  
          @Override
          public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic)
          {
              Log.i(TAG, "onCharacteristicChanged");
              /*
               * 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.
               */
          }
  
          @Override
          public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status)
          {
              Log.i(TAG, "onDescriptorWrite");
              // Once notifications are enabled, we move to the next sensor and
              // start over with enable
              advance();
              enableNextSensor(gatt);
          }
  
          @Override
          public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status)
          {
              Log.i(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_PROGRESS = 201;
      private static final int MSG_DISMISS = 202;
      private static final int MSG_CLEAR = 301;
      private Handler mHandler = new Handler()
      {
          @SuppressLint("NewApi")
          @Override
          public void handleMessage(Message msg)
          {
              BluetoothGattCharacteristic characteristic;
              switch (msg.what)
              {
              case MSG_PROGRESS:
                  tvMessage.setText((String) msg.obj);
                  break;
              case MSG_DISMISS:
                  tvMessage.setText("Service Enabled");
                  break;
              case MSG_CLEAR:
                  tvMessage.setText("");
                  break;
              }
          }
      };
  }
  </code></pre>
  
  <p>In my activity, first of all I am scanning all the available devices &amp; preparing ListView. On clicking on list item I connect to that particular device. When device's status become connected then I discover services. I have UUIDs of the device's service &amp; its characteristics. But I am not sure how to write to any particular characteristics or enable or read data from it. 
    Although I have tried this thing but I don't see any success.</p>
  
  <p>If any one has any idea about it, so please help me.</p>