1*90c8c64dSAndroid Build Coastguard Worker /*
2*90c8c64dSAndroid Build Coastguard Worker  * Copyright (C) 2013 The Android Open Source Project
3*90c8c64dSAndroid Build Coastguard Worker  *
4*90c8c64dSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*90c8c64dSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*90c8c64dSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*90c8c64dSAndroid Build Coastguard Worker  *
8*90c8c64dSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*90c8c64dSAndroid Build Coastguard Worker  *
10*90c8c64dSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*90c8c64dSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*90c8c64dSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*90c8c64dSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*90c8c64dSAndroid Build Coastguard Worker  * limitations under the License.
15*90c8c64dSAndroid Build Coastguard Worker  */
16*90c8c64dSAndroid Build Coastguard Worker 
17*90c8c64dSAndroid Build Coastguard Worker package com.example.android.bluetoothlegatt;
18*90c8c64dSAndroid Build Coastguard Worker 
19*90c8c64dSAndroid Build Coastguard Worker import android.app.Activity;
20*90c8c64dSAndroid Build Coastguard Worker import android.bluetooth.BluetoothGattCharacteristic;
21*90c8c64dSAndroid Build Coastguard Worker import android.bluetooth.BluetoothGattService;
22*90c8c64dSAndroid Build Coastguard Worker import android.content.BroadcastReceiver;
23*90c8c64dSAndroid Build Coastguard Worker import android.content.ComponentName;
24*90c8c64dSAndroid Build Coastguard Worker import android.content.Context;
25*90c8c64dSAndroid Build Coastguard Worker import android.content.Intent;
26*90c8c64dSAndroid Build Coastguard Worker import android.content.IntentFilter;
27*90c8c64dSAndroid Build Coastguard Worker import android.content.ServiceConnection;
28*90c8c64dSAndroid Build Coastguard Worker import android.os.Bundle;
29*90c8c64dSAndroid Build Coastguard Worker import android.os.IBinder;
30*90c8c64dSAndroid Build Coastguard Worker import android.util.Log;
31*90c8c64dSAndroid Build Coastguard Worker import android.view.Menu;
32*90c8c64dSAndroid Build Coastguard Worker import android.view.MenuItem;
33*90c8c64dSAndroid Build Coastguard Worker import android.view.View;
34*90c8c64dSAndroid Build Coastguard Worker import android.widget.ExpandableListView;
35*90c8c64dSAndroid Build Coastguard Worker import android.widget.SimpleExpandableListAdapter;
36*90c8c64dSAndroid Build Coastguard Worker import android.widget.TextView;
37*90c8c64dSAndroid Build Coastguard Worker 
38*90c8c64dSAndroid Build Coastguard Worker import java.util.ArrayList;
39*90c8c64dSAndroid Build Coastguard Worker import java.util.HashMap;
40*90c8c64dSAndroid Build Coastguard Worker import java.util.List;
41*90c8c64dSAndroid Build Coastguard Worker 
42*90c8c64dSAndroid Build Coastguard Worker /**
43*90c8c64dSAndroid Build Coastguard Worker  * For a given BLE device, this Activity provides the user interface to connect, display data,
44*90c8c64dSAndroid Build Coastguard Worker  * and display GATT services and characteristics supported by the device.  The Activity
45*90c8c64dSAndroid Build Coastguard Worker  * communicates with {@code BluetoothLeService}, which in turn interacts with the
46*90c8c64dSAndroid Build Coastguard Worker  * Bluetooth LE API.
47*90c8c64dSAndroid Build Coastguard Worker  */
48*90c8c64dSAndroid Build Coastguard Worker public class DeviceControlActivity extends Activity {
49*90c8c64dSAndroid Build Coastguard Worker     private final static String TAG = DeviceControlActivity.class.getSimpleName();
50*90c8c64dSAndroid Build Coastguard Worker 
51*90c8c64dSAndroid Build Coastguard Worker     public static final String EXTRAS_DEVICE_NAME = "DEVICE_NAME";
52*90c8c64dSAndroid Build Coastguard Worker     public static final String EXTRAS_DEVICE_ADDRESS = "DEVICE_ADDRESS";
53*90c8c64dSAndroid Build Coastguard Worker 
54*90c8c64dSAndroid Build Coastguard Worker     private TextView mConnectionState;
55*90c8c64dSAndroid Build Coastguard Worker     private TextView mDataField;
56*90c8c64dSAndroid Build Coastguard Worker     private String mDeviceName;
57*90c8c64dSAndroid Build Coastguard Worker     private String mDeviceAddress;
58*90c8c64dSAndroid Build Coastguard Worker     private ExpandableListView mGattServicesList;
59*90c8c64dSAndroid Build Coastguard Worker     private BluetoothLeService mBluetoothLeService;
60*90c8c64dSAndroid Build Coastguard Worker     private ArrayList<ArrayList<BluetoothGattCharacteristic>> mGattCharacteristics =
61*90c8c64dSAndroid Build Coastguard Worker             new ArrayList<ArrayList<BluetoothGattCharacteristic>>();
62*90c8c64dSAndroid Build Coastguard Worker     private boolean mConnected = false;
63*90c8c64dSAndroid Build Coastguard Worker     private BluetoothGattCharacteristic mNotifyCharacteristic;
64*90c8c64dSAndroid Build Coastguard Worker 
65*90c8c64dSAndroid Build Coastguard Worker     private final String LIST_NAME = "NAME";
66*90c8c64dSAndroid Build Coastguard Worker     private final String LIST_UUID = "UUID";
67*90c8c64dSAndroid Build Coastguard Worker 
68*90c8c64dSAndroid Build Coastguard Worker     // Code to manage Service lifecycle.
69*90c8c64dSAndroid Build Coastguard Worker     private final ServiceConnection mServiceConnection = new ServiceConnection() {
70*90c8c64dSAndroid Build Coastguard Worker 
71*90c8c64dSAndroid Build Coastguard Worker         @Override
72*90c8c64dSAndroid Build Coastguard Worker         public void onServiceConnected(ComponentName componentName, IBinder service) {
73*90c8c64dSAndroid Build Coastguard Worker             mBluetoothLeService = ((BluetoothLeService.LocalBinder) service).getService();
74*90c8c64dSAndroid Build Coastguard Worker             if (!mBluetoothLeService.initialize()) {
75*90c8c64dSAndroid Build Coastguard Worker                 Log.e(TAG, "Unable to initialize Bluetooth");
76*90c8c64dSAndroid Build Coastguard Worker                 finish();
77*90c8c64dSAndroid Build Coastguard Worker             }
78*90c8c64dSAndroid Build Coastguard Worker             // Automatically connects to the device upon successful start-up initialization.
79*90c8c64dSAndroid Build Coastguard Worker             mBluetoothLeService.connect(mDeviceAddress);
80*90c8c64dSAndroid Build Coastguard Worker         }
81*90c8c64dSAndroid Build Coastguard Worker 
82*90c8c64dSAndroid Build Coastguard Worker         @Override
83*90c8c64dSAndroid Build Coastguard Worker         public void onServiceDisconnected(ComponentName componentName) {
84*90c8c64dSAndroid Build Coastguard Worker             mBluetoothLeService = null;
85*90c8c64dSAndroid Build Coastguard Worker         }
86*90c8c64dSAndroid Build Coastguard Worker     };
87*90c8c64dSAndroid Build Coastguard Worker 
88*90c8c64dSAndroid Build Coastguard Worker     // Handles various events fired by the Service.
89*90c8c64dSAndroid Build Coastguard Worker     // ACTION_GATT_CONNECTED: connected to a GATT server.
90*90c8c64dSAndroid Build Coastguard Worker     // ACTION_GATT_DISCONNECTED: disconnected from a GATT server.
91*90c8c64dSAndroid Build Coastguard Worker     // ACTION_GATT_SERVICES_DISCOVERED: discovered GATT services.
92*90c8c64dSAndroid Build Coastguard Worker     // ACTION_DATA_AVAILABLE: received data from the device.  This can be a result of read
93*90c8c64dSAndroid Build Coastguard Worker     //                        or notification operations.
94*90c8c64dSAndroid Build Coastguard Worker     private final BroadcastReceiver mGattUpdateReceiver = new BroadcastReceiver() {
95*90c8c64dSAndroid Build Coastguard Worker         @Override
96*90c8c64dSAndroid Build Coastguard Worker         public void onReceive(Context context, Intent intent) {
97*90c8c64dSAndroid Build Coastguard Worker             final String action = intent.getAction();
98*90c8c64dSAndroid Build Coastguard Worker             if (BluetoothLeService.ACTION_GATT_CONNECTED.equals(action)) {
99*90c8c64dSAndroid Build Coastguard Worker                 mConnected = true;
100*90c8c64dSAndroid Build Coastguard Worker                 updateConnectionState(R.string.connected);
101*90c8c64dSAndroid Build Coastguard Worker                 invalidateOptionsMenu();
102*90c8c64dSAndroid Build Coastguard Worker             } else if (BluetoothLeService.ACTION_GATT_DISCONNECTED.equals(action)) {
103*90c8c64dSAndroid Build Coastguard Worker                 mConnected = false;
104*90c8c64dSAndroid Build Coastguard Worker                 updateConnectionState(R.string.disconnected);
105*90c8c64dSAndroid Build Coastguard Worker                 invalidateOptionsMenu();
106*90c8c64dSAndroid Build Coastguard Worker                 clearUI();
107*90c8c64dSAndroid Build Coastguard Worker             } else if (BluetoothLeService.ACTION_GATT_SERVICES_DISCOVERED.equals(action)) {
108*90c8c64dSAndroid Build Coastguard Worker                 // Show all the supported services and characteristics on the user interface.
109*90c8c64dSAndroid Build Coastguard Worker                 displayGattServices(mBluetoothLeService.getSupportedGattServices());
110*90c8c64dSAndroid Build Coastguard Worker             } else if (BluetoothLeService.ACTION_DATA_AVAILABLE.equals(action)) {
111*90c8c64dSAndroid Build Coastguard Worker                 displayData(intent.getStringExtra(BluetoothLeService.EXTRA_DATA));
112*90c8c64dSAndroid Build Coastguard Worker             }
113*90c8c64dSAndroid Build Coastguard Worker         }
114*90c8c64dSAndroid Build Coastguard Worker     };
115*90c8c64dSAndroid Build Coastguard Worker 
116*90c8c64dSAndroid Build Coastguard Worker     // If a given GATT characteristic is selected, check for supported features.  This sample
117*90c8c64dSAndroid Build Coastguard Worker     // demonstrates 'Read' and 'Notify' features.  See
118*90c8c64dSAndroid Build Coastguard Worker     // http://d.android.com/reference/android/bluetooth/BluetoothGatt.html for the complete
119*90c8c64dSAndroid Build Coastguard Worker     // list of supported characteristic features.
120*90c8c64dSAndroid Build Coastguard Worker     private final ExpandableListView.OnChildClickListener servicesListClickListner =
121*90c8c64dSAndroid Build Coastguard Worker             new ExpandableListView.OnChildClickListener() {
122*90c8c64dSAndroid Build Coastguard Worker                 @Override
123*90c8c64dSAndroid Build Coastguard Worker                 public boolean onChildClick(ExpandableListView parent, View v, int groupPosition,
124*90c8c64dSAndroid Build Coastguard Worker                                             int childPosition, long id) {
125*90c8c64dSAndroid Build Coastguard Worker                     if (mGattCharacteristics != null) {
126*90c8c64dSAndroid Build Coastguard Worker                         final BluetoothGattCharacteristic characteristic =
127*90c8c64dSAndroid Build Coastguard Worker                                 mGattCharacteristics.get(groupPosition).get(childPosition);
128*90c8c64dSAndroid Build Coastguard Worker                         final int charaProp = characteristic.getProperties();
129*90c8c64dSAndroid Build Coastguard Worker                         if ((charaProp | BluetoothGattCharacteristic.PROPERTY_READ) > 0) {
130*90c8c64dSAndroid Build Coastguard Worker                             // If there is an active notification on a characteristic, clear
131*90c8c64dSAndroid Build Coastguard Worker                             // it first so it doesn't update the data field on the user interface.
132*90c8c64dSAndroid Build Coastguard Worker                             if (mNotifyCharacteristic != null) {
133*90c8c64dSAndroid Build Coastguard Worker                                 mBluetoothLeService.setCharacteristicNotification(
134*90c8c64dSAndroid Build Coastguard Worker                                         mNotifyCharacteristic, false);
135*90c8c64dSAndroid Build Coastguard Worker                                 mNotifyCharacteristic = null;
136*90c8c64dSAndroid Build Coastguard Worker                             }
137*90c8c64dSAndroid Build Coastguard Worker                             mBluetoothLeService.readCharacteristic(characteristic);
138*90c8c64dSAndroid Build Coastguard Worker                         }
139*90c8c64dSAndroid Build Coastguard Worker                         if ((charaProp | BluetoothGattCharacteristic.PROPERTY_NOTIFY) > 0) {
140*90c8c64dSAndroid Build Coastguard Worker                             mNotifyCharacteristic = characteristic;
141*90c8c64dSAndroid Build Coastguard Worker                             mBluetoothLeService.setCharacteristicNotification(
142*90c8c64dSAndroid Build Coastguard Worker                                     characteristic, true);
143*90c8c64dSAndroid Build Coastguard Worker                         }
144*90c8c64dSAndroid Build Coastguard Worker                         return true;
145*90c8c64dSAndroid Build Coastguard Worker                     }
146*90c8c64dSAndroid Build Coastguard Worker                     return false;
147*90c8c64dSAndroid Build Coastguard Worker                 }
148*90c8c64dSAndroid Build Coastguard Worker     };
149*90c8c64dSAndroid Build Coastguard Worker 
clearUI()150*90c8c64dSAndroid Build Coastguard Worker     private void clearUI() {
151*90c8c64dSAndroid Build Coastguard Worker         mGattServicesList.setAdapter((SimpleExpandableListAdapter) null);
152*90c8c64dSAndroid Build Coastguard Worker         mDataField.setText(R.string.no_data);
153*90c8c64dSAndroid Build Coastguard Worker     }
154*90c8c64dSAndroid Build Coastguard Worker 
155*90c8c64dSAndroid Build Coastguard Worker     @Override
onCreate(Bundle savedInstanceState)156*90c8c64dSAndroid Build Coastguard Worker     public void onCreate(Bundle savedInstanceState) {
157*90c8c64dSAndroid Build Coastguard Worker         super.onCreate(savedInstanceState);
158*90c8c64dSAndroid Build Coastguard Worker         setContentView(R.layout.gatt_services_characteristics);
159*90c8c64dSAndroid Build Coastguard Worker 
160*90c8c64dSAndroid Build Coastguard Worker         final Intent intent = getIntent();
161*90c8c64dSAndroid Build Coastguard Worker         mDeviceName = intent.getStringExtra(EXTRAS_DEVICE_NAME);
162*90c8c64dSAndroid Build Coastguard Worker         mDeviceAddress = intent.getStringExtra(EXTRAS_DEVICE_ADDRESS);
163*90c8c64dSAndroid Build Coastguard Worker 
164*90c8c64dSAndroid Build Coastguard Worker         // Sets up UI references.
165*90c8c64dSAndroid Build Coastguard Worker         ((TextView) findViewById(R.id.device_address)).setText(mDeviceAddress);
166*90c8c64dSAndroid Build Coastguard Worker         mGattServicesList = (ExpandableListView) findViewById(R.id.gatt_services_list);
167*90c8c64dSAndroid Build Coastguard Worker         mGattServicesList.setOnChildClickListener(servicesListClickListner);
168*90c8c64dSAndroid Build Coastguard Worker         mConnectionState = (TextView) findViewById(R.id.connection_state);
169*90c8c64dSAndroid Build Coastguard Worker         mDataField = (TextView) findViewById(R.id.data_value);
170*90c8c64dSAndroid Build Coastguard Worker 
171*90c8c64dSAndroid Build Coastguard Worker         getActionBar().setTitle(mDeviceName);
172*90c8c64dSAndroid Build Coastguard Worker         getActionBar().setDisplayHomeAsUpEnabled(true);
173*90c8c64dSAndroid Build Coastguard Worker         Intent gattServiceIntent = new Intent(this, BluetoothLeService.class);
174*90c8c64dSAndroid Build Coastguard Worker         bindService(gattServiceIntent, mServiceConnection, BIND_AUTO_CREATE);
175*90c8c64dSAndroid Build Coastguard Worker     }
176*90c8c64dSAndroid Build Coastguard Worker 
177*90c8c64dSAndroid Build Coastguard Worker     @Override
onResume()178*90c8c64dSAndroid Build Coastguard Worker     protected void onResume() {
179*90c8c64dSAndroid Build Coastguard Worker         super.onResume();
180*90c8c64dSAndroid Build Coastguard Worker         registerReceiver(mGattUpdateReceiver, makeGattUpdateIntentFilter());
181*90c8c64dSAndroid Build Coastguard Worker         if (mBluetoothLeService != null) {
182*90c8c64dSAndroid Build Coastguard Worker             final boolean result = mBluetoothLeService.connect(mDeviceAddress);
183*90c8c64dSAndroid Build Coastguard Worker             Log.d(TAG, "Connect request result=" + result);
184*90c8c64dSAndroid Build Coastguard Worker         }
185*90c8c64dSAndroid Build Coastguard Worker     }
186*90c8c64dSAndroid Build Coastguard Worker 
187*90c8c64dSAndroid Build Coastguard Worker     @Override
onPause()188*90c8c64dSAndroid Build Coastguard Worker     protected void onPause() {
189*90c8c64dSAndroid Build Coastguard Worker         super.onPause();
190*90c8c64dSAndroid Build Coastguard Worker         unregisterReceiver(mGattUpdateReceiver);
191*90c8c64dSAndroid Build Coastguard Worker     }
192*90c8c64dSAndroid Build Coastguard Worker 
193*90c8c64dSAndroid Build Coastguard Worker     @Override
onDestroy()194*90c8c64dSAndroid Build Coastguard Worker     protected void onDestroy() {
195*90c8c64dSAndroid Build Coastguard Worker         super.onDestroy();
196*90c8c64dSAndroid Build Coastguard Worker         unbindService(mServiceConnection);
197*90c8c64dSAndroid Build Coastguard Worker         mBluetoothLeService = null;
198*90c8c64dSAndroid Build Coastguard Worker     }
199*90c8c64dSAndroid Build Coastguard Worker 
200*90c8c64dSAndroid Build Coastguard Worker     @Override
onCreateOptionsMenu(Menu menu)201*90c8c64dSAndroid Build Coastguard Worker     public boolean onCreateOptionsMenu(Menu menu) {
202*90c8c64dSAndroid Build Coastguard Worker         getMenuInflater().inflate(R.menu.gatt_services, menu);
203*90c8c64dSAndroid Build Coastguard Worker         if (mConnected) {
204*90c8c64dSAndroid Build Coastguard Worker             menu.findItem(R.id.menu_connect).setVisible(false);
205*90c8c64dSAndroid Build Coastguard Worker             menu.findItem(R.id.menu_disconnect).setVisible(true);
206*90c8c64dSAndroid Build Coastguard Worker         } else {
207*90c8c64dSAndroid Build Coastguard Worker             menu.findItem(R.id.menu_connect).setVisible(true);
208*90c8c64dSAndroid Build Coastguard Worker             menu.findItem(R.id.menu_disconnect).setVisible(false);
209*90c8c64dSAndroid Build Coastguard Worker         }
210*90c8c64dSAndroid Build Coastguard Worker         return true;
211*90c8c64dSAndroid Build Coastguard Worker     }
212*90c8c64dSAndroid Build Coastguard Worker 
213*90c8c64dSAndroid Build Coastguard Worker     @Override
onOptionsItemSelected(MenuItem item)214*90c8c64dSAndroid Build Coastguard Worker     public boolean onOptionsItemSelected(MenuItem item) {
215*90c8c64dSAndroid Build Coastguard Worker         switch(item.getItemId()) {
216*90c8c64dSAndroid Build Coastguard Worker             case R.id.menu_connect:
217*90c8c64dSAndroid Build Coastguard Worker                 mBluetoothLeService.connect(mDeviceAddress);
218*90c8c64dSAndroid Build Coastguard Worker                 return true;
219*90c8c64dSAndroid Build Coastguard Worker             case R.id.menu_disconnect:
220*90c8c64dSAndroid Build Coastguard Worker                 mBluetoothLeService.disconnect();
221*90c8c64dSAndroid Build Coastguard Worker                 return true;
222*90c8c64dSAndroid Build Coastguard Worker             case android.R.id.home:
223*90c8c64dSAndroid Build Coastguard Worker                 onBackPressed();
224*90c8c64dSAndroid Build Coastguard Worker                 return true;
225*90c8c64dSAndroid Build Coastguard Worker         }
226*90c8c64dSAndroid Build Coastguard Worker         return super.onOptionsItemSelected(item);
227*90c8c64dSAndroid Build Coastguard Worker     }
228*90c8c64dSAndroid Build Coastguard Worker 
updateConnectionState(final int resourceId)229*90c8c64dSAndroid Build Coastguard Worker     private void updateConnectionState(final int resourceId) {
230*90c8c64dSAndroid Build Coastguard Worker         runOnUiThread(new Runnable() {
231*90c8c64dSAndroid Build Coastguard Worker             @Override
232*90c8c64dSAndroid Build Coastguard Worker             public void run() {
233*90c8c64dSAndroid Build Coastguard Worker                 mConnectionState.setText(resourceId);
234*90c8c64dSAndroid Build Coastguard Worker             }
235*90c8c64dSAndroid Build Coastguard Worker         });
236*90c8c64dSAndroid Build Coastguard Worker     }
237*90c8c64dSAndroid Build Coastguard Worker 
displayData(String data)238*90c8c64dSAndroid Build Coastguard Worker     private void displayData(String data) {
239*90c8c64dSAndroid Build Coastguard Worker         if (data != null) {
240*90c8c64dSAndroid Build Coastguard Worker             mDataField.setText(data);
241*90c8c64dSAndroid Build Coastguard Worker         }
242*90c8c64dSAndroid Build Coastguard Worker     }
243*90c8c64dSAndroid Build Coastguard Worker 
244*90c8c64dSAndroid Build Coastguard Worker     // Demonstrates how to iterate through the supported GATT Services/Characteristics.
245*90c8c64dSAndroid Build Coastguard Worker     // In this sample, we populate the data structure that is bound to the ExpandableListView
246*90c8c64dSAndroid Build Coastguard Worker     // on the UI.
displayGattServices(List<BluetoothGattService> gattServices)247*90c8c64dSAndroid Build Coastguard Worker     private void displayGattServices(List<BluetoothGattService> gattServices) {
248*90c8c64dSAndroid Build Coastguard Worker         if (gattServices == null) return;
249*90c8c64dSAndroid Build Coastguard Worker         String uuid = null;
250*90c8c64dSAndroid Build Coastguard Worker         String unknownServiceString = getResources().getString(R.string.unknown_service);
251*90c8c64dSAndroid Build Coastguard Worker         String unknownCharaString = getResources().getString(R.string.unknown_characteristic);
252*90c8c64dSAndroid Build Coastguard Worker         ArrayList<HashMap<String, String>> gattServiceData = new ArrayList<HashMap<String, String>>();
253*90c8c64dSAndroid Build Coastguard Worker         ArrayList<ArrayList<HashMap<String, String>>> gattCharacteristicData
254*90c8c64dSAndroid Build Coastguard Worker                 = new ArrayList<ArrayList<HashMap<String, String>>>();
255*90c8c64dSAndroid Build Coastguard Worker         mGattCharacteristics = new ArrayList<ArrayList<BluetoothGattCharacteristic>>();
256*90c8c64dSAndroid Build Coastguard Worker 
257*90c8c64dSAndroid Build Coastguard Worker         // Loops through available GATT Services.
258*90c8c64dSAndroid Build Coastguard Worker         for (BluetoothGattService gattService : gattServices) {
259*90c8c64dSAndroid Build Coastguard Worker             HashMap<String, String> currentServiceData = new HashMap<String, String>();
260*90c8c64dSAndroid Build Coastguard Worker             uuid = gattService.getUuid().toString();
261*90c8c64dSAndroid Build Coastguard Worker             currentServiceData.put(
262*90c8c64dSAndroid Build Coastguard Worker                     LIST_NAME, SampleGattAttributes.lookup(uuid, unknownServiceString));
263*90c8c64dSAndroid Build Coastguard Worker             currentServiceData.put(LIST_UUID, uuid);
264*90c8c64dSAndroid Build Coastguard Worker             gattServiceData.add(currentServiceData);
265*90c8c64dSAndroid Build Coastguard Worker 
266*90c8c64dSAndroid Build Coastguard Worker             ArrayList<HashMap<String, String>> gattCharacteristicGroupData =
267*90c8c64dSAndroid Build Coastguard Worker                     new ArrayList<HashMap<String, String>>();
268*90c8c64dSAndroid Build Coastguard Worker             List<BluetoothGattCharacteristic> gattCharacteristics =
269*90c8c64dSAndroid Build Coastguard Worker                     gattService.getCharacteristics();
270*90c8c64dSAndroid Build Coastguard Worker             ArrayList<BluetoothGattCharacteristic> charas =
271*90c8c64dSAndroid Build Coastguard Worker                     new ArrayList<BluetoothGattCharacteristic>();
272*90c8c64dSAndroid Build Coastguard Worker 
273*90c8c64dSAndroid Build Coastguard Worker             // Loops through available Characteristics.
274*90c8c64dSAndroid Build Coastguard Worker             for (BluetoothGattCharacteristic gattCharacteristic : gattCharacteristics) {
275*90c8c64dSAndroid Build Coastguard Worker                 charas.add(gattCharacteristic);
276*90c8c64dSAndroid Build Coastguard Worker                 HashMap<String, String> currentCharaData = new HashMap<String, String>();
277*90c8c64dSAndroid Build Coastguard Worker                 uuid = gattCharacteristic.getUuid().toString();
278*90c8c64dSAndroid Build Coastguard Worker                 currentCharaData.put(
279*90c8c64dSAndroid Build Coastguard Worker                         LIST_NAME, SampleGattAttributes.lookup(uuid, unknownCharaString));
280*90c8c64dSAndroid Build Coastguard Worker                 currentCharaData.put(LIST_UUID, uuid);
281*90c8c64dSAndroid Build Coastguard Worker                 gattCharacteristicGroupData.add(currentCharaData);
282*90c8c64dSAndroid Build Coastguard Worker             }
283*90c8c64dSAndroid Build Coastguard Worker             mGattCharacteristics.add(charas);
284*90c8c64dSAndroid Build Coastguard Worker             gattCharacteristicData.add(gattCharacteristicGroupData);
285*90c8c64dSAndroid Build Coastguard Worker         }
286*90c8c64dSAndroid Build Coastguard Worker 
287*90c8c64dSAndroid Build Coastguard Worker         SimpleExpandableListAdapter gattServiceAdapter = new SimpleExpandableListAdapter(
288*90c8c64dSAndroid Build Coastguard Worker                 this,
289*90c8c64dSAndroid Build Coastguard Worker                 gattServiceData,
290*90c8c64dSAndroid Build Coastguard Worker                 android.R.layout.simple_expandable_list_item_2,
291*90c8c64dSAndroid Build Coastguard Worker                 new String[] {LIST_NAME, LIST_UUID},
292*90c8c64dSAndroid Build Coastguard Worker                 new int[] { android.R.id.text1, android.R.id.text2 },
293*90c8c64dSAndroid Build Coastguard Worker                 gattCharacteristicData,
294*90c8c64dSAndroid Build Coastguard Worker                 android.R.layout.simple_expandable_list_item_2,
295*90c8c64dSAndroid Build Coastguard Worker                 new String[] {LIST_NAME, LIST_UUID},
296*90c8c64dSAndroid Build Coastguard Worker                 new int[] { android.R.id.text1, android.R.id.text2 }
297*90c8c64dSAndroid Build Coastguard Worker         );
298*90c8c64dSAndroid Build Coastguard Worker         mGattServicesList.setAdapter(gattServiceAdapter);
299*90c8c64dSAndroid Build Coastguard Worker     }
300*90c8c64dSAndroid Build Coastguard Worker 
makeGattUpdateIntentFilter()301*90c8c64dSAndroid Build Coastguard Worker     private static IntentFilter makeGattUpdateIntentFilter() {
302*90c8c64dSAndroid Build Coastguard Worker         final IntentFilter intentFilter = new IntentFilter();
303*90c8c64dSAndroid Build Coastguard Worker         intentFilter.addAction(BluetoothLeService.ACTION_GATT_CONNECTED);
304*90c8c64dSAndroid Build Coastguard Worker         intentFilter.addAction(BluetoothLeService.ACTION_GATT_DISCONNECTED);
305*90c8c64dSAndroid Build Coastguard Worker         intentFilter.addAction(BluetoothLeService.ACTION_GATT_SERVICES_DISCOVERED);
306*90c8c64dSAndroid Build Coastguard Worker         intentFilter.addAction(BluetoothLeService.ACTION_DATA_AVAILABLE);
307*90c8c64dSAndroid Build Coastguard Worker         return intentFilter;
308*90c8c64dSAndroid Build Coastguard Worker     }
309*90c8c64dSAndroid Build Coastguard Worker }
310