Bluetooth Le Gatt Example, Scan Ble Devices

Posted on

Last ship service present the commencement pace to enable Bluetooth, this ship service present how to scan BLE devices inwards range.

We volition re-use the BluetoothLeService.java inwards Android representative code “Bluetooth Le Gatt example“. Modify to suit our case.

BluetoothLeService.java

/*  * Copyright (C) 2013 The Android Open Source Project  *  * Licensed nether the Apache License, Version 2.0 (the "License");  * y'all may non purpose this file except inwards compliance alongside the License.  * You may obtain a re-create of the License at  *  *      http://www.apache.org/licenses/LICENSE-2.0  *  * Unless required past times applicable police describe or agreed to inwards writing, software  * distributed nether the License is distributed on an "AS IS" BASIS,  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either limited or implied.  * See the License for the specific linguistic communication governing permissions together with  * limitations nether the License.  */  packet com.blogspot.android_er.androidblegatt;  import android.app.Service; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothGatt; import android.bluetooth.BluetoothGattCallback; import android.bluetooth.BluetoothGattCharacteristic; import android.bluetooth.BluetoothGattDescriptor; import android.bluetooth.BluetoothGattService; import android.bluetooth.BluetoothManager; import android.bluetooth.BluetoothProfile; import android.content.Context; import android.content.Intent; import android.os.Binder; import android.os.IBinder; import android.os.ParcelUuid; import android.util.Log;  import java.util.List; import java.util.UUID;  /**  * Service for managing connexion together with information communication alongside a GATT server hosted on a  * given Bluetooth LE device.  */ world course of pedagogy BluetoothLeService extends Service {     person lastly static String TAG = BluetoothLeService.class.getSimpleName();      person BluetoothManager mBluetoothManager;     person BluetoothAdapter mBluetoothAdapter;     person String mBluetoothDeviceAddress;     person BluetoothGatt mBluetoothGatt;     person int mConnectionState = STATE_DISCONNECTED;      person static lastly int STATE_DISCONNECTED = 0;     person static lastly int STATE_CONNECTING = 1;     person static lastly int STATE_CONNECTED = 2;      world lastly static String ACTION_GATT_CONNECTED =             "android-er.ACTION_GATT_CONNECTED";     world lastly static String ACTION_GATT_DISCONNECTED =             "android-er.ACTION_GATT_DISCONNECTED";     world lastly static String ACTION_GATT_SERVICES_DISCOVERED =             "android-er.ACTION_GATT_SERVICES_DISCOVERED";     world lastly static String ACTION_DATA_AVAILABLE =             "android-er.ACTION_DATA_AVAILABLE";     world lastly static String EXTRA_DATA =             "android-er.EXTRA_DATA";      public static String String_GENUINO101_ledService =             "19B10000-E8F2-537E-4F6C-D104768A1214";     world lastly static ParcelUuid ParcelUuid_GENUINO101_ledService =             ParcelUuid.fromString(String_GENUINO101_ledService);     world lastly static UUID UUID_GENUINO101_ledService =             UUID.fromString(String_GENUINO101_ledService);      public static String String_GENUINO101_switchChar =             "19B10001-E8F2-537E-4F6C-D104768A1214";     world lastly static UUID UUID_GENUINO101_switchChare =             UUID.fromString(String_GENUINO101_switchChar);      // Implements callback methods for GATT events that the app cares about.  For example,     // connexion modify together with services discovered.     person lastly BluetoothGattCallback mGattCallback = novel BluetoothGattCallback() {         @Override         world void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {             String intentAction;             if (newState == BluetoothProfile.STATE_CONNECTED) {                 intentAction = ACTION_GATT_CONNECTED;                 mConnectionState = STATE_CONNECTED;                 broadcastUpdate(intentAction);                 Log.i(TAG, "Connected to GATT server.");                 // Attempts to regain services afterward successful connection.                 Log.i(TAG, "Attempting to start service discovery:" +                         mBluetoothGatt.discoverServices());              } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {                 intentAction = ACTION_GATT_DISCONNECTED;                 mConnectionState = STATE_DISCONNECTED;                 Log.i(TAG, "Disconnected from GATT server.");                 broadcastUpdate(intentAction);             }         }          @Override         world void onServicesDiscovered(BluetoothGatt gatt, int status) {             if (status == BluetoothGatt.GATT_SUCCESS) {                 broadcastUpdate(ACTION_GATT_SERVICES_DISCOVERED);             } else {                 Log.w(TAG, "onServicesDiscovered received: " + status);             }         }          @Override         world void onCharacteristicRead(BluetoothGatt gatt,                                          BluetoothGattCharacteristic characteristic,                                          int status) {             if (status == BluetoothGatt.GATT_SUCCESS) {                 broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);             }         }          @Override         world void onCharacteristicChanged(BluetoothGatt gatt,                                             BluetoothGattCharacteristic characteristic) {             broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);         }     };      person void broadcastUpdate(final String action) {         lastly Intent intent = novel Intent(action);         sendBroadcast(intent);     }      person void broadcastUpdate(final String action,                                  lastly BluetoothGattCharacteristic characteristic) {         lastly Intent intent = novel Intent(action);          /*         // This is exceptional treatment for the Heart Rate Measurement profile.  Data parsing is         // carried out every bit per profile specifications:         // http://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx         // ?u=org.bluetooth.characteristic.heart_rate_measurement.xml         if (UUID_HEART_RATE_MEASUREMENT.equals(characteristic.getUuid())) {             int flag = characteristic.getProperties();             int format = -1;             if ((flag & 0x01) != 0) {                 format = BluetoothGattCharacteristic.FORMAT_UINT16;                 Log.d(TAG, "Heart charge per unit of measurement format UINT16.");             } else {                 format = BluetoothGattCharacteristic.FORMAT_UINT8;                 Log.d(TAG, "Heart charge per unit of measurement format UINT8.");             }             lastly int heartRate = characteristic.getIntValue(format, 1);             Log.d(TAG, String.format("Received see rate: %d", heartRate));             intent.putExtra(EXTRA_DATA, String.valueOf(heartRate));         } else {             // For all other profiles, writes the information formatted inwards HEX.             lastly byte[] information = characteristic.getValue();             if (data != nothing && data.length > 0) {                 lastly StringBuilder stringBuilder = novel StringBuilder(data.length);                 for(byte byteChar : data)                     stringBuilder.append(String.format("%02X ", byteChar));                 intent.putExtra(EXTRA_DATA, novel String(data) + "\n" + stringBuilder.toString());             }         }         */          //remove exceptional treatment for fourth dimension existence         Log.w(TAG, "broadcastUpdate()");          lastly byte[] information = characteristic.getValue();          Log.v(TAG, "data.length: " + data.length);          if (data != nothing && data.length > 0) {             lastly StringBuilder stringBuilder = novel StringBuilder(data.length);             for(byte byteChar : data) {                 stringBuilder.append(String.format("%02X ", byteChar));                  Log.v(TAG, String.format("%02X ", byteChar));             }             intent.putExtra(EXTRA_DATA, novel String(data) + "\n" + stringBuilder.toString());         }          sendBroadcast(intent);     }      world course of pedagogy LocalBinder extends Binder {         BluetoothLeService getService() {             supply BluetoothLeService.this;         }     }      @Override     world IBinder onBind(Intent intent) {         supply mBinder;     }      @Override     world boolean onUnbind(Intent intent) {         // After using a given device, y'all should brand certain that BluetoothGatt.close() is called         // such that resources are cleaned upwards properly.  In this item example, close() is         // invoked when the UI is disconnected from the Service.         close();         supply super.onUnbind(intent);     }      person lastly IBinder mBinder = novel LocalBinder();      /**      * Initializes a reference to the local Bluetooth adapter.      *      * @return Return truthful if the initialization is successful.      */     world boolean initialize() {         // For API marker xviii together with above, larn a reference to BluetoothAdapter through         // BluetoothManager.         if (mBluetoothManager == null) {             mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);             if (mBluetoothManager == null) {                 Log.e(TAG, "Unable to initialize BluetoothManager.");                 supply false;             }         }          mBluetoothAdapter = mBluetoothManager.getAdapter();         if (mBluetoothAdapter == null) {             Log.e(TAG, "Unable to obtain a BluetoothAdapter.");             supply false;         }          supply true;     }      /**      * Connects to the GATT server hosted on the Bluetooth LE device.      *      * @param address The device address of the destination device.      *      * @return Return truthful if the connexion is initiated successfully. The connexion lawsuit      *         is reported asynchronously through the      *         {@code BluetoothGattCallback#onConnectionStateChange(      *         android.bluetooth.BluetoothGatt, int, int)}      *         callback.      */     world boolean connect(final String address) {         if (mBluetoothAdapter == nothing || address == null) {             Log.w(TAG, "BluetoothAdapter non initialized or unspecified address.");             supply false;         }          // Previously connected device.  Try to reconnect.         if (mBluetoothDeviceAddress != nothing && address.equals(mBluetoothDeviceAddress)                 && mBluetoothGatt != null) {             Log.d(TAG, "Trying to purpose an existing mBluetoothGatt for connection.");             if (mBluetoothGatt.connect()) {                 mConnectionState = STATE_CONNECTING;                 supply true;             } else {                 supply false;             }         }          lastly BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);         if (device == null) {             Log.w(TAG, "Device non found.  Unable to connect.");             supply false;         }         // We desire to straight connect to the device, together with hence nosotros are setting the autoConnect         // parameter to false.         mBluetoothGatt = device.connectGatt(this, false, mGattCallback);         Log.d(TAG, "Trying to create a novel connection.");         mBluetoothDeviceAddress = address;         mConnectionState = STATE_CONNECTING;         supply true;     }      /**      * Disconnects an existing connexion or cancel a pending connection. The disconnection lawsuit      * is reported asynchronously through the      * {@code BluetoothGattCallback#onConnectionStateChange(      * android.bluetooth.BluetoothGatt, int, int)}      * callback.      */     world void disconnect() {         if (mBluetoothAdapter == nothing || mBluetoothGatt == null) {             Log.w(TAG, "BluetoothAdapter non initialized");             return;         }         mBluetoothGatt.disconnect();     }      /**      * After using a given BLE device, the app must telephone scream upwards this method to ensure resources are      * released properly.      */     world void close() {         if (mBluetoothGatt == null) {             return;         }         mBluetoothGatt.close();         mBluetoothGatt = null;     }      /**      * Request a read on a given {@code BluetoothGattCharacteristic}. The read lawsuit is reported      * asynchronously through the {@code BluetoothGattCallback#onCharacteristicRead(      * android.bluetooth.BluetoothGatt, android.bluetooth.BluetoothGattCharacteristic, int)}      * callback.      *      * @param characteristic The characteristic to read from.      */     world void readCharacteristic(BluetoothGattCharacteristic characteristic) {         if (mBluetoothAdapter == nothing || mBluetoothGatt == null) {             Log.w(TAG, "BluetoothAdapter non initialized");             return;         }         mBluetoothGatt.readCharacteristic(characteristic);     }      /**      * Enables or disables notification on a give characteristic.      *      * @param characteristic Characteristic to human activity on.      * @param enabled If true, enable notification.  False otherwise.      */     world void setCharacteristicNotification(BluetoothGattCharacteristic characteristic,                                               boolean enabled) {         if (mBluetoothAdapter == nothing || mBluetoothGatt == null) {             Log.w(TAG, "BluetoothAdapter non initialized");             return;         }         mBluetoothGatt.setCharacteristicNotification(characteristic, enabled);          // This is specific to Genuino 101 ledService.         if (UUID_GENUINO101_ledService.equals(characteristic.getUuid())) {             BluetoothGattDescriptor descriptor = characteristic.getDescriptor(                     UUID_GENUINO101_switchChare);             descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);             mBluetoothGatt.writeDescriptor(descriptor);         }     }      /**      * Retrieves a listing of supported GATT services on the connected device. This should live      * invoked solely afterward {@code BluetoothGatt#discoverServices()} completes successfully.      *      * @return Influenza A virus subtype H5N1 {@code List} of supported services.      */     world List<BluetoothGattService> getSupportedGattServices() {         if (mBluetoothGatt == null) supply null;          supply mBluetoothGatt.getServices();     } }  

Edit AndroidManifest.xml to add together service of “.BluetoothLeService”.

<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android"     package="com.blogspot.android_er.androidblegatt">      <uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/>     <uses-permission android:name="android.permission.BLUETOOTH"/>     <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>     <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>      <application         android:allowBackup="true"         android:icon="@mipmap/ic_launcher"         android:label="@string/app_name"         android:supportsRtl="true"         android:theme="@style/AppTheme">         <activity android:name=".MainActivity">             <intent-filter>                 <action android:name="android.intent.action.MAIN" />                  <category android:name="android.intent.category.LAUNCHER" />             </intent-filter>         </activity>         <service android:name=".BluetoothLeService" android:enabled="true"/>     </application>  </manifest> 

Edit activity_main.xml to add together a Button to start scanning, together with a ListView to display the result.

<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"     xmlns:tools="http://schemas.android.com/tools"     android:layout_width="match_parent"     android:layout_height="match_parent"     android:padding="16dp"     android:orientation="vertical"     tools:context="com.blogspot.android_er.androidblegatt.MainActivity">      <TextView         android:layout_width="wrap_content"         android:layout_height="wrap_content"         android:layout_gravity="center_horizontal"         android:autoLink="web"         android:text="https://rootandroid.org//"         android:textStyle="bold" />      <TextView         android:layout_width="wrap_content"         android:layout_height="wrap_content"         android:layout_gravity="center_horizontal"         android:autoLink="web"         android:text="Bluetooth LE Gatt Example"         android:textStyle="italic" />      <Button         android:id="@+id/scan"         android:layout_width="match_parent"         android:layout_height="wrap_content"         android:text="Scan"/>     <ListView         android:id="@+id/lelist"         android:layout_width="match_parent"         android:layout_height="match_parent"/> </LinearLayout>  

MainActivity.java

package com.blogspot.android_er.androidblegatt;  import android.app.Activity; import android.app.AlertDialog; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothManager; import android.bluetooth.le.BluetoothLeScanner; import android.bluetooth.le.ScanCallback; import android.bluetooth.le.ScanResult; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.pm.PackageManager; import android.os.Bundle; import android.os.Handler; import android.support.v7.app.AppCompatActivity; import android.view.View; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.Button; import android.widget.ListAdapter; import android.widget.ListView; import android.widget.Toast;  import java.util.ArrayList; import java.util.List;  world course of pedagogy MainActivity extends AppCompatActivity {      person BluetoothAdapter mBluetoothAdapter;     person BluetoothLeScanner mBluetoothLeScanner;      person boolean mScanning;      person static lastly int RQS_ENABLE_BLUETOOTH = 1;      Button btnScan;     ListView listViewLE;      List<BluetoothDevice> listBluetoothDevice;     ListAdapter adapterLeScanResult;      person Handler mHandler;     person static lastly long SCAN_PERIOD = 10000;      @Override     protected void onCreate(Bundle savedInstanceState) {         super.onCreate(savedInstanceState);         setContentView(R.layout.activity_main);          // Check if BLE is supported on the device.         if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {             Toast.makeText(this,                     "BLUETOOTH_LE non supported inwards this device!",                     Toast.LENGTH_SHORT).show();             finish();         }          getBluetoothAdapterAndLeScanner();          // Checks if Bluetooth is supported on the device.         if (mBluetoothAdapter == null) {             Toast.makeText(this,                     "bluetoothManager.getAdapter()==null",                     Toast.LENGTH_SHORT).show();             finish();             return;         }          btnScan = (Button)findViewById(R.id.scan);         btnScan.setOnClickListener(new View.OnClickListener() {             @Override             world void onClick(View v) {                 scanLeDevice(true);             }         });         listViewLE = (ListView)findViewById(R.id.lelist);          listBluetoothDevice = novel ArrayList<>();         adapterLeScanResult = novel ArrayAdapter<BluetoothDevice>(                 this, android.R.layout.simple_list_item_1, listBluetoothDevice);         listViewLE.setAdapter(adapterLeScanResult);         listViewLE.setOnItemClickListener(scanResultOnItemClickListener);          mHandler = novel Handler();      }      AdapterView.OnItemClickListener scanResultOnItemClickListener =             novel AdapterView.OnItemClickListener(){                  @Override                 world void onItemClick(AdapterView<?> parent, View view, int position, long id) {                     lastly BluetoothDevice device = (BluetoothDevice) parent.getItemAtPosition(position);                      String msg = device.getAddress() + "\n"                             + device.getBluetoothClass().toString() + "\n"                             + getBTDevieType(device);                      novel AlertDialog.Builder(MainActivity.this)                             .setTitle(device.getName())                             .setMessage(msg)                             .setPositiveButton("OK", novel DialogInterface.OnClickListener() {                                 @Override                                 world void onClick(DialogInterface dialog, int which) {                                  }                             })                             .show();                  }             };      person String getBTDevieType(BluetoothDevice d){         String type = "";          switch (d.getType()){             representative BluetoothDevice.DEVICE_TYPE_CLASSIC:                 type = "DEVICE_TYPE_CLASSIC";                 break;             representative BluetoothDevice.DEVICE_TYPE_DUAL:                 type = "DEVICE_TYPE_DUAL";                 break;             representative BluetoothDevice.DEVICE_TYPE_LE:                 type = "DEVICE_TYPE_LE";                 break;             representative BluetoothDevice.DEVICE_TYPE_UNKNOWN:                 type = "DEVICE_TYPE_UNKNOWN";                 break;             default:                 type = "unknown...";         }          supply type;     }      @Override     protected void onResume() {         super.onResume();          if (!mBluetoothAdapter.isEnabled()) {             if (!mBluetoothAdapter.isEnabled()) {                 Intent enableBtIntent = novel Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);                 startActivityForResult(enableBtIntent, RQS_ENABLE_BLUETOOTH);             }         }     }      @Override     protected void onActivityResult(int requestCode, int resultCode, Intent data) {          if (requestCode == RQS_ENABLE_BLUETOOTH && resultCode == Activity.RESULT_CANCELED) {             finish();             return;         }          getBluetoothAdapterAndLeScanner();          // Checks if Bluetooth is supported on the device.         if (mBluetoothAdapter == null) {             Toast.makeText(this,                     "bluetoothManager.getAdapter()==null",                     Toast.LENGTH_SHORT).show();             finish();             return;         }          super.onActivityResult(requestCode, resultCode, data);     }      person void getBluetoothAdapterAndLeScanner(){         // Get BluetoothAdapter together with BluetoothLeScanner.         lastly BluetoothManager bluetoothManager =                 (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);         mBluetoothAdapter = bluetoothManager.getAdapter();         mBluetoothLeScanner = mBluetoothAdapter.getBluetoothLeScanner();          mScanning = false;     }      /*     to telephone scream upwards startScan (ScanCallback callback),     Requires BLUETOOTH_ADMIN permission.     Must handgrip ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION permission to larn results.      */     person void scanLeDevice(final boolean enable) {         if (enable) {             listBluetoothDevice.clear();             listViewLE.invalidateViews();              // Stops scanning afterward a pre-defined scan period.             mHandler.postDelayed(new Runnable() {                 @Override                 world void run() {                     mBluetoothLeScanner.stopScan(scanCallback);                     listViewLE.invalidateViews();                      Toast.makeText(MainActivity.this,                             "Scan timeout",                             Toast.LENGTH_LONG).show();                      mScanning = false;                     btnScan.setEnabled(true);                 }             }, SCAN_PERIOD);              mBluetoothLeScanner.startScan(scanCallback);             mScanning = true;             btnScan.setEnabled(false);         } else {             mBluetoothLeScanner.stopScan(scanCallback);             mScanning = false;             btnScan.setEnabled(true);         }     }      person ScanCallback scanCallback = novel ScanCallback() {         @Override         world void onScanResult(int callbackType, ScanResult result) {             super.onScanResult(callbackType, result);              addBluetoothDevice(result.getDevice());         }          @Override         world void onBatchScanResults(List<ScanResult> results) {             super.onBatchScanResults(results);             for(ScanResult lawsuit : results){                 addBluetoothDevice(result.getDevice());             }         }          @Override         world void onScanFailed(int errorCode) {             super.onScanFailed(errorCode);             Toast.makeText(MainActivity.this,                     "onScanFailed: " + String.valueOf(errorCode),                     Toast.LENGTH_LONG).show();         }          person void addBluetoothDevice(BluetoothDevice device){             if(!listBluetoothDevice.contains(device)){                 listBluetoothDevice.add(device);                 listViewLE.invalidateViews();             }         }     }; }  

As shown inwards this video; at that spot are 3 bluetooth devices running inwards range. This representative recognize Genuino 101 together with HM-10 (BLE module), simply non HC-06 (classic Bluetooth module).

Next:
– Scan specified BLE devices alongside ScanFilter


Bluetooth LE Gatt Example, step-by-step