From a6b4636faeaa3613bae3dfcbed7fd8886d615714 Mon Sep 17 00:00:00 2001 From: Trevor Johns Date: Wed, 30 Oct 2013 16:38:01 -0700 Subject: Restore "Merge downstream branch 'developers-dev' into 'klp-dev'" This reverts commit ec985147ec781dfff9a229c6b794ee4eac0ced91. --- .../BluetoothLeGatt/BluetoothLeGatt/build.gradle | 6 - .../BluetoothLeGatt/src/main/AndroidManifest.xml | 45 --- .../example/bluetooth/le/BluetoothLeService.java | 319 --------------------- .../bluetooth/le/DeviceControlActivity.java | 309 -------------------- .../example/bluetooth/le/DeviceScanActivity.java | 269 ----------------- .../example/bluetooth/le/SampleGattAttributes.java | 42 --- .../src/main/res/drawable-hdpi/ic_launcher.png | Bin 5170 -> 0 bytes .../src/main/res/drawable-mdpi/ic_launcher.png | Bin 3025 -> 0 bytes .../src/main/res/drawable-xhdpi/ic_launcher.png | Bin 7227 -> 0 bytes .../src/main/res/drawable-xxhdpi/ic_launcher.png | Bin 12800 -> 0 bytes .../layout/actionbar_indeterminate_progress.xml | 23 -- .../res/layout/gatt_services_characteristics.xml | 71 ----- .../src/main/res/layout/listitem_device.xml | 28 -- .../src/main/res/menu/gatt_services.xml | 29 -- .../BluetoothLeGatt/src/main/res/menu/main.xml | 29 -- .../src/main/res/values/strings.xml | 37 --- .../BluetoothLeGattSample/.gitignore | 16 ++ .../BluetoothLeGattSample/proguard-project.txt | 20 ++ .../src/main/AndroidManifest.xml | 50 ++++ .../bluetoothlegatt/BluetoothLeService.java | 319 +++++++++++++++++++++ .../bluetoothlegatt/DeviceControlActivity.java | 309 ++++++++++++++++++++ .../bluetoothlegatt/DeviceScanActivity.java | 268 +++++++++++++++++ .../bluetoothlegatt/SampleGattAttributes.java | 42 +++ .../src/main/res/drawable-hdpi/ic_launcher.png | Bin 0 -> 5170 bytes .../src/main/res/drawable-mdpi/ic_launcher.png | Bin 0 -> 3025 bytes .../src/main/res/drawable-xhdpi/ic_launcher.png | Bin 0 -> 7227 bytes .../src/main/res/drawable-xxhdpi/ic_launcher.png | Bin 0 -> 12800 bytes .../layout/actionbar_indeterminate_progress.xml | 23 ++ .../res/layout/gatt_services_characteristics.xml | 71 +++++ .../src/main/res/layout/listitem_device.xml | 28 ++ .../src/main/res/menu/gatt_services.xml | 29 ++ .../src/main/res/menu/main.xml | 29 ++ .../src/main/res/values/strings.xml | 36 +++ .../bluetooth/BluetoothLeGatt/build.gradle | 16 +- .../BluetoothLeGatt/buildSrc/build.gradle | 18 ++ .../gradle/wrapper/gradle-wrapper.properties | 2 +- .../bluetooth/BluetoothLeGatt/settings.gradle | 5 +- .../bluetooth/BluetoothLeGatt/template-params.xml | 36 +++ 38 files changed, 1308 insertions(+), 1216 deletions(-) delete mode 100644 connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGatt/build.gradle delete mode 100644 connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGatt/src/main/AndroidManifest.xml delete mode 100644 connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGatt/src/main/java/com/example/bluetooth/le/BluetoothLeService.java delete mode 100644 connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGatt/src/main/java/com/example/bluetooth/le/DeviceControlActivity.java delete mode 100644 connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGatt/src/main/java/com/example/bluetooth/le/DeviceScanActivity.java delete mode 100644 connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGatt/src/main/java/com/example/bluetooth/le/SampleGattAttributes.java delete mode 100755 connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGatt/src/main/res/drawable-hdpi/ic_launcher.png delete mode 100755 connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGatt/src/main/res/drawable-mdpi/ic_launcher.png delete mode 100755 connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGatt/src/main/res/drawable-xhdpi/ic_launcher.png delete mode 100755 connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGatt/src/main/res/drawable-xxhdpi/ic_launcher.png delete mode 100644 connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGatt/src/main/res/layout/actionbar_indeterminate_progress.xml delete mode 100644 connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGatt/src/main/res/layout/gatt_services_characteristics.xml delete mode 100644 connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGatt/src/main/res/layout/listitem_device.xml delete mode 100644 connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGatt/src/main/res/menu/gatt_services.xml delete mode 100644 connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGatt/src/main/res/menu/main.xml delete mode 100644 connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGatt/src/main/res/values/strings.xml create mode 100644 connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGattSample/.gitignore create mode 100644 connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGattSample/proguard-project.txt create mode 100644 connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGattSample/src/main/AndroidManifest.xml create mode 100644 connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGattSample/src/main/java/com/example/android/bluetoothlegatt/BluetoothLeService.java create mode 100644 connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGattSample/src/main/java/com/example/android/bluetoothlegatt/DeviceControlActivity.java create mode 100644 connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGattSample/src/main/java/com/example/android/bluetoothlegatt/DeviceScanActivity.java create mode 100644 connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGattSample/src/main/java/com/example/android/bluetoothlegatt/SampleGattAttributes.java create mode 100755 connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGattSample/src/main/res/drawable-hdpi/ic_launcher.png create mode 100755 connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGattSample/src/main/res/drawable-mdpi/ic_launcher.png create mode 100755 connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGattSample/src/main/res/drawable-xhdpi/ic_launcher.png create mode 100755 connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGattSample/src/main/res/drawable-xxhdpi/ic_launcher.png create mode 100644 connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGattSample/src/main/res/layout/actionbar_indeterminate_progress.xml create mode 100644 connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGattSample/src/main/res/layout/gatt_services_characteristics.xml create mode 100644 connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGattSample/src/main/res/layout/listitem_device.xml create mode 100644 connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGattSample/src/main/res/menu/gatt_services.xml create mode 100644 connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGattSample/src/main/res/menu/main.xml create mode 100644 connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGattSample/src/main/res/values/strings.xml create mode 100644 connectivity/bluetooth/BluetoothLeGatt/buildSrc/build.gradle create mode 100644 connectivity/bluetooth/BluetoothLeGatt/template-params.xml (limited to 'connectivity/bluetooth') diff --git a/connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGatt/build.gradle b/connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGatt/build.gradle deleted file mode 100644 index 945e1f51..00000000 --- a/connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGatt/build.gradle +++ /dev/null @@ -1,6 +0,0 @@ -apply plugin: 'android' - -android { - compileSdkVersion 18 - buildToolsVersion "18.0.0" -} diff --git a/connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGatt/src/main/AndroidManifest.xml b/connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGatt/src/main/AndroidManifest.xml deleted file mode 100644 index 019d2587..00000000 --- a/connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGatt/src/main/AndroidManifest.xml +++ /dev/null @@ -1,45 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - diff --git a/connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGatt/src/main/java/com/example/bluetooth/le/BluetoothLeService.java b/connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGatt/src/main/java/com/example/bluetooth/le/BluetoothLeService.java deleted file mode 100644 index 9e7aabd8..00000000 --- a/connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGatt/src/main/java/com/example/bluetooth/le/BluetoothLeService.java +++ /dev/null @@ -1,319 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.bluetooth.le; - -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.util.Log; - -import java.util.List; -import java.util.UUID; - -/** - * Service for managing connection and data communication with a GATT server hosted on a - * given Bluetooth LE device. - */ -public class BluetoothLeService extends Service { - private final static String TAG = BluetoothLeService.class.getSimpleName(); - - private BluetoothManager mBluetoothManager; - private BluetoothAdapter mBluetoothAdapter; - private String mBluetoothDeviceAddress; - private BluetoothGatt mBluetoothGatt; - private int mConnectionState = STATE_DISCONNECTED; - - private static final int STATE_DISCONNECTED = 0; - private static final int STATE_CONNECTING = 1; - private static final int STATE_CONNECTED = 2; - - public final static String ACTION_GATT_CONNECTED = - "com.example.bluetooth.le.ACTION_GATT_CONNECTED"; - public final static String ACTION_GATT_DISCONNECTED = - "com.example.bluetooth.le.ACTION_GATT_DISCONNECTED"; - public final static String ACTION_GATT_SERVICES_DISCOVERED = - "com.example.bluetooth.le.ACTION_GATT_SERVICES_DISCOVERED"; - public final static String ACTION_DATA_AVAILABLE = - "com.example.bluetooth.le.ACTION_DATA_AVAILABLE"; - public final static String EXTRA_DATA = - "com.example.bluetooth.le.EXTRA_DATA"; - - public final static UUID UUID_HEART_RATE_MEASUREMENT = - UUID.fromString(SampleGattAttributes.HEART_RATE_MEASUREMENT); - - // Implements callback methods for GATT events that the app cares about. For example, - // connection change and services discovered. - private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() { - @Override - public 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 discover services after 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 - public void onServicesDiscovered(BluetoothGatt gatt, int status) { - if (status == BluetoothGatt.GATT_SUCCESS) { - broadcastUpdate(ACTION_GATT_SERVICES_DISCOVERED); - } else { - Log.w(TAG, "onServicesDiscovered received: " + status); - } - } - - @Override - public void onCharacteristicRead(BluetoothGatt gatt, - BluetoothGattCharacteristic characteristic, - int status) { - if (status == BluetoothGatt.GATT_SUCCESS) { - broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic); - } - } - - @Override - public void onCharacteristicChanged(BluetoothGatt gatt, - BluetoothGattCharacteristic characteristic) { - broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic); - } - }; - - private void broadcastUpdate(final String action) { - final Intent intent = new Intent(action); - sendBroadcast(intent); - } - - private void broadcastUpdate(final String action, - final BluetoothGattCharacteristic characteristic) { - final Intent intent = new Intent(action); - - // This is special handling for the Heart Rate Measurement profile. Data parsing is - // carried out as 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 rate format UINT16."); - } else { - format = BluetoothGattCharacteristic.FORMAT_UINT8; - Log.d(TAG, "Heart rate format UINT8."); - } - final int heartRate = characteristic.getIntValue(format, 1); - Log.d(TAG, String.format("Received heart rate: %d", heartRate)); - intent.putExtra(EXTRA_DATA, String.valueOf(heartRate)); - } else { - // For all other profiles, writes the data formatted in HEX. - final byte[] data = characteristic.getValue(); - if (data != null && data.length > 0) { - final StringBuilder stringBuilder = new StringBuilder(data.length); - for(byte byteChar : data) - stringBuilder.append(String.format("%02X ", byteChar)); - intent.putExtra(EXTRA_DATA, new String(data) + "\n" + stringBuilder.toString()); - } - } - sendBroadcast(intent); - } - - public class LocalBinder extends Binder { - BluetoothLeService getService() { - return BluetoothLeService.this; - } - } - - @Override - public IBinder onBind(Intent intent) { - return mBinder; - } - - @Override - public boolean onUnbind(Intent intent) { - // After using a given device, you should make sure that BluetoothGatt.close() is called - // such that resources are cleaned up properly. In this particular example, close() is - // invoked when the UI is disconnected from the Service. - close(); - return super.onUnbind(intent); - } - - private final IBinder mBinder = new LocalBinder(); - - /** - * Initializes a reference to the local Bluetooth adapter. - * - * @return Return true if the initialization is successful. - */ - public boolean initialize() { - // For API level 18 and above, get 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."); - return false; - } - } - - mBluetoothAdapter = mBluetoothManager.getAdapter(); - if (mBluetoothAdapter == null) { - Log.e(TAG, "Unable to obtain a BluetoothAdapter."); - return false; - } - - return true; - } - - /** - * Connects to the GATT server hosted on the Bluetooth LE device. - * - * @param address The device address of the destination device. - * - * @return Return true if the connection is initiated successfully. The connection result - * is reported asynchronously through the - * {@code BluetoothGattCallback#onConnectionStateChange(android.bluetooth.BluetoothGatt, int, int)} - * callback. - */ - public boolean connect(final String address) { - if (mBluetoothAdapter == null || address == null) { - Log.w(TAG, "BluetoothAdapter not initialized or unspecified address."); - return false; - } - - // Previously connected device. Try to reconnect. - if (mBluetoothDeviceAddress != null && address.equals(mBluetoothDeviceAddress) - && mBluetoothGatt != null) { - Log.d(TAG, "Trying to use an existing mBluetoothGatt for connection."); - if (mBluetoothGatt.connect()) { - mConnectionState = STATE_CONNECTING; - return true; - } else { - return false; - } - } - - final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address); - if (device == null) { - Log.w(TAG, "Device not found. Unable to connect."); - return false; - } - // We want to directly connect to the device, so we are setting the autoConnect - // parameter to false. - mBluetoothGatt = device.connectGatt(this, false, mGattCallback); - Log.d(TAG, "Trying to create a new connection."); - mBluetoothDeviceAddress = address; - mConnectionState = STATE_CONNECTING; - return true; - } - - /** - * Disconnects an existing connection or cancel a pending connection. The disconnection result - * is reported asynchronously through the - * {@code BluetoothGattCallback#onConnectionStateChange(android.bluetooth.BluetoothGatt, int, int)} - * callback. - */ - public void disconnect() { - if (mBluetoothAdapter == null || mBluetoothGatt == null) { - Log.w(TAG, "BluetoothAdapter not initialized"); - return; - } - mBluetoothGatt.disconnect(); - } - - /** - * After using a given BLE device, the app must call this method to ensure resources are - * released properly. - */ - public void close() { - if (mBluetoothGatt == null) { - return; - } - mBluetoothGatt.close(); - mBluetoothGatt = null; - } - - /** - * Request a read on a given {@code BluetoothGattCharacteristic}. The read result is reported - * asynchronously through the {@code BluetoothGattCallback#onCharacteristicRead(android.bluetooth.BluetoothGatt, android.bluetooth.BluetoothGattCharacteristic, int)} - * callback. - * - * @param characteristic The characteristic to read from. - */ - public void readCharacteristic(BluetoothGattCharacteristic characteristic) { - if (mBluetoothAdapter == null || mBluetoothGatt == null) { - Log.w(TAG, "BluetoothAdapter not initialized"); - return; - } - mBluetoothGatt.readCharacteristic(characteristic); - } - - /** - * Enables or disables notification on a give characteristic. - * - * @param characteristic Characteristic to act on. - * @param enabled If true, enable notification. False otherwise. - */ - public void setCharacteristicNotification(BluetoothGattCharacteristic characteristic, - boolean enabled) { - if (mBluetoothAdapter == null || mBluetoothGatt == null) { - Log.w(TAG, "BluetoothAdapter not initialized"); - return; - } - mBluetoothGatt.setCharacteristicNotification(characteristic, enabled); - - // This is specific to Heart Rate Measurement. - if (UUID_HEART_RATE_MEASUREMENT.equals(characteristic.getUuid())) { - BluetoothGattDescriptor descriptor = characteristic.getDescriptor( - UUID.fromString(SampleGattAttributes.CLIENT_CHARACTERISTIC_CONFIG)); - descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE); - mBluetoothGatt.writeDescriptor(descriptor); - } - } - - /** - * Retrieves a list of supported GATT services on the connected device. This should be - * invoked only after {@code BluetoothGatt#discoverServices()} completes successfully. - * - * @return A {@code List} of supported services. - */ - public List getSupportedGattServices() { - if (mBluetoothGatt == null) return null; - - return mBluetoothGatt.getServices(); - } -} diff --git a/connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGatt/src/main/java/com/example/bluetooth/le/DeviceControlActivity.java b/connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGatt/src/main/java/com/example/bluetooth/le/DeviceControlActivity.java deleted file mode 100644 index 06b3bb46..00000000 --- a/connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGatt/src/main/java/com/example/bluetooth/le/DeviceControlActivity.java +++ /dev/null @@ -1,309 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.bluetooth.le; - -import android.app.Activity; -import android.bluetooth.BluetoothGattCharacteristic; -import android.bluetooth.BluetoothGattService; -import android.content.BroadcastReceiver; -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.ServiceConnection; -import android.os.Bundle; -import android.os.IBinder; -import android.util.Log; -import android.view.Menu; -import android.view.MenuItem; -import android.view.View; -import android.widget.ExpandableListView; -import android.widget.SimpleExpandableListAdapter; -import android.widget.TextView; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; - -/** - * For a given BLE device, this Activity provides the user interface to connect, display data, - * and display GATT services and characteristics supported by the device. The Activity - * communicates with {@code BluetoothLeService}, which in turn interacts with the - * Bluetooth LE API. - */ -public class DeviceControlActivity extends Activity { - private final static String TAG = DeviceControlActivity.class.getSimpleName(); - - public static final String EXTRAS_DEVICE_NAME = "DEVICE_NAME"; - public static final String EXTRAS_DEVICE_ADDRESS = "DEVICE_ADDRESS"; - - private TextView mConnectionState; - private TextView mDataField; - private String mDeviceName; - private String mDeviceAddress; - private ExpandableListView mGattServicesList; - private BluetoothLeService mBluetoothLeService; - private ArrayList> mGattCharacteristics = - new ArrayList>(); - private boolean mConnected = false; - private BluetoothGattCharacteristic mNotifyCharacteristic; - - private final String LIST_NAME = "NAME"; - private final String LIST_UUID = "UUID"; - - // Code to manage Service lifecycle. - private final ServiceConnection mServiceConnection = new ServiceConnection() { - - @Override - public void onServiceConnected(ComponentName componentName, IBinder service) { - mBluetoothLeService = ((BluetoothLeService.LocalBinder) service).getService(); - if (!mBluetoothLeService.initialize()) { - Log.e(TAG, "Unable to initialize Bluetooth"); - finish(); - } - // Automatically connects to the device upon successful start-up initialization. - mBluetoothLeService.connect(mDeviceAddress); - } - - @Override - public void onServiceDisconnected(ComponentName componentName) { - mBluetoothLeService = null; - } - }; - - // Handles various events fired by the Service. - // ACTION_GATT_CONNECTED: connected to a GATT server. - // ACTION_GATT_DISCONNECTED: disconnected from a GATT server. - // ACTION_GATT_SERVICES_DISCOVERED: discovered GATT services. - // ACTION_DATA_AVAILABLE: received data from the device. This can be a result of read - // or notification operations. - private final BroadcastReceiver mGattUpdateReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - final String action = intent.getAction(); - if (BluetoothLeService.ACTION_GATT_CONNECTED.equals(action)) { - mConnected = true; - updateConnectionState(R.string.connected); - invalidateOptionsMenu(); - } else if (BluetoothLeService.ACTION_GATT_DISCONNECTED.equals(action)) { - mConnected = false; - updateConnectionState(R.string.disconnected); - invalidateOptionsMenu(); - clearUI(); - } else if (BluetoothLeService.ACTION_GATT_SERVICES_DISCOVERED.equals(action)) { - // Show all the supported services and characteristics on the user interface. - displayGattServices(mBluetoothLeService.getSupportedGattServices()); - } else if (BluetoothLeService.ACTION_DATA_AVAILABLE.equals(action)) { - displayData(intent.getStringExtra(BluetoothLeService.EXTRA_DATA)); - } - } - }; - - // If a given GATT characteristic is selected, check for supported features. This sample - // demonstrates 'Read' and 'Notify' features. See - // http://d.android.com/reference/android/bluetooth/BluetoothGatt.html for the complete - // list of supported characteristic features. - private final ExpandableListView.OnChildClickListener servicesListClickListner = - new ExpandableListView.OnChildClickListener() { - @Override - public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, - int childPosition, long id) { - if (mGattCharacteristics != null) { - final BluetoothGattCharacteristic characteristic = - mGattCharacteristics.get(groupPosition).get(childPosition); - final int charaProp = characteristic.getProperties(); - if ((charaProp | BluetoothGattCharacteristic.PROPERTY_READ) > 0) { - // If there is an active notification on a characteristic, clear - // it first so it doesn't update the data field on the user interface. - if (mNotifyCharacteristic != null) { - mBluetoothLeService.setCharacteristicNotification( - mNotifyCharacteristic, false); - mNotifyCharacteristic = null; - } - mBluetoothLeService.readCharacteristic(characteristic); - } - if ((charaProp | BluetoothGattCharacteristic.PROPERTY_NOTIFY) > 0) { - mNotifyCharacteristic = characteristic; - mBluetoothLeService.setCharacteristicNotification( - characteristic, true); - } - return true; - } - return false; - } - }; - - private void clearUI() { - mGattServicesList.setAdapter((SimpleExpandableListAdapter) null); - mDataField.setText(R.string.no_data); - } - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.gatt_services_characteristics); - - final Intent intent = getIntent(); - mDeviceName = intent.getStringExtra(EXTRAS_DEVICE_NAME); - mDeviceAddress = intent.getStringExtra(EXTRAS_DEVICE_ADDRESS); - - // Sets up UI references. - ((TextView) findViewById(R.id.device_address)).setText(mDeviceAddress); - mGattServicesList = (ExpandableListView) findViewById(R.id.gatt_services_list); - mGattServicesList.setOnChildClickListener(servicesListClickListner); - mConnectionState = (TextView) findViewById(R.id.connection_state); - mDataField = (TextView) findViewById(R.id.data_value); - - getActionBar().setTitle(mDeviceName); - getActionBar().setDisplayHomeAsUpEnabled(true); - Intent gattServiceIntent = new Intent(this, BluetoothLeService.class); - bindService(gattServiceIntent, mServiceConnection, BIND_AUTO_CREATE); - } - - @Override - protected void onResume() { - super.onResume(); - registerReceiver(mGattUpdateReceiver, makeGattUpdateIntentFilter()); - if (mBluetoothLeService != null) { - final boolean result = mBluetoothLeService.connect(mDeviceAddress); - Log.d(TAG, "Connect request result=" + result); - } - } - - @Override - protected void onPause() { - super.onPause(); - unregisterReceiver(mGattUpdateReceiver); - } - - @Override - protected void onDestroy() { - super.onDestroy(); - unbindService(mServiceConnection); - mBluetoothLeService = null; - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - getMenuInflater().inflate(R.menu.gatt_services, menu); - if (mConnected) { - menu.findItem(R.id.menu_connect).setVisible(false); - menu.findItem(R.id.menu_disconnect).setVisible(true); - } else { - menu.findItem(R.id.menu_connect).setVisible(true); - menu.findItem(R.id.menu_disconnect).setVisible(false); - } - return true; - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch(item.getItemId()) { - case R.id.menu_connect: - mBluetoothLeService.connect(mDeviceAddress); - return true; - case R.id.menu_disconnect: - mBluetoothLeService.disconnect(); - return true; - case android.R.id.home: - onBackPressed(); - return true; - } - return super.onOptionsItemSelected(item); - } - - private void updateConnectionState(final int resourceId) { - runOnUiThread(new Runnable() { - @Override - public void run() { - mConnectionState.setText(resourceId); - } - }); - } - - private void displayData(String data) { - if (data != null) { - mDataField.setText(data); - } - } - - // Demonstrates how to iterate through the supported GATT Services/Characteristics. - // In this sample, we populate the data structure that is bound to the ExpandableListView - // on the UI. - private void displayGattServices(List gattServices) { - if (gattServices == null) return; - String uuid = null; - String unknownServiceString = getResources().getString(R.string.unknown_service); - String unknownCharaString = getResources().getString(R.string.unknown_characteristic); - ArrayList> gattServiceData = new ArrayList>(); - ArrayList>> gattCharacteristicData - = new ArrayList>>(); - mGattCharacteristics = new ArrayList>(); - - // Loops through available GATT Services. - for (BluetoothGattService gattService : gattServices) { - HashMap currentServiceData = new HashMap(); - uuid = gattService.getUuid().toString(); - currentServiceData.put( - LIST_NAME, SampleGattAttributes.lookup(uuid, unknownServiceString)); - currentServiceData.put(LIST_UUID, uuid); - gattServiceData.add(currentServiceData); - - ArrayList> gattCharacteristicGroupData = - new ArrayList>(); - List gattCharacteristics = - gattService.getCharacteristics(); - ArrayList charas = - new ArrayList(); - - // Loops through available Characteristics. - for (BluetoothGattCharacteristic gattCharacteristic : gattCharacteristics) { - charas.add(gattCharacteristic); - HashMap currentCharaData = new HashMap(); - uuid = gattCharacteristic.getUuid().toString(); - currentCharaData.put( - LIST_NAME, SampleGattAttributes.lookup(uuid, unknownCharaString)); - currentCharaData.put(LIST_UUID, uuid); - gattCharacteristicGroupData.add(currentCharaData); - } - mGattCharacteristics.add(charas); - gattCharacteristicData.add(gattCharacteristicGroupData); - } - - SimpleExpandableListAdapter gattServiceAdapter = new SimpleExpandableListAdapter( - this, - gattServiceData, - android.R.layout.simple_expandable_list_item_2, - new String[] {LIST_NAME, LIST_UUID}, - new int[] { android.R.id.text1, android.R.id.text2 }, - gattCharacteristicData, - android.R.layout.simple_expandable_list_item_2, - new String[] {LIST_NAME, LIST_UUID}, - new int[] { android.R.id.text1, android.R.id.text2 } - ); - mGattServicesList.setAdapter(gattServiceAdapter); - } - - private static IntentFilter makeGattUpdateIntentFilter() { - final IntentFilter intentFilter = new IntentFilter(); - intentFilter.addAction(BluetoothLeService.ACTION_GATT_CONNECTED); - intentFilter.addAction(BluetoothLeService.ACTION_GATT_DISCONNECTED); - intentFilter.addAction(BluetoothLeService.ACTION_GATT_SERVICES_DISCOVERED); - intentFilter.addAction(BluetoothLeService.ACTION_DATA_AVAILABLE); - return intentFilter; - } -} diff --git a/connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGatt/src/main/java/com/example/bluetooth/le/DeviceScanActivity.java b/connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGatt/src/main/java/com/example/bluetooth/le/DeviceScanActivity.java deleted file mode 100644 index 1cc954df..00000000 --- a/connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGatt/src/main/java/com/example/bluetooth/le/DeviceScanActivity.java +++ /dev/null @@ -1,269 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.bluetooth.le; - -import android.app.Activity; -import android.app.ListActivity; -import android.bluetooth.BluetoothAdapter; -import android.bluetooth.BluetoothDevice; -import android.bluetooth.BluetoothManager; -import android.content.Context; -import android.content.Intent; -import android.content.pm.PackageManager; -import android.os.Bundle; -import android.os.Handler; -import android.view.LayoutInflater; -import android.view.Menu; -import android.view.MenuItem; -import android.view.View; -import android.view.ViewGroup; -import android.widget.BaseAdapter; -import android.widget.ListView; -import android.widget.TextView; -import android.widget.Toast; - -import java.util.ArrayList; -import java.util.UUID; - -/** - * Activity for scanning and displaying available Bluetooth LE devices. - */ -public class DeviceScanActivity extends ListActivity { - private LeDeviceListAdapter mLeDeviceListAdapter; - private BluetoothAdapter mBluetoothAdapter; - private boolean mScanning; - private Handler mHandler; - - private static final int REQUEST_ENABLE_BT = 1; - // Stops scanning after 10 seconds. - private static final long SCAN_PERIOD = 10000; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - getActionBar().setTitle(R.string.title_devices); - mHandler = new Handler(); - - // Use this check to determine whether BLE is supported on the device. Then you can - // selectively disable BLE-related features. - if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) { - Toast.makeText(this, R.string.ble_not_supported, Toast.LENGTH_SHORT).show(); - finish(); - } - - // Initializes a Bluetooth adapter. For API level 18 and above, get a reference to - // BluetoothAdapter through BluetoothManager. - final BluetoothManager bluetoothManager = - (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE); - mBluetoothAdapter = bluetoothManager.getAdapter(); - - // Checks if Bluetooth is supported on the device. - if (mBluetoothAdapter == null) { - Toast.makeText(this, R.string.error_bluetooth_not_supported, Toast.LENGTH_SHORT).show(); - finish(); - return; - } - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - getMenuInflater().inflate(R.menu.main, menu); - if (!mScanning) { - menu.findItem(R.id.menu_stop).setVisible(false); - menu.findItem(R.id.menu_scan).setVisible(true); - menu.findItem(R.id.menu_refresh).setActionView(null); - } else { - menu.findItem(R.id.menu_stop).setVisible(true); - menu.findItem(R.id.menu_scan).setVisible(false); - menu.findItem(R.id.menu_refresh).setActionView( - R.layout.actionbar_indeterminate_progress); - } - return true; - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case R.id.menu_scan: - mLeDeviceListAdapter.clear(); - scanLeDevice(true); - break; - case R.id.menu_stop: - scanLeDevice(false); - break; - } - return true; - } - - @Override - protected void onResume() { - super.onResume(); - - // Ensures Bluetooth is enabled on the device. If Bluetooth is not currently enabled, - // fire an intent to display a dialog asking the user to grant permission to enable it. - if (!mBluetoothAdapter.isEnabled()) { - if (!mBluetoothAdapter.isEnabled()) { - Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); - startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT); - } - } - - // Initializes list view adapter. - mLeDeviceListAdapter = new LeDeviceListAdapter(); - setListAdapter(mLeDeviceListAdapter); - scanLeDevice(true); - } - - @Override - protected void onActivityResult(int requestCode, int resultCode, Intent data) { - // User chose not to enable Bluetooth. - if (requestCode == REQUEST_ENABLE_BT && resultCode == Activity.RESULT_CANCELED) { - finish(); - return; - } - super.onActivityResult(requestCode, resultCode, data); - } - - @Override - protected void onPause() { - super.onPause(); - scanLeDevice(false); - mLeDeviceListAdapter.clear(); - } - - @Override - protected void onListItemClick(ListView l, View v, int position, long id) { - final BluetoothDevice device = mLeDeviceListAdapter.getDevice(position); - if (device == null) return; - final Intent intent = new Intent(this, DeviceControlActivity.class); - intent.putExtra(DeviceControlActivity.EXTRAS_DEVICE_NAME, device.getName()); - intent.putExtra(DeviceControlActivity.EXTRAS_DEVICE_ADDRESS, device.getAddress()); - if (mScanning) { - mBluetoothAdapter.stopLeScan(mLeScanCallback); - mScanning = false; - } - startActivity(intent); - } - - private void scanLeDevice(final boolean enable) { - if (enable) { - // Stops scanning after a pre-defined scan period. - mHandler.postDelayed(new Runnable() { - @Override - public void run() { - mScanning = false; - mBluetoothAdapter.stopLeScan(mLeScanCallback); - invalidateOptionsMenu(); - } - }, SCAN_PERIOD); - - mScanning = true; - mBluetoothAdapter.startLeScan(mLeScanCallback); - } else { - mScanning = false; - mBluetoothAdapter.stopLeScan(mLeScanCallback); - } - invalidateOptionsMenu(); - } - - // Adapter for holding devices found through scanning. - private class LeDeviceListAdapter extends BaseAdapter { - private ArrayList mLeDevices; - private LayoutInflater mInflator; - - public LeDeviceListAdapter() { - super(); - mLeDevices = new ArrayList(); - mInflator = DeviceScanActivity.this.getLayoutInflater(); - } - - public void addDevice(BluetoothDevice device) { - if(!mLeDevices.contains(device)) { - mLeDevices.add(device); - } - } - - public BluetoothDevice getDevice(int position) { - return mLeDevices.get(position); - } - - public void clear() { - mLeDevices.clear(); - } - - @Override - public int getCount() { - return mLeDevices.size(); - } - - @Override - public Object getItem(int i) { - return mLeDevices.get(i); - } - - @Override - public long getItemId(int i) { - return i; - } - - @Override - public View getView(int i, View view, ViewGroup viewGroup) { - ViewHolder viewHolder; - // General ListView optimization code. - if (view == null) { - view = mInflator.inflate(R.layout.listitem_device, null); - viewHolder = new ViewHolder(); - viewHolder.deviceAddress = (TextView) view.findViewById(R.id.device_address); - viewHolder.deviceName = (TextView) view.findViewById(R.id.device_name); - view.setTag(viewHolder); - } else { - viewHolder = (ViewHolder) view.getTag(); - } - - BluetoothDevice device = mLeDevices.get(i); - final String deviceName = device.getName(); - if (deviceName != null && deviceName.length() > 0) - viewHolder.deviceName.setText(deviceName); - else - viewHolder.deviceName.setText(R.string.unknown_device); - viewHolder.deviceAddress.setText(device.getAddress()); - - return view; - } - } - - // Device scan callback. - private BluetoothAdapter.LeScanCallback mLeScanCallback = - new BluetoothAdapter.LeScanCallback() { - - @Override - public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) { - runOnUiThread(new Runnable() { - @Override - public void run() { - mLeDeviceListAdapter.addDevice(device); - mLeDeviceListAdapter.notifyDataSetChanged(); - } - }); - } - }; - - static class ViewHolder { - TextView deviceName; - TextView deviceAddress; - } -} \ No newline at end of file diff --git a/connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGatt/src/main/java/com/example/bluetooth/le/SampleGattAttributes.java b/connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGatt/src/main/java/com/example/bluetooth/le/SampleGattAttributes.java deleted file mode 100644 index 255653eb..00000000 --- a/connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGatt/src/main/java/com/example/bluetooth/le/SampleGattAttributes.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.bluetooth.le; - -import java.util.HashMap; - -/** - * This class includes a small subset of standard GATT attributes for demonstration purposes. - */ -public class SampleGattAttributes { - private static HashMap attributes = new HashMap(); - public static String HEART_RATE_MEASUREMENT = "00002a37-0000-1000-8000-00805f9b34fb"; - public static String CLIENT_CHARACTERISTIC_CONFIG = "00002902-0000-1000-8000-00805f9b34fb"; - - static { - // Sample Services. - attributes.put("0000180d-0000-1000-8000-00805f9b34fb", "Heart Rate Service"); - attributes.put("0000180a-0000-1000-8000-00805f9b34fb", "Device Information Service"); - // Sample Characteristics. - attributes.put(HEART_RATE_MEASUREMENT, "Heart Rate Measurement"); - attributes.put("00002a29-0000-1000-8000-00805f9b34fb", "Manufacturer Name String"); - } - - public static String lookup(String uuid, String defaultName) { - String name = attributes.get(uuid); - return name == null ? defaultName : name; - } -} diff --git a/connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGatt/src/main/res/drawable-hdpi/ic_launcher.png b/connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGatt/src/main/res/drawable-hdpi/ic_launcher.png deleted file mode 100755 index 15367c05..00000000 Binary files a/connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGatt/src/main/res/drawable-hdpi/ic_launcher.png and /dev/null differ diff --git a/connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGatt/src/main/res/drawable-mdpi/ic_launcher.png b/connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGatt/src/main/res/drawable-mdpi/ic_launcher.png deleted file mode 100755 index ba810a76..00000000 Binary files a/connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGatt/src/main/res/drawable-mdpi/ic_launcher.png and /dev/null differ diff --git a/connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGatt/src/main/res/drawable-xhdpi/ic_launcher.png b/connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGatt/src/main/res/drawable-xhdpi/ic_launcher.png deleted file mode 100755 index 14f1d746..00000000 Binary files a/connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGatt/src/main/res/drawable-xhdpi/ic_launcher.png and /dev/null differ diff --git a/connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGatt/src/main/res/drawable-xxhdpi/ic_launcher.png b/connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGatt/src/main/res/drawable-xxhdpi/ic_launcher.png deleted file mode 100755 index 81ff9cc8..00000000 Binary files a/connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGatt/src/main/res/drawable-xxhdpi/ic_launcher.png and /dev/null differ diff --git a/connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGatt/src/main/res/layout/actionbar_indeterminate_progress.xml b/connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGatt/src/main/res/layout/actionbar_indeterminate_progress.xml deleted file mode 100644 index a950833f..00000000 --- a/connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGatt/src/main/res/layout/actionbar_indeterminate_progress.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - diff --git a/connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGatt/src/main/res/layout/gatt_services_characteristics.xml b/connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGatt/src/main/res/layout/gatt_services_characteristics.xml deleted file mode 100644 index 2f310610..00000000 --- a/connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGatt/src/main/res/layout/gatt_services_characteristics.xml +++ /dev/null @@ -1,71 +0,0 @@ - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGatt/src/main/res/layout/listitem_device.xml b/connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGatt/src/main/res/layout/listitem_device.xml deleted file mode 100644 index eff44fcd..00000000 --- a/connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGatt/src/main/res/layout/listitem_device.xml +++ /dev/null @@ -1,28 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGatt/src/main/res/menu/gatt_services.xml b/connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGatt/src/main/res/menu/gatt_services.xml deleted file mode 100644 index 464d32ff..00000000 --- a/connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGatt/src/main/res/menu/gatt_services.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - diff --git a/connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGatt/src/main/res/menu/main.xml b/connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGatt/src/main/res/menu/main.xml deleted file mode 100644 index 39dd66aa..00000000 --- a/connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGatt/src/main/res/menu/main.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - diff --git a/connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGatt/src/main/res/values/strings.xml b/connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGatt/src/main/res/values/strings.xml deleted file mode 100644 index d828aa01..00000000 --- a/connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGatt/src/main/res/values/strings.xml +++ /dev/null @@ -1,37 +0,0 @@ - - - - BLE Sample - BLE is not supported - Data: - Device address: - State: - No data - Connected - Disconnected - BLE Device Scan - Bluetooth not supported. - - Unknown device - Unknown characteristic - Unknown service - - - Connect - Disconnect - Scan - Stop - diff --git a/connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGattSample/.gitignore b/connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGattSample/.gitignore new file mode 100644 index 00000000..6eb878d4 --- /dev/null +++ b/connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGattSample/.gitignore @@ -0,0 +1,16 @@ +# Copyright 2013 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +src/template/ +src/common/ +build.gradle diff --git a/connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGattSample/proguard-project.txt b/connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGattSample/proguard-project.txt new file mode 100644 index 00000000..0d8f171d --- /dev/null +++ b/connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGattSample/proguard-project.txt @@ -0,0 +1,20 @@ + To enable ProGuard in your project, edit project.properties +# to define the proguard.config property as described in that file. +# +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in ${sdk.dir}/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the ProGuard +# include property in project.properties. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} diff --git a/connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGattSample/src/main/AndroidManifest.xml b/connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGattSample/src/main/AndroidManifest.xml new file mode 100644 index 00000000..babd6df2 --- /dev/null +++ b/connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGattSample/src/main/AndroidManifest.xml @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGattSample/src/main/java/com/example/android/bluetoothlegatt/BluetoothLeService.java b/connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGattSample/src/main/java/com/example/android/bluetoothlegatt/BluetoothLeService.java new file mode 100644 index 00000000..694faaf9 --- /dev/null +++ b/connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGattSample/src/main/java/com/example/android/bluetoothlegatt/BluetoothLeService.java @@ -0,0 +1,319 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.android.bluetoothlegatt; + +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.util.Log; + +import java.util.List; +import java.util.UUID; + +/** + * Service for managing connection and data communication with a GATT server hosted on a + * given Bluetooth LE device. + */ +public class BluetoothLeService extends Service { + private final static String TAG = BluetoothLeService.class.getSimpleName(); + + private BluetoothManager mBluetoothManager; + private BluetoothAdapter mBluetoothAdapter; + private String mBluetoothDeviceAddress; + private BluetoothGatt mBluetoothGatt; + private int mConnectionState = STATE_DISCONNECTED; + + private static final int STATE_DISCONNECTED = 0; + private static final int STATE_CONNECTING = 1; + private static final int STATE_CONNECTED = 2; + + public final static String ACTION_GATT_CONNECTED = + "com.example.bluetooth.le.ACTION_GATT_CONNECTED"; + public final static String ACTION_GATT_DISCONNECTED = + "com.example.bluetooth.le.ACTION_GATT_DISCONNECTED"; + public final static String ACTION_GATT_SERVICES_DISCOVERED = + "com.example.bluetooth.le.ACTION_GATT_SERVICES_DISCOVERED"; + public final static String ACTION_DATA_AVAILABLE = + "com.example.bluetooth.le.ACTION_DATA_AVAILABLE"; + public final static String EXTRA_DATA = + "com.example.bluetooth.le.EXTRA_DATA"; + + public final static UUID UUID_HEART_RATE_MEASUREMENT = + UUID.fromString(SampleGattAttributes.HEART_RATE_MEASUREMENT); + + // Implements callback methods for GATT events that the app cares about. For example, + // connection change and services discovered. + private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() { + @Override + public 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 discover services after 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 + public void onServicesDiscovered(BluetoothGatt gatt, int status) { + if (status == BluetoothGatt.GATT_SUCCESS) { + broadcastUpdate(ACTION_GATT_SERVICES_DISCOVERED); + } else { + Log.w(TAG, "onServicesDiscovered received: " + status); + } + } + + @Override + public void onCharacteristicRead(BluetoothGatt gatt, + BluetoothGattCharacteristic characteristic, + int status) { + if (status == BluetoothGatt.GATT_SUCCESS) { + broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic); + } + } + + @Override + public void onCharacteristicChanged(BluetoothGatt gatt, + BluetoothGattCharacteristic characteristic) { + broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic); + } + }; + + private void broadcastUpdate(final String action) { + final Intent intent = new Intent(action); + sendBroadcast(intent); + } + + private void broadcastUpdate(final String action, + final BluetoothGattCharacteristic characteristic) { + final Intent intent = new Intent(action); + + // This is special handling for the Heart Rate Measurement profile. Data parsing is + // carried out as 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 rate format UINT16."); + } else { + format = BluetoothGattCharacteristic.FORMAT_UINT8; + Log.d(TAG, "Heart rate format UINT8."); + } + final int heartRate = characteristic.getIntValue(format, 1); + Log.d(TAG, String.format("Received heart rate: %d", heartRate)); + intent.putExtra(EXTRA_DATA, String.valueOf(heartRate)); + } else { + // For all other profiles, writes the data formatted in HEX. + final byte[] data = characteristic.getValue(); + if (data != null && data.length > 0) { + final StringBuilder stringBuilder = new StringBuilder(data.length); + for(byte byteChar : data) + stringBuilder.append(String.format("%02X ", byteChar)); + intent.putExtra(EXTRA_DATA, new String(data) + "\n" + stringBuilder.toString()); + } + } + sendBroadcast(intent); + } + + public class LocalBinder extends Binder { + BluetoothLeService getService() { + return BluetoothLeService.this; + } + } + + @Override + public IBinder onBind(Intent intent) { + return mBinder; + } + + @Override + public boolean onUnbind(Intent intent) { + // After using a given device, you should make sure that BluetoothGatt.close() is called + // such that resources are cleaned up properly. In this particular example, close() is + // invoked when the UI is disconnected from the Service. + close(); + return super.onUnbind(intent); + } + + private final IBinder mBinder = new LocalBinder(); + + /** + * Initializes a reference to the local Bluetooth adapter. + * + * @return Return true if the initialization is successful. + */ + public boolean initialize() { + // For API level 18 and above, get 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."); + return false; + } + } + + mBluetoothAdapter = mBluetoothManager.getAdapter(); + if (mBluetoothAdapter == null) { + Log.e(TAG, "Unable to obtain a BluetoothAdapter."); + return false; + } + + return true; + } + + /** + * Connects to the GATT server hosted on the Bluetooth LE device. + * + * @param address The device address of the destination device. + * + * @return Return true if the connection is initiated successfully. The connection result + * is reported asynchronously through the + * {@code BluetoothGattCallback#onConnectionStateChange(android.bluetooth.BluetoothGatt, int, int)} + * callback. + */ + public boolean connect(final String address) { + if (mBluetoothAdapter == null || address == null) { + Log.w(TAG, "BluetoothAdapter not initialized or unspecified address."); + return false; + } + + // Previously connected device. Try to reconnect. + if (mBluetoothDeviceAddress != null && address.equals(mBluetoothDeviceAddress) + && mBluetoothGatt != null) { + Log.d(TAG, "Trying to use an existing mBluetoothGatt for connection."); + if (mBluetoothGatt.connect()) { + mConnectionState = STATE_CONNECTING; + return true; + } else { + return false; + } + } + + final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address); + if (device == null) { + Log.w(TAG, "Device not found. Unable to connect."); + return false; + } + // We want to directly connect to the device, so we are setting the autoConnect + // parameter to false. + mBluetoothGatt = device.connectGatt(this, false, mGattCallback); + Log.d(TAG, "Trying to create a new connection."); + mBluetoothDeviceAddress = address; + mConnectionState = STATE_CONNECTING; + return true; + } + + /** + * Disconnects an existing connection or cancel a pending connection. The disconnection result + * is reported asynchronously through the + * {@code BluetoothGattCallback#onConnectionStateChange(android.bluetooth.BluetoothGatt, int, int)} + * callback. + */ + public void disconnect() { + if (mBluetoothAdapter == null || mBluetoothGatt == null) { + Log.w(TAG, "BluetoothAdapter not initialized"); + return; + } + mBluetoothGatt.disconnect(); + } + + /** + * After using a given BLE device, the app must call this method to ensure resources are + * released properly. + */ + public void close() { + if (mBluetoothGatt == null) { + return; + } + mBluetoothGatt.close(); + mBluetoothGatt = null; + } + + /** + * Request a read on a given {@code BluetoothGattCharacteristic}. The read result is reported + * asynchronously through the {@code BluetoothGattCallback#onCharacteristicRead(android.bluetooth.BluetoothGatt, android.bluetooth.BluetoothGattCharacteristic, int)} + * callback. + * + * @param characteristic The characteristic to read from. + */ + public void readCharacteristic(BluetoothGattCharacteristic characteristic) { + if (mBluetoothAdapter == null || mBluetoothGatt == null) { + Log.w(TAG, "BluetoothAdapter not initialized"); + return; + } + mBluetoothGatt.readCharacteristic(characteristic); + } + + /** + * Enables or disables notification on a give characteristic. + * + * @param characteristic Characteristic to act on. + * @param enabled If true, enable notification. False otherwise. + */ + public void setCharacteristicNotification(BluetoothGattCharacteristic characteristic, + boolean enabled) { + if (mBluetoothAdapter == null || mBluetoothGatt == null) { + Log.w(TAG, "BluetoothAdapter not initialized"); + return; + } + mBluetoothGatt.setCharacteristicNotification(characteristic, enabled); + + // This is specific to Heart Rate Measurement. + if (UUID_HEART_RATE_MEASUREMENT.equals(characteristic.getUuid())) { + BluetoothGattDescriptor descriptor = characteristic.getDescriptor( + UUID.fromString(SampleGattAttributes.CLIENT_CHARACTERISTIC_CONFIG)); + descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE); + mBluetoothGatt.writeDescriptor(descriptor); + } + } + + /** + * Retrieves a list of supported GATT services on the connected device. This should be + * invoked only after {@code BluetoothGatt#discoverServices()} completes successfully. + * + * @return A {@code List} of supported services. + */ + public List getSupportedGattServices() { + if (mBluetoothGatt == null) return null; + + return mBluetoothGatt.getServices(); + } +} diff --git a/connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGattSample/src/main/java/com/example/android/bluetoothlegatt/DeviceControlActivity.java b/connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGattSample/src/main/java/com/example/android/bluetoothlegatt/DeviceControlActivity.java new file mode 100644 index 00000000..dc2f90bd --- /dev/null +++ b/connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGattSample/src/main/java/com/example/android/bluetoothlegatt/DeviceControlActivity.java @@ -0,0 +1,309 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.android.bluetoothlegatt; + +import android.app.Activity; +import android.bluetooth.BluetoothGattCharacteristic; +import android.bluetooth.BluetoothGattService; +import android.content.BroadcastReceiver; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.ServiceConnection; +import android.os.Bundle; +import android.os.IBinder; +import android.util.Log; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.widget.ExpandableListView; +import android.widget.SimpleExpandableListAdapter; +import android.widget.TextView; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +/** + * For a given BLE device, this Activity provides the user interface to connect, display data, + * and display GATT services and characteristics supported by the device. The Activity + * communicates with {@code BluetoothLeService}, which in turn interacts with the + * Bluetooth LE API. + */ +public class DeviceControlActivity extends Activity { + private final static String TAG = DeviceControlActivity.class.getSimpleName(); + + public static final String EXTRAS_DEVICE_NAME = "DEVICE_NAME"; + public static final String EXTRAS_DEVICE_ADDRESS = "DEVICE_ADDRESS"; + + private TextView mConnectionState; + private TextView mDataField; + private String mDeviceName; + private String mDeviceAddress; + private ExpandableListView mGattServicesList; + private BluetoothLeService mBluetoothLeService; + private ArrayList> mGattCharacteristics = + new ArrayList>(); + private boolean mConnected = false; + private BluetoothGattCharacteristic mNotifyCharacteristic; + + private final String LIST_NAME = "NAME"; + private final String LIST_UUID = "UUID"; + + // Code to manage Service lifecycle. + private final ServiceConnection mServiceConnection = new ServiceConnection() { + + @Override + public void onServiceConnected(ComponentName componentName, IBinder service) { + mBluetoothLeService = ((BluetoothLeService.LocalBinder) service).getService(); + if (!mBluetoothLeService.initialize()) { + Log.e(TAG, "Unable to initialize Bluetooth"); + finish(); + } + // Automatically connects to the device upon successful start-up initialization. + mBluetoothLeService.connect(mDeviceAddress); + } + + @Override + public void onServiceDisconnected(ComponentName componentName) { + mBluetoothLeService = null; + } + }; + + // Handles various events fired by the Service. + // ACTION_GATT_CONNECTED: connected to a GATT server. + // ACTION_GATT_DISCONNECTED: disconnected from a GATT server. + // ACTION_GATT_SERVICES_DISCOVERED: discovered GATT services. + // ACTION_DATA_AVAILABLE: received data from the device. This can be a result of read + // or notification operations. + private final BroadcastReceiver mGattUpdateReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + final String action = intent.getAction(); + if (BluetoothLeService.ACTION_GATT_CONNECTED.equals(action)) { + mConnected = true; + updateConnectionState(R.string.connected); + invalidateOptionsMenu(); + } else if (BluetoothLeService.ACTION_GATT_DISCONNECTED.equals(action)) { + mConnected = false; + updateConnectionState(R.string.disconnected); + invalidateOptionsMenu(); + clearUI(); + } else if (BluetoothLeService.ACTION_GATT_SERVICES_DISCOVERED.equals(action)) { + // Show all the supported services and characteristics on the user interface. + displayGattServices(mBluetoothLeService.getSupportedGattServices()); + } else if (BluetoothLeService.ACTION_DATA_AVAILABLE.equals(action)) { + displayData(intent.getStringExtra(BluetoothLeService.EXTRA_DATA)); + } + } + }; + + // If a given GATT characteristic is selected, check for supported features. This sample + // demonstrates 'Read' and 'Notify' features. See + // http://d.android.com/reference/android/bluetooth/BluetoothGatt.html for the complete + // list of supported characteristic features. + private final ExpandableListView.OnChildClickListener servicesListClickListner = + new ExpandableListView.OnChildClickListener() { + @Override + public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, + int childPosition, long id) { + if (mGattCharacteristics != null) { + final BluetoothGattCharacteristic characteristic = + mGattCharacteristics.get(groupPosition).get(childPosition); + final int charaProp = characteristic.getProperties(); + if ((charaProp | BluetoothGattCharacteristic.PROPERTY_READ) > 0) { + // If there is an active notification on a characteristic, clear + // it first so it doesn't update the data field on the user interface. + if (mNotifyCharacteristic != null) { + mBluetoothLeService.setCharacteristicNotification( + mNotifyCharacteristic, false); + mNotifyCharacteristic = null; + } + mBluetoothLeService.readCharacteristic(characteristic); + } + if ((charaProp | BluetoothGattCharacteristic.PROPERTY_NOTIFY) > 0) { + mNotifyCharacteristic = characteristic; + mBluetoothLeService.setCharacteristicNotification( + characteristic, true); + } + return true; + } + return false; + } + }; + + private void clearUI() { + mGattServicesList.setAdapter((SimpleExpandableListAdapter) null); + mDataField.setText(R.string.no_data); + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.gatt_services_characteristics); + + final Intent intent = getIntent(); + mDeviceName = intent.getStringExtra(EXTRAS_DEVICE_NAME); + mDeviceAddress = intent.getStringExtra(EXTRAS_DEVICE_ADDRESS); + + // Sets up UI references. + ((TextView) findViewById(R.id.device_address)).setText(mDeviceAddress); + mGattServicesList = (ExpandableListView) findViewById(R.id.gatt_services_list); + mGattServicesList.setOnChildClickListener(servicesListClickListner); + mConnectionState = (TextView) findViewById(R.id.connection_state); + mDataField = (TextView) findViewById(R.id.data_value); + + getActionBar().setTitle(mDeviceName); + getActionBar().setDisplayHomeAsUpEnabled(true); + Intent gattServiceIntent = new Intent(this, BluetoothLeService.class); + bindService(gattServiceIntent, mServiceConnection, BIND_AUTO_CREATE); + } + + @Override + protected void onResume() { + super.onResume(); + registerReceiver(mGattUpdateReceiver, makeGattUpdateIntentFilter()); + if (mBluetoothLeService != null) { + final boolean result = mBluetoothLeService.connect(mDeviceAddress); + Log.d(TAG, "Connect request result=" + result); + } + } + + @Override + protected void onPause() { + super.onPause(); + unregisterReceiver(mGattUpdateReceiver); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + unbindService(mServiceConnection); + mBluetoothLeService = null; + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + getMenuInflater().inflate(R.menu.gatt_services, menu); + if (mConnected) { + menu.findItem(R.id.menu_connect).setVisible(false); + menu.findItem(R.id.menu_disconnect).setVisible(true); + } else { + menu.findItem(R.id.menu_connect).setVisible(true); + menu.findItem(R.id.menu_disconnect).setVisible(false); + } + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch(item.getItemId()) { + case R.id.menu_connect: + mBluetoothLeService.connect(mDeviceAddress); + return true; + case R.id.menu_disconnect: + mBluetoothLeService.disconnect(); + return true; + case android.R.id.home: + onBackPressed(); + return true; + } + return super.onOptionsItemSelected(item); + } + + private void updateConnectionState(final int resourceId) { + runOnUiThread(new Runnable() { + @Override + public void run() { + mConnectionState.setText(resourceId); + } + }); + } + + private void displayData(String data) { + if (data != null) { + mDataField.setText(data); + } + } + + // Demonstrates how to iterate through the supported GATT Services/Characteristics. + // In this sample, we populate the data structure that is bound to the ExpandableListView + // on the UI. + private void displayGattServices(List gattServices) { + if (gattServices == null) return; + String uuid = null; + String unknownServiceString = getResources().getString(R.string.unknown_service); + String unknownCharaString = getResources().getString(R.string.unknown_characteristic); + ArrayList> gattServiceData = new ArrayList>(); + ArrayList>> gattCharacteristicData + = new ArrayList>>(); + mGattCharacteristics = new ArrayList>(); + + // Loops through available GATT Services. + for (BluetoothGattService gattService : gattServices) { + HashMap currentServiceData = new HashMap(); + uuid = gattService.getUuid().toString(); + currentServiceData.put( + LIST_NAME, SampleGattAttributes.lookup(uuid, unknownServiceString)); + currentServiceData.put(LIST_UUID, uuid); + gattServiceData.add(currentServiceData); + + ArrayList> gattCharacteristicGroupData = + new ArrayList>(); + List gattCharacteristics = + gattService.getCharacteristics(); + ArrayList charas = + new ArrayList(); + + // Loops through available Characteristics. + for (BluetoothGattCharacteristic gattCharacteristic : gattCharacteristics) { + charas.add(gattCharacteristic); + HashMap currentCharaData = new HashMap(); + uuid = gattCharacteristic.getUuid().toString(); + currentCharaData.put( + LIST_NAME, SampleGattAttributes.lookup(uuid, unknownCharaString)); + currentCharaData.put(LIST_UUID, uuid); + gattCharacteristicGroupData.add(currentCharaData); + } + mGattCharacteristics.add(charas); + gattCharacteristicData.add(gattCharacteristicGroupData); + } + + SimpleExpandableListAdapter gattServiceAdapter = new SimpleExpandableListAdapter( + this, + gattServiceData, + android.R.layout.simple_expandable_list_item_2, + new String[] {LIST_NAME, LIST_UUID}, + new int[] { android.R.id.text1, android.R.id.text2 }, + gattCharacteristicData, + android.R.layout.simple_expandable_list_item_2, + new String[] {LIST_NAME, LIST_UUID}, + new int[] { android.R.id.text1, android.R.id.text2 } + ); + mGattServicesList.setAdapter(gattServiceAdapter); + } + + private static IntentFilter makeGattUpdateIntentFilter() { + final IntentFilter intentFilter = new IntentFilter(); + intentFilter.addAction(BluetoothLeService.ACTION_GATT_CONNECTED); + intentFilter.addAction(BluetoothLeService.ACTION_GATT_DISCONNECTED); + intentFilter.addAction(BluetoothLeService.ACTION_GATT_SERVICES_DISCOVERED); + intentFilter.addAction(BluetoothLeService.ACTION_DATA_AVAILABLE); + return intentFilter; + } +} diff --git a/connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGattSample/src/main/java/com/example/android/bluetoothlegatt/DeviceScanActivity.java b/connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGattSample/src/main/java/com/example/android/bluetoothlegatt/DeviceScanActivity.java new file mode 100644 index 00000000..9b86f7ab --- /dev/null +++ b/connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGattSample/src/main/java/com/example/android/bluetoothlegatt/DeviceScanActivity.java @@ -0,0 +1,268 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.android.bluetoothlegatt; + +import android.app.Activity; +import android.app.ListActivity; +import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothManager; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.os.Bundle; +import android.os.Handler; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; +import android.widget.BaseAdapter; +import android.widget.ListView; +import android.widget.TextView; +import android.widget.Toast; + +import java.util.ArrayList; + +/** + * Activity for scanning and displaying available Bluetooth LE devices. + */ +public class DeviceScanActivity extends ListActivity { + private LeDeviceListAdapter mLeDeviceListAdapter; + private BluetoothAdapter mBluetoothAdapter; + private boolean mScanning; + private Handler mHandler; + + private static final int REQUEST_ENABLE_BT = 1; + // Stops scanning after 10 seconds. + private static final long SCAN_PERIOD = 10000; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + getActionBar().setTitle(R.string.title_devices); + mHandler = new Handler(); + + // Use this check to determine whether BLE is supported on the device. Then you can + // selectively disable BLE-related features. + if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) { + Toast.makeText(this, R.string.ble_not_supported, Toast.LENGTH_SHORT).show(); + finish(); + } + + // Initializes a Bluetooth adapter. For API level 18 and above, get a reference to + // BluetoothAdapter through BluetoothManager. + final BluetoothManager bluetoothManager = + (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE); + mBluetoothAdapter = bluetoothManager.getAdapter(); + + // Checks if Bluetooth is supported on the device. + if (mBluetoothAdapter == null) { + Toast.makeText(this, R.string.error_bluetooth_not_supported, Toast.LENGTH_SHORT).show(); + finish(); + return; + } + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + getMenuInflater().inflate(R.menu.main, menu); + if (!mScanning) { + menu.findItem(R.id.menu_stop).setVisible(false); + menu.findItem(R.id.menu_scan).setVisible(true); + menu.findItem(R.id.menu_refresh).setActionView(null); + } else { + menu.findItem(R.id.menu_stop).setVisible(true); + menu.findItem(R.id.menu_scan).setVisible(false); + menu.findItem(R.id.menu_refresh).setActionView( + R.layout.actionbar_indeterminate_progress); + } + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case R.id.menu_scan: + mLeDeviceListAdapter.clear(); + scanLeDevice(true); + break; + case R.id.menu_stop: + scanLeDevice(false); + break; + } + return true; + } + + @Override + protected void onResume() { + super.onResume(); + + // Ensures Bluetooth is enabled on the device. If Bluetooth is not currently enabled, + // fire an intent to display a dialog asking the user to grant permission to enable it. + if (!mBluetoothAdapter.isEnabled()) { + if (!mBluetoothAdapter.isEnabled()) { + Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); + startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT); + } + } + + // Initializes list view adapter. + mLeDeviceListAdapter = new LeDeviceListAdapter(); + setListAdapter(mLeDeviceListAdapter); + scanLeDevice(true); + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + // User chose not to enable Bluetooth. + if (requestCode == REQUEST_ENABLE_BT && resultCode == Activity.RESULT_CANCELED) { + finish(); + return; + } + super.onActivityResult(requestCode, resultCode, data); + } + + @Override + protected void onPause() { + super.onPause(); + scanLeDevice(false); + mLeDeviceListAdapter.clear(); + } + + @Override + protected void onListItemClick(ListView l, View v, int position, long id) { + final BluetoothDevice device = mLeDeviceListAdapter.getDevice(position); + if (device == null) return; + final Intent intent = new Intent(this, DeviceControlActivity.class); + intent.putExtra(DeviceControlActivity.EXTRAS_DEVICE_NAME, device.getName()); + intent.putExtra(DeviceControlActivity.EXTRAS_DEVICE_ADDRESS, device.getAddress()); + if (mScanning) { + mBluetoothAdapter.stopLeScan(mLeScanCallback); + mScanning = false; + } + startActivity(intent); + } + + private void scanLeDevice(final boolean enable) { + if (enable) { + // Stops scanning after a pre-defined scan period. + mHandler.postDelayed(new Runnable() { + @Override + public void run() { + mScanning = false; + mBluetoothAdapter.stopLeScan(mLeScanCallback); + invalidateOptionsMenu(); + } + }, SCAN_PERIOD); + + mScanning = true; + mBluetoothAdapter.startLeScan(mLeScanCallback); + } else { + mScanning = false; + mBluetoothAdapter.stopLeScan(mLeScanCallback); + } + invalidateOptionsMenu(); + } + + // Adapter for holding devices found through scanning. + private class LeDeviceListAdapter extends BaseAdapter { + private ArrayList mLeDevices; + private LayoutInflater mInflator; + + public LeDeviceListAdapter() { + super(); + mLeDevices = new ArrayList(); + mInflator = DeviceScanActivity.this.getLayoutInflater(); + } + + public void addDevice(BluetoothDevice device) { + if(!mLeDevices.contains(device)) { + mLeDevices.add(device); + } + } + + public BluetoothDevice getDevice(int position) { + return mLeDevices.get(position); + } + + public void clear() { + mLeDevices.clear(); + } + + @Override + public int getCount() { + return mLeDevices.size(); + } + + @Override + public Object getItem(int i) { + return mLeDevices.get(i); + } + + @Override + public long getItemId(int i) { + return i; + } + + @Override + public View getView(int i, View view, ViewGroup viewGroup) { + ViewHolder viewHolder; + // General ListView optimization code. + if (view == null) { + view = mInflator.inflate(R.layout.listitem_device, null); + viewHolder = new ViewHolder(); + viewHolder.deviceAddress = (TextView) view.findViewById(R.id.device_address); + viewHolder.deviceName = (TextView) view.findViewById(R.id.device_name); + view.setTag(viewHolder); + } else { + viewHolder = (ViewHolder) view.getTag(); + } + + BluetoothDevice device = mLeDevices.get(i); + final String deviceName = device.getName(); + if (deviceName != null && deviceName.length() > 0) + viewHolder.deviceName.setText(deviceName); + else + viewHolder.deviceName.setText(R.string.unknown_device); + viewHolder.deviceAddress.setText(device.getAddress()); + + return view; + } + } + + // Device scan callback. + private BluetoothAdapter.LeScanCallback mLeScanCallback = + new BluetoothAdapter.LeScanCallback() { + + @Override + public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) { + runOnUiThread(new Runnable() { + @Override + public void run() { + mLeDeviceListAdapter.addDevice(device); + mLeDeviceListAdapter.notifyDataSetChanged(); + } + }); + } + }; + + static class ViewHolder { + TextView deviceName; + TextView deviceAddress; + } +} \ No newline at end of file diff --git a/connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGattSample/src/main/java/com/example/android/bluetoothlegatt/SampleGattAttributes.java b/connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGattSample/src/main/java/com/example/android/bluetoothlegatt/SampleGattAttributes.java new file mode 100644 index 00000000..e8db74cd --- /dev/null +++ b/connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGattSample/src/main/java/com/example/android/bluetoothlegatt/SampleGattAttributes.java @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.android.bluetoothlegatt; + +import java.util.HashMap; + +/** + * This class includes a small subset of standard GATT attributes for demonstration purposes. + */ +public class SampleGattAttributes { + private static HashMap attributes = new HashMap(); + public static String HEART_RATE_MEASUREMENT = "00002a37-0000-1000-8000-00805f9b34fb"; + public static String CLIENT_CHARACTERISTIC_CONFIG = "00002902-0000-1000-8000-00805f9b34fb"; + + static { + // Sample Services. + attributes.put("0000180d-0000-1000-8000-00805f9b34fb", "Heart Rate Service"); + attributes.put("0000180a-0000-1000-8000-00805f9b34fb", "Device Information Service"); + // Sample Characteristics. + attributes.put(HEART_RATE_MEASUREMENT, "Heart Rate Measurement"); + attributes.put("00002a29-0000-1000-8000-00805f9b34fb", "Manufacturer Name String"); + } + + public static String lookup(String uuid, String defaultName) { + String name = attributes.get(uuid); + return name == null ? defaultName : name; + } +} diff --git a/connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGattSample/src/main/res/drawable-hdpi/ic_launcher.png b/connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGattSample/src/main/res/drawable-hdpi/ic_launcher.png new file mode 100755 index 00000000..15367c05 Binary files /dev/null and b/connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGattSample/src/main/res/drawable-hdpi/ic_launcher.png differ diff --git a/connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGattSample/src/main/res/drawable-mdpi/ic_launcher.png b/connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGattSample/src/main/res/drawable-mdpi/ic_launcher.png new file mode 100755 index 00000000..ba810a76 Binary files /dev/null and b/connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGattSample/src/main/res/drawable-mdpi/ic_launcher.png differ diff --git a/connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGattSample/src/main/res/drawable-xhdpi/ic_launcher.png b/connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGattSample/src/main/res/drawable-xhdpi/ic_launcher.png new file mode 100755 index 00000000..14f1d746 Binary files /dev/null and b/connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGattSample/src/main/res/drawable-xhdpi/ic_launcher.png differ diff --git a/connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGattSample/src/main/res/drawable-xxhdpi/ic_launcher.png b/connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGattSample/src/main/res/drawable-xxhdpi/ic_launcher.png new file mode 100755 index 00000000..81ff9cc8 Binary files /dev/null and b/connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGattSample/src/main/res/drawable-xxhdpi/ic_launcher.png differ diff --git a/connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGattSample/src/main/res/layout/actionbar_indeterminate_progress.xml b/connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGattSample/src/main/res/layout/actionbar_indeterminate_progress.xml new file mode 100644 index 00000000..a950833f --- /dev/null +++ b/connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGattSample/src/main/res/layout/actionbar_indeterminate_progress.xml @@ -0,0 +1,23 @@ + + + + diff --git a/connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGattSample/src/main/res/layout/gatt_services_characteristics.xml b/connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGattSample/src/main/res/layout/gatt_services_characteristics.xml new file mode 100644 index 00000000..2f310610 --- /dev/null +++ b/connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGattSample/src/main/res/layout/gatt_services_characteristics.xml @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGattSample/src/main/res/layout/listitem_device.xml b/connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGattSample/src/main/res/layout/listitem_device.xml new file mode 100644 index 00000000..eff44fcd --- /dev/null +++ b/connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGattSample/src/main/res/layout/listitem_device.xml @@ -0,0 +1,28 @@ + + + + + + \ No newline at end of file diff --git a/connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGattSample/src/main/res/menu/gatt_services.xml b/connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGattSample/src/main/res/menu/gatt_services.xml new file mode 100644 index 00000000..464d32ff --- /dev/null +++ b/connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGattSample/src/main/res/menu/gatt_services.xml @@ -0,0 +1,29 @@ + + + + + + + diff --git a/connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGattSample/src/main/res/menu/main.xml b/connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGattSample/src/main/res/menu/main.xml new file mode 100644 index 00000000..39dd66aa --- /dev/null +++ b/connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGattSample/src/main/res/menu/main.xml @@ -0,0 +1,29 @@ + + + + + + + diff --git a/connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGattSample/src/main/res/values/strings.xml b/connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGattSample/src/main/res/values/strings.xml new file mode 100644 index 00000000..19f3dce9 --- /dev/null +++ b/connectivity/bluetooth/BluetoothLeGatt/BluetoothLeGattSample/src/main/res/values/strings.xml @@ -0,0 +1,36 @@ + + + + BLE is not supported + Data: + Device address: + State: + No data + Connected + Disconnected + BLE Device Scan + Bluetooth not supported. + + Unknown device + Unknown characteristic + Unknown service + + + Connect + Disconnect + Scan + Stop + diff --git a/connectivity/bluetooth/BluetoothLeGatt/build.gradle b/connectivity/bluetooth/BluetoothLeGatt/build.gradle index 036abc8d..cca9ac33 100644 --- a/connectivity/bluetooth/BluetoothLeGatt/build.gradle +++ b/connectivity/bluetooth/BluetoothLeGatt/build.gradle @@ -1,8 +1,10 @@ -buildscript { - repositories { - mavenCentral() - } - dependencies { - classpath 'com.android.tools.build:gradle:0.5.+' - } +// BEGIN_EXCLUDE +import com.example.android.samples.build.SampleGenPlugin +apply plugin: SampleGenPlugin + +samplegen { + pathToBuild "../../../../../build" + pathToSamplesCommon "../../../common" } +apply from: "../../../../../build/build.gradle" +// END_EXCLUDE diff --git a/connectivity/bluetooth/BluetoothLeGatt/buildSrc/build.gradle b/connectivity/bluetooth/BluetoothLeGatt/buildSrc/build.gradle new file mode 100644 index 00000000..e344a8cb --- /dev/null +++ b/connectivity/bluetooth/BluetoothLeGatt/buildSrc/build.gradle @@ -0,0 +1,18 @@ + + + +repositories { + mavenCentral() +} +dependencies { + compile 'org.freemarker:freemarker:2.3.20' +} + +sourceSets { + main { + groovy { + srcDir new File(rootDir, "../../../../../../build/buildSrc/src/main/groovy") + } + } +} + diff --git a/connectivity/bluetooth/BluetoothLeGatt/gradle/wrapper/gradle-wrapper.properties b/connectivity/bluetooth/BluetoothLeGatt/gradle/wrapper/gradle-wrapper.properties index 5c22dec0..861eddc3 100644 --- a/connectivity/bluetooth/BluetoothLeGatt/gradle/wrapper/gradle-wrapper.properties +++ b/connectivity/bluetooth/BluetoothLeGatt/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=http\://services.gradle.org/distributions/gradle-1.6-bin.zip +distributionUrl=http\://services.gradle.org/distributions/gradle-1.8-bin.zip diff --git a/connectivity/bluetooth/BluetoothLeGatt/settings.gradle b/connectivity/bluetooth/BluetoothLeGatt/settings.gradle index 639c5c89..05cae43f 100644 --- a/connectivity/bluetooth/BluetoothLeGatt/settings.gradle +++ b/connectivity/bluetooth/BluetoothLeGatt/settings.gradle @@ -1 +1,4 @@ -include ':BluetoothLeGatt' + + + +include 'BluetoothLeGattSample' diff --git a/connectivity/bluetooth/BluetoothLeGatt/template-params.xml b/connectivity/bluetooth/BluetoothLeGatt/template-params.xml new file mode 100644 index 00000000..323e1d72 --- /dev/null +++ b/connectivity/bluetooth/BluetoothLeGatt/template-params.xml @@ -0,0 +1,36 @@ + + + + BluetoothLeGatt + Connectivity + com.example.android.bluetoothlegatt + + + 18 + + + + + + + +