码迷,mamicode.com
首页 > 移动开发 > 详细

Android as Bluetooth Low Energy Peripherial (GATT server).

时间:2015-05-26 23:29:03      阅读:248      评论:0      收藏:0      [点我收藏+]

标签:android   bluetooth-low-energy   



  I demonstrate how to write a simple BLE peripheral application in Android here. I am bad in Android development, The UI would be very ugly, but the code work:

  Currently(5/25/2015), the code could be running in Nexus 6 or Nexus 9 only based on my test. The other phones or tablets  not support to be a BLE peripheral.  So, if you really interested in the Android as peripheral issue, please open your wallet and buy a GOOGLE official device, thank you.


 How to add a characteristic as notification is little bit complicated, In here I just add read write  ones.
  About the notification, I put code in the lat part of this post.

You should add

 <uses-permission android:name="android.permission.BLUETOOTH" />
 <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />

The 2 lines in your AndroidManifest.xml, like this :


<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.awind.presentsenseperipheral"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="21"
        android:targetSdkVersion="21" />

    <uses-permission android:name="android.permission.BLUETOOTH" />
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>



The kernal code are below , note the AdvertiseCallback is callback of BluetoothLeAdvertiser ::startAdvertising, and BluetoothGattServerCallback is callback function of ALL BluetoothGattCharacteristic.


BLEPeripheral.java: (that is what you want)


package com.awind.presentsenseperipheral;

import java.util.UUID;

import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothGattServer;
import android.bluetooth.BluetoothGattServerCallback;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothManager;
import android.bluetooth.le.AdvertiseCallback;
import android.bluetooth.le.AdvertiseData;
import android.bluetooth.le.AdvertiseSettings;
import android.bluetooth.le.BluetoothLeAdvertiser;
import android.content.Context;
import android.content.pm.PackageManager;
import android.util.Log;


public class BLEPeripheral{
 
 Context mContext;
 
 BluetoothManager mManager;
 BluetoothAdapter mAdapter;
 
 BluetoothLeAdvertiser  mLeAdvertiser;
 
 BluetoothGattServer  mGattServer;  
 
 public static boolean isEnableBluetooth(){
  return BluetoothAdapter.getDefaultAdapter().isEnabled();
 }
 
 public int init(Context context){
  
  if(null == mManager)
   mManager = (BluetoothManager)context.getSystemService(Context.BLUETOOTH_SERVICE);
  
  if(null == mManager)
   return -1;
  
  if(false == context.getPackageManager().
    hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE))
   return -2;          
        
  
  if(null == mAdapter)
   mAdapter = mManager.getAdapter();
  
  if(false == mAdapter.isMultipleAdvertisementSupported())
   return -3; 
  
  mContext = context;
  return 0;
 }
 
 public void close()
 {
  
 }

 public static String getAddress(){return BluetoothAdapter.getDefaultAdapter().getAddress();}
 
 private AdvertiseCallback mAdvCallback = new AdvertiseCallback() {
  
  @Override
  public void onStartFailure(int errorCode){
   Log.d("advertise","onStartFailure");
  }
  
  @Override
  public void onStartSuccess(AdvertiseSettings settingsInEffect){
   Log.d("advertise","onStartSuccess");
  };
 };
 
  private final BluetoothGattServerCallback mGattServerCallback 
   = new BluetoothGattServerCallback(){
   
  @Override
        public void onConnectionStateChange(BluetoothDevice device, int status, int newState){
   Log.d("GattServer", "Our gatt server connection state changed, new state ");
         Log.d("GattServer", Integer.toString(newState));
            super.onConnectionStateChange(device, status, newState);
        }
   
  @Override
        public void onServiceAdded(int status, BluetoothGattService service) {
            Log.d("GattServer", "Our gatt server service was added.");
            super.onServiceAdded(status, service);
        }

        @Override
        public void onCharacteristicReadRequest(BluetoothDevice device, int requestId, int offset, BluetoothGattCharacteristic characteristic) {
            Log.d("GattServer", "Our gatt characteristic was read.");
            super.onCharacteristicReadRequest(device, requestId, offset, characteristic);
            mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, 
              characteristic.getValue());
        }

        @Override
        public void onCharacteristicWriteRequest(BluetoothDevice device, int requestId, BluetoothGattCharacteristic characteristic, boolean preparedWrite, boolean responseNeeded, int offset, byte[] value) {
            Log.d("GattServer", "We have received a write request for one of our hosted characteristics");
            Log.d("GattServer", "data = "+ value.toString()); 
            super.onCharacteristicWriteRequest(device, requestId, characteristic, preparedWrite, responseNeeded, offset, value);
        }

        @Override
        public void onNotificationSent(BluetoothDevice device, int status)
        {
         Log.d("GattServer", "onNotificationSent");          
         super.onNotificationSent(device, status);                  
        }
        
        @Override
        public void onDescriptorReadRequest(BluetoothDevice device, int requestId, int offset, BluetoothGattDescriptor descriptor) {
            Log.d("GattServer", "Our gatt server descriptor was read.");
            super.onDescriptorReadRequest(device, requestId, offset, descriptor);
            
        }

        @Override
        public void onDescriptorWriteRequest(BluetoothDevice device, int requestId, BluetoothGattDescriptor descriptor, boolean preparedWrite, boolean responseNeeded, int offset, byte[] value) {
            Log.d("GattServer", "Our gatt server descriptor was written.");
            super.onDescriptorWriteRequest(device, requestId, descriptor, preparedWrite, responseNeeded, offset, value);
        }

        @Override
        public void onExecuteWrite(BluetoothDevice device, int requestId, boolean execute) {
            Log.d("GattServer", "Our gatt server on execute write.");
            super.onExecuteWrite(device, requestId, execute);
        }
   
 };
 
 private void addDeviceInfoService(BluetoothGattServer gattServer)
 {  
  if(null == gattServer)
   return;  
   //
        // device info   
        //
        final String SERVICE_DEVICE_INFORMATION = "0000180a-0000-1000-8000-00805f9b34fb";
        final String SOFTWARE_REVISION_STRING = "00002A28-0000-1000-8000-00805f9b34fb";
                                                   
        BluetoothGattCharacteristic softwareVerCharacteristic = new BluetoothGattCharacteristic(
          UUID.fromString(SOFTWARE_REVISION_STRING), 
          BluetoothGattCharacteristic.PROPERTY_READ,
          BluetoothGattCharacteristic.PERMISSION_READ
          );
        
        BluetoothGattService deviceInfoService = new BluetoothGattService(
          UUID.fromString(SERVICE_DEVICE_INFORMATION), 
          BluetoothGattService.SERVICE_TYPE_PRIMARY);
        
        
        softwareVerCharacteristic.setValue(new String("0.0.1").getBytes());
        
        deviceInfoService.addCharacteristic(softwareVerCharacteristic);
        gattServer.addService(deviceInfoService);
 }
 
 public void startAdvertise()
 {
  if(null == mAdapter)
   return;
  
  if (null == mLeAdvertiser) 
   mLeAdvertiser = mAdapter.getBluetoothLeAdvertiser();
        
  if(null == mLeAdvertiser)
   return;
  
   AdvertiseSettings.Builder settingBuilder;
   
   settingBuilder = new AdvertiseSettings.Builder();
   settingBuilder.setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_LOW_LATENCY);
   settingBuilder.setConnectable(true);   
   settingBuilder.setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_HIGH);  
            
         AdvertiseData.Builder advBuilder;
         
         advBuilder = new AdvertiseData.Builder();
                                          
         mAdapter.setName("PeripheralAndroid"); //8 characters works, 9+ fails
         advBuilder.setIncludeDeviceName(true);
        
         mGattServer = mManager.openGattServer(mContext, mGattServerCallback);                          
                 
         addDeviceInfoService(mGattServer);
                  
         
         final String  SERVICE_A = "0000fff0-0000-1000-8000-00805f9b34fb";
         final String  CHAR_READ_1 = "00fff1-0000-1000-8000-00805f9b34fb";
         final String  CHAR_READ_2 = "00fff2-0000-1000-8000-00805f9b34fb";
         final String  CHAR_WRITE = "00fff3-0000-1000-8000-00805f9b34fb";      
         
         
         BluetoothGattCharacteristic read1Characteristic = new BluetoothGattCharacteristic(
           UUID.fromString(CHAR_READ_1), 
           BluetoothGattCharacteristic.PROPERTY_READ,
           BluetoothGattCharacteristic.PERMISSION_READ
           );
        
         read1Characteristic.setValue(new String("this is read 1").getBytes());
         
         BluetoothGattCharacteristic read2Characteristic = new BluetoothGattCharacteristic(
           UUID.fromString(CHAR_READ_2), 
           BluetoothGattCharacteristic.PROPERTY_READ,
           BluetoothGattCharacteristic.PERMISSION_READ
           );
         
         read2Characteristic.setValue(new String("this is read 2").getBytes());
         
         
         BluetoothGattCharacteristic writeCharacteristic = new BluetoothGattCharacteristic(
           UUID.fromString(CHAR_WRITE), 
           BluetoothGattCharacteristic.PROPERTY_WRITE,
           BluetoothGattCharacteristic.PERMISSION_WRITE
           );
         
         
/
         
         BluetoothGattService AService = new BluetoothGattService(
           UUID.fromString(SERVICE_A), 
           BluetoothGattService.SERVICE_TYPE_PRIMARY);
                          
         
         AService.addCharacteristic(read1Characteristic);
         AService.addCharacteristic(read2Characteristic);
         AService.addCharacteristic(writeCharacteristic);
         
        // Add notify characteristic here !!!
         
         mGattServer.addService(AService);
         
          
         mLeAdvertiser.startAdvertising(settingBuilder.build(), 
           advBuilder.build(), mAdvCallback);
         
 }
 
 public void stopAdvertise()
 {
  if(null != mLeAdvertiser)
   mLeAdvertiser.stopAdvertising(mAdvCallback);
  
  mLeAdvertiser = null;  
 }
}



MainActivity.java : (UI part)


package com.awind.presentsenseperipheral;

import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.content.Intent;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.CheckBox;
import android.widget.TextView;
import android.widget.Toast;


public class MainActivity extends Activity {

 private BLEPeripheral blePeri; 
 private CheckBox  adverstiseCheckBox;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        adverstiseCheckBox = (CheckBox) findViewById(R.id.advertise_checkBox);
        
        blePeri = new BLEPeripheral();
        
        
        adverstiseCheckBox.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
             
             if(true == adverstiseCheckBox.isChecked())
             {
              TextView textView;
              textView = (TextView)findViewById(R.id.status_text);
              textView.setText("advertising");
              blePeri.startAdvertise();              
             }
             else
             {
              TextView textView;
              textView = (TextView)findViewById(R.id.status_text);
              textView.setText("disable");
              blePeri.stopAdvertise();              
             }
            }
        });
        
        adverstiseCheckBox.setEnabled(false);
        
     if(false == BLEPeripheral.isEnableBluetooth())
     {
      
      Intent intentBtEnabled = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); 
            // The REQUEST_ENABLE_BT constant passed to startActivityForResult() is a locally defined integer (which must be greater than 0), that the system passes back to you in your onActivityResult() 
            // implementation as the requestCode parameter. 
            int REQUEST_ENABLE_BT = 1;
            startActivityForResult(intentBtEnabled, REQUEST_ENABLE_BT);
            
            Toast.makeText(this, "Please enable bluetooth and execute the application agagin.",
     Toast.LENGTH_LONG).show();
     }          
     
    }

    @Override
    public void onResume(){
     
        super.onResume();
                       
        int sts;
        sts = blePeri.init(this);
                        
        if(0  > sts)
     {
      if(-1 == sts)
       Toast.makeText(this, "this device is without bluetooth module",
         Toast.LENGTH_LONG).show();
      
      if(-2 == sts)
       Toast.makeText(this, "this device do not support Bluetooth low energy", 
         Toast.LENGTH_LONG).show();
      
      if(-3 == sts)
       Toast.makeText(this, "this device do not support to be a BLE peripheral, " +
         "please buy nexus 6 or 9 then try again", 
         Toast.LENGTH_LONG).show();
      
      finish();
     }   
        
        TextView textView;
     textView = (TextView)findViewById(R.id.mac_text);
     
     textView.setText(BLEPeripheral.getAddress());
     
     adverstiseCheckBox.setEnabled(true);   
    }
    
    
    
    @Override
    protected void onStop() {
        super.onStop();      
    }

        
    
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();
        if (id == R.id.action_settings) {
            return true;
        }
        return super.onOptionsItemSelected(item);
    }
}



activity_main.xml: (layout, very ugly)


<RelativeLayout 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:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.awind.presentsenseperipheral.MainActivity" >

    <TextView
        android:id="@+id/status_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:layout_marginLeft="15dp"
        android:layout_marginTop="25dp"
        android:text="Disable"
        android:textAppearance="?android:attr/textAppearanceMedium" />

    <TextView
        android:id="@+id/mac_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignTop="@+id/status_text"
        android:layout_marginLeft="18dp"
        android:layout_toRightOf="@+id/status_text"
        android:text="00:11:22:AA:BB:CC"
        android:textAppearance="?android:attr/textAppearanceLarge" />

    <CheckBox
        android:id="@+id/advertise_checkBox"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignLeft="@+id/status_text"
        android:layout_below="@+id/mac_text"
        android:layout_marginTop="34dp"
        android:text="Advertise" />

</RelativeLayout>



    I do not like to write too much explanation in here, One said: if you could implement, you understand it; if you could not, you know about nothing of it .

About notification characteristic:


Replace the line :

// Add nodify characteristic here !!! 
As :


final String  CHAR_NOTIFY = "00fffB-0000-1000-8000-00805f9b34fb";  
        final BluetoothGattCharacteristic notifyCharacteristic = new BluetoothGattCharacteristic(
             UUID.fromString(CHAR_NOTIFY), 
             BluetoothGattCharacteristic.PROPERTY_NOTIFY,
             BluetoothGattCharacteristic.PERMISSION_READ
             );
        
        notifyCharacteristic.setValue(new String("0"));
        presentSenseService.addCharacteristic(notifyCharacteristic);  
        
        final Handler handler = new Handler();
        
        Thread thread = new Thread() {
         int i = 0;         
         
            @Override
            public void run() {             
                try {
                    while(true) {
                        sleep(1500);
                        handler.post(this);
                        
                        List<BluetoothDevice> connectedDevices 
                         = mManager.getConnectedDevices(BluetoothProfile.GATT);
                        
                        if(null != connectedDevices)
                        {
                         notifyCharacteristic.setValue(String.valueOf(i).getBytes());
                        
                         mGattServer.notifyCharacteristicChanged(connectedDevices.get(0),
                          notifyCharacteristic, false);
                        }
                        i++;
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };

        thread.start();


    That is, create a thread , that updates value and send a signal to BluetoothGattServer to note the value has been change.


Android as Bluetooth Low Energy Peripherial (GATT server).

标签:android   bluetooth-low-energy   

原文地址:http://blog.csdn.net/u013606170/article/details/46038283

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!