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; /*from w w w.java 2 s . c om*/ import android.app.Activity; import android.app.TimePickerDialog; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothGatt; import android.bluetooth.BluetoothGattCallback; import android.bluetooth.BluetoothGattCharacteristic; import android.bluetooth.BluetoothGattService; import android.bluetooth.BluetoothManager; import android.bluetooth.BluetoothProfile; import android.bluetooth.le.ScanCallback; import android.bluetooth.le.ScanFilter; import android.bluetooth.le.ScanResult; import android.bluetooth.le.ScanSettings; 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.util.SparseArray; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.TextView; import android.widget.TimePicker; import android.widget.Toast; import java.text.DateFormat; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.List; /** * Dave Smith * Date: 11/13/14 * ClientActivity */ public class ClientActivity extends Activity { private static final String TAG = "ClientActivity"; private BluetoothManager mBluetoothManager; private BluetoothAdapter mBluetoothAdapter; private SparseArray<BluetoothDevice> mDevices; private BluetoothGatt mConnectedGatt; private Handler mHandler = new Handler(); /* Client UI elements */ private TextView mLatestValue; private TextView mCurrentOffset; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_client); mLatestValue = (TextView) findViewById(R.id.latest_value); mCurrentOffset = (TextView) findViewById(R.id.offset_date); updateDateText(0); /* * 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(); mDevices = new SparseArray<BluetoothDevice>(); } @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; } } @Override protected void onStop() { super.onStop(); //Stop any active scans stopScan(); //Disconnect from any active connection if (mConnectedGatt != null) { mConnectedGatt.disconnect(); mConnectedGatt = null; } } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.scan, menu); //Add any device elements we've discovered to the overflow menu for (int i=0; i < 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); return super.onOptionsItemSelected(item); } } /* * Select a new time to set as the base offset * on the GATT Server. Then write to the characteristic. */ public void onUpdateClick(View v) { if (mConnectedGatt != null) { final Calendar now = Calendar.getInstance(); TimePickerDialog dialog = new TimePickerDialog(this, new TimePickerDialog.OnTimeSetListener() { @Override public void onTimeSet(TimePicker view, int hourOfDay, int minute) { now.set(Calendar.HOUR_OF_DAY, hourOfDay); now.set(Calendar.MINUTE, minute); now.set(Calendar.SECOND, 0); now.set(Calendar.MILLISECOND, 0); BluetoothGattCharacteristic characteristic = mConnectedGatt .getService(DeviceProfile.SERVICE_UUID) .getCharacteristic(DeviceProfile.CHARACTERISTIC_OFFSET_UUID); byte[] value = DeviceProfile.bytesFromInt((int)(now.getTimeInMillis()/1000)); Log.d(TAG, "Writing value of size "+value.length); characteristic.setValue(value); mConnectedGatt.writeCharacteristic(characteristic); } }, now.get(Calendar.HOUR_OF_DAY), now.get(Calendar.MINUTE), false); dialog.show(); } } /* * Retrieve the current value of the time offset */ public void onGetOffsetClick(View v) { if (mConnectedGatt != null) { BluetoothGattCharacteristic characteristic = mConnectedGatt .getService(DeviceProfile.SERVICE_UUID) .getCharacteristic(DeviceProfile.CHARACTERISTIC_OFFSET_UUID); mConnectedGatt.readCharacteristic(characteristic); mCurrentOffset.setText("---"); } } private void updateDateText(long offset) { Date date = new Date(offset); String dateString = DateFormat.getDateTimeInstance().format(date); mCurrentOffset.setText(dateString); } /* * Begin a scan for new servers that advertise our * matching service. */ private void startScan() { //Scan for devices advertising our custom service ScanFilter scanFilter = new ScanFilter.Builder() .setServiceUuid(new ParcelUuid(DeviceProfile.SERVICE_UUID)) .build(); ArrayList<ScanFilter> filters = new ArrayList<ScanFilter>(); filters.add(scanFilter); ScanSettings settings = new ScanSettings.Builder() .setScanMode(ScanSettings.SCAN_MODE_BALANCED) .build(); mBluetoothAdapter.getBluetoothLeScanner().startScan(filters, settings, mScanCallback); } /* * Terminate any active scans */ private void stopScan() { mBluetoothAdapter.getBluetoothLeScanner().stopScan(mScanCallback); } /* * Callback handles results from new devices that appear * during a scan. Batch results appear when scan delay * filters are enabled. */ private ScanCallback mScanCallback = new ScanCallback() { @Override public void onScanResult(int callbackType, ScanResult result) { Log.d(TAG, "onScanResult"); processResult(result); } @Override public void onBatchScanResults(List<ScanResult> results) { Log.d(TAG, "onBatchScanResults: "+results.size()+" results"); for (ScanResult result : results) { processResult(result); } } @Override public void onScanFailed(int errorCode) { Log.w(TAG, "LE Scan Failed: "+errorCode); } private void processResult(ScanResult result) { BluetoothDevice device = result.getDevice(); Log.i(TAG, "New LE Device: " + device.getName() + " @ " + result.getRssi()); //Add it to the collection mDevices.put(device.hashCode(), device); //Update the overflow menu invalidateOptionsMenu(); stopScan(); } }; /* * Callback handles GATT client events, such as results from * reading or writing a characteristic value on the server. */ private BluetoothGattCallback mGattCallback = new BluetoothGattCallback() { @Override public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { super.onConnectionStateChange(gatt, status, newState); Log.d(TAG, "onConnectionStateChange " +DeviceProfile.getStatusDescription(status)+" " +DeviceProfile.getStateDescription(newState)); if (newState == BluetoothProfile.STATE_CONNECTED) { gatt.discoverServices(); } } @Override public void onServicesDiscovered(BluetoothGatt gatt, int status) { super.onServicesDiscovered(gatt, status); Log.d(TAG, "onServicesDiscovered:"); for (BluetoothGattService service : gatt.getServices()) { Log.d(TAG, "Service: "+service.getUuid()); if (DeviceProfile.SERVICE_UUID.equals(service.getUuid())) { //Read the current characteristic's value gatt.readCharacteristic(service.getCharacteristic(DeviceProfile.CHARACTERISTIC_ELAPSED_UUID)); } } } @Override public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { super.onCharacteristicRead(gatt, characteristic, status); final int charValue = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT32, 0); if (DeviceProfile.CHARACTERISTIC_ELAPSED_UUID.equals(characteristic.getUuid())) { mHandler.post(new Runnable() { @Override public void run() { mLatestValue.setText(String.valueOf(charValue)); } }); //Register for further updates as notifications gatt.setCharacteristicNotification(characteristic, true); } if (DeviceProfile.CHARACTERISTIC_OFFSET_UUID.equals(characteristic.getUuid())) { Log.d(TAG, "Current time offset: "+charValue); mHandler.post(new Runnable() { @Override public void run() { updateDateText((long)charValue * 1000); } }); } } @Override public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) { super.onCharacteristicChanged(gatt, characteristic); Log.i(TAG, "Notification of time characteristic changed on server."); final int charValue = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT32, 0); mHandler.post(new Runnable() { @Override public void run() { mLatestValue.setText(String.valueOf(charValue)); } }); } }; }