Back to project page accessory-samples.
The source code is released under:
Copyright (c) 2012 Wireless Designs, LLC Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in ...
If you think the Android project accessory-samples listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.
package com.example.android.bluetoothgattperipheral; // w w w . j a va 2s . co m import android.app.Activity; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothGatt; import android.bluetooth.BluetoothGattCharacteristic; import android.bluetooth.BluetoothGattServer; import android.bluetooth.BluetoothGattServerCallback; import android.bluetooth.BluetoothGattService; import android.bluetooth.BluetoothManager; import android.bluetooth.BluetoothProfile; import android.bluetooth.le.AdvertiseCallback; import android.bluetooth.le.AdvertiseData; import android.bluetooth.le.AdvertiseSettings; import android.bluetooth.le.BluetoothLeAdvertiser; import android.content.Intent; import android.content.pm.PackageManager; import android.os.Bundle; import android.os.Handler; import android.os.ParcelUuid; import android.util.Log; import android.widget.ArrayAdapter; import android.widget.ListView; import android.widget.Toast; import java.util.ArrayList; /** * Dave Smith * Date: 11/13/14 * PeripheralActivity */ public class PeripheralActivity extends Activity { private static final String TAG = "PeripheralActivity"; private BluetoothManager mBluetoothManager; private BluetoothAdapter mBluetoothAdapter; private BluetoothLeAdvertiser mBluetoothLeAdvertiser; private BluetoothGattServer mGattServer; private ArrayList<BluetoothDevice> mConnectedDevices; private ArrayAdapter<BluetoothDevice> mConnectedDevicesAdapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ListView list = new ListView(this); setContentView(list); mConnectedDevices = new ArrayList<BluetoothDevice>(); mConnectedDevicesAdapter = new ArrayAdapter<BluetoothDevice>(this, android.R.layout.simple_list_item_1, mConnectedDevices); list.setAdapter(mConnectedDevicesAdapter); /* * Bluetooth in Android 4.3+ is accessed via the BluetoothManager, rather than * the old static BluetoothAdapter.getInstance() */ mBluetoothManager = (BluetoothManager) getSystemService(BLUETOOTH_SERVICE); mBluetoothAdapter = mBluetoothManager.getAdapter(); } @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; } /* * Check for advertising support. Not all devices are enabled to advertise * Bluetooth LE data. */ if (!mBluetoothAdapter.isMultipleAdvertisementSupported()) { Toast.makeText(this, "No Advertising Support.", Toast.LENGTH_SHORT).show(); finish(); return; } mBluetoothLeAdvertiser = mBluetoothAdapter.getBluetoothLeAdvertiser(); mGattServer = mBluetoothManager.openGattServer(this, mGattServerCallback); initServer(); startAdvertising(); } @Override protected void onPause() { super.onPause(); stopAdvertising(); shutdownServer(); } /* * Create the GATT server instance, attaching all services and * characteristics that should be exposed */ private void initServer() { BluetoothGattService service =new BluetoothGattService(DeviceProfile.SERVICE_UUID, BluetoothGattService.SERVICE_TYPE_PRIMARY); BluetoothGattCharacteristic elapsedCharacteristic = new BluetoothGattCharacteristic(DeviceProfile.CHARACTERISTIC_ELAPSED_UUID, //Read-only characteristic, supports notifications BluetoothGattCharacteristic.PROPERTY_READ | BluetoothGattCharacteristic.PROPERTY_NOTIFY, BluetoothGattCharacteristic.PERMISSION_READ); BluetoothGattCharacteristic offsetCharacteristic = new BluetoothGattCharacteristic(DeviceProfile.CHARACTERISTIC_OFFSET_UUID, //Read+write permissions BluetoothGattCharacteristic.PROPERTY_READ | BluetoothGattCharacteristic.PROPERTY_WRITE, BluetoothGattCharacteristic.PERMISSION_READ | BluetoothGattCharacteristic.PERMISSION_WRITE); service.addCharacteristic(elapsedCharacteristic); service.addCharacteristic(offsetCharacteristic); mGattServer.addService(service); } /* * Terminate the server and any running callbacks */ private void shutdownServer() { mHandler.removeCallbacks(mNotifyRunnable); if (mGattServer == null) return; mGattServer.close(); } private Runnable mNotifyRunnable = new Runnable() { @Override public void run() { notifyConnectedDevices(); mHandler.postDelayed(this, 2000); } }; /* * Callback handles all incoming requests from GATT clients. * From connections to read/write requests. */ private BluetoothGattServerCallback mGattServerCallback = new BluetoothGattServerCallback() { @Override public void onConnectionStateChange(BluetoothDevice device, int status, int newState) { super.onConnectionStateChange(device, status, newState); Log.i(TAG, "onConnectionStateChange " +DeviceProfile.getStatusDescription(status)+" " +DeviceProfile.getStateDescription(newState)); if (newState == BluetoothProfile.STATE_CONNECTED) { postDeviceChange(device, true); } else if (newState == BluetoothProfile.STATE_DISCONNECTED) { postDeviceChange(device, false); } } @Override public void onCharacteristicReadRequest(BluetoothDevice device, int requestId, int offset, BluetoothGattCharacteristic characteristic) { super.onCharacteristicReadRequest(device, requestId, offset, characteristic); Log.i(TAG, "onCharacteristicReadRequest " + characteristic.getUuid().toString()); if (DeviceProfile.CHARACTERISTIC_ELAPSED_UUID.equals(characteristic.getUuid())) { mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, 0, getStoredValue()); } if (DeviceProfile.CHARACTERISTIC_OFFSET_UUID.equals(characteristic.getUuid())) { mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, 0, DeviceProfile.bytesFromInt(mTimeOffset)); } /* * Unless the characteristic supports WRITE_NO_RESPONSE, * always send a response back for any request. */ mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_FAILURE, 0, null); } @Override public void onCharacteristicWriteRequest(BluetoothDevice device, int requestId, BluetoothGattCharacteristic characteristic, boolean preparedWrite, boolean responseNeeded, int offset, byte[] value) { super.onCharacteristicWriteRequest(device, requestId, characteristic, preparedWrite, responseNeeded, offset, value); Log.i(TAG, "onCharacteristicWriteRequest "+characteristic.getUuid().toString()); if (DeviceProfile.CHARACTERISTIC_OFFSET_UUID.equals(characteristic.getUuid())) { int newOffset = DeviceProfile.unsignedIntFromBytes(value); setStoredValue(newOffset); if (responseNeeded) { mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, 0, value); } mHandler.post(new Runnable() { @Override public void run() { Toast.makeText(PeripheralActivity.this, "Time Offset Updated", Toast.LENGTH_SHORT).show(); } }); notifyConnectedDevices(); } } }; /* * Initialize the advertiser */ private void startAdvertising() { if (mBluetoothLeAdvertiser == null) return; AdvertiseSettings settings = new AdvertiseSettings.Builder() .setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_BALANCED) .setConnectable(true) .setTimeout(0) .setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_MEDIUM) .build(); AdvertiseData data = new AdvertiseData.Builder() .setIncludeDeviceName(true) .addServiceUuid(new ParcelUuid(DeviceProfile.SERVICE_UUID)) .build(); mBluetoothLeAdvertiser.startAdvertising(settings, data, mAdvertiseCallback); } /* * Terminate the advertiser */ private void stopAdvertising() { if (mBluetoothLeAdvertiser == null) return; mBluetoothLeAdvertiser.stopAdvertising(mAdvertiseCallback); } /* * Callback handles events from the framework describing * if we were successful in starting the advertisement requests. */ private AdvertiseCallback mAdvertiseCallback = new AdvertiseCallback() { @Override public void onStartSuccess(AdvertiseSettings settingsInEffect) { Log.i(TAG, "Peripheral Advertise Started."); postStatusMessage("GATT Server Ready"); } @Override public void onStartFailure(int errorCode) { Log.w(TAG, "Peripheral Advertise Failed: "+errorCode); postStatusMessage("GATT Server Error "+errorCode); } }; private Handler mHandler = new Handler(); private void postStatusMessage(final String message) { mHandler.post(new Runnable() { @Override public void run() { setTitle(message); } }); } private void postDeviceChange(final BluetoothDevice device, final boolean toAdd) { mHandler.post(new Runnable() { @Override public void run() { //This will add the item to our list and update the adapter at the same time. if (toAdd) { mConnectedDevicesAdapter.add(device); } else { mConnectedDevicesAdapter.remove(device); } //Trigger our periodic notification once devices are connected mHandler.removeCallbacks(mNotifyRunnable); if (!mConnectedDevices.isEmpty()) { mHandler.post(mNotifyRunnable); } } }); } /* Storage and access to local characteristic data */ private void notifyConnectedDevices() { for (BluetoothDevice device : mConnectedDevices) { BluetoothGattCharacteristic readCharacteristic = mGattServer.getService(DeviceProfile.SERVICE_UUID) .getCharacteristic(DeviceProfile.CHARACTERISTIC_ELAPSED_UUID); readCharacteristic.setValue(getStoredValue()); mGattServer.notifyCharacteristicChanged(device, readCharacteristic, false); } } private Object mLock = new Object(); private int mTimeOffset; private byte[] getStoredValue() { synchronized (mLock) { return DeviceProfile.getShiftedTimeValue(mTimeOffset); } } private void setStoredValue(int newOffset) { synchronized (mLock) { mTimeOffset = newOffset; } } }