package cc.zachary.bluetoothlowenergy; import android.bluetooth.BluetoothGattCharacteristic; import android.bluetooth.BluetoothGattService; import android.content.ComponentName; import android.content.Intent; import android.content.ServiceConnection; import android.os.Bundle; import android.os.IBinder; import android.support.annotation.StringRes; import android.support.v7.app.AppCompatActivity; 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 org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.Subscribe; import org.greenrobot.eventbus.ThreadMode; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; /** * 设备控制页面 * Created by Zachary on 2016/2/17. */ public class DeviceControlActivity extends AppCompatActivity implements ExpandableListView.OnChildClickListener { public static final String BLE_DEVICE_NAME = "bluetoothLeName"; public static final String BLE_DEVICE_ADDRESS = "bluetoothLeAddress"; private boolean connecting = false; private TextView mDeviceAddress; private TextView mDeviceStatus; private TextView mDeviceData; private ExpandableListView mDeviceService; private BluetoothDeviceService mBluetoothService; private ServiceConnection mBluetoothServiceConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { mBluetoothService = ((BluetoothDeviceService.LocalBinder) service).getService(); if (!mBluetoothService.initialize()) { LogUtil.d("无法初始化蓝牙"); finish(); } //初始化成功后连接设备 mBluetoothService.connect(mBluetoothAddress); } @Override public void onServiceDisconnected(ComponentName name) { mBluetoothService = null; } }; private String mBluetoothAddress; private List<List<BluetoothGattCharacteristic>> mGattCharacteristics; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_devicecontrol); setTitle(getIntent().getStringExtra(BLE_DEVICE_NAME)); getSupportActionBar().setDisplayHomeAsUpEnabled(true); EventBus.getDefault().register(this); mBluetoothAddress = getIntent().getStringExtra(BLE_DEVICE_ADDRESS); mDeviceAddress = (TextView) findViewById(R.id.tv_deviceAddress); mDeviceStatus = (TextView) findViewById(R.id.tv_deviceStatus); mDeviceData = (TextView) findViewById(R.id.tv_deviceData); mDeviceService = (ExpandableListView) findViewById(R.id.elv_deviceService); mDeviceService.setOnChildClickListener(this); clearUI(); //绑定服务 bindService(new Intent(this, BluetoothDeviceService.class), mBluetoothServiceConnection, BIND_AUTO_CREATE); } @Override protected void onResume() { super.onResume(); mDeviceAddress.setText(String.format(getString(R.string.ble_address), mBluetoothAddress)); if (mBluetoothService != null) { mBluetoothService.connect(mBluetoothAddress); } } @Override protected void onDestroy() { super.onDestroy(); EventBus.getDefault().unregister(this); unbindService(mBluetoothServiceConnection); mDeviceService = null; } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.menu_devicecontrol, menu); if (!connecting) { menu.findItem(R.id.connect).setVisible(true); menu.findItem(R.id.disconnect).setVisible(false); } else { menu.findItem(R.id.connect).setVisible(false); menu.findItem(R.id.disconnect).setVisible(true); } return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case android.R.id.home: onBackPressed(); break; case R.id.connect: mBluetoothService.connect(mBluetoothAddress); break; case R.id.disconnect: mBluetoothService.disconnect(); break; } return super.onOptionsItemSelected(item); } /** * 自身事件驱动,在UI线程中接收事件 * * @param gattEvent BluetoothGattEvent */ @Subscribe(threadMode = ThreadMode.MAIN) public void onReceive(BluetoothGattEvent gattEvent) { switch (gattEvent.event) { case GATT_CONNECT_SUCCESS: connecting = true; updateConnectState(R.string.ble_connect); invalidateOptionsMenu(); break; case GATT_CONNECT_FAILED: connecting = false; updateConnectState(R.string.ble_disconnect); invalidateOptionsMenu(); break; case GATT_DISCOVERED_SUCCESS: displayGattService(mBluetoothService.getSupportGattServices()); LogUtil.d("#发现服务#"); break; case GATT_RED_SUCCESS: case GATT_CHANGE: LogUtil.d("#收到数据#\t" + Arrays.toString(gattEvent.characteristic.getValue())); displayData(gattEvent.characteristic.getValue()); break; } } protected void clearUI() { mDeviceAddress.setText(String.format(getString(R.string.ble_address), "")); mDeviceStatus.setText(String.format(getString(R.string.ble_state), "")); mDeviceData.setText(String.format(getString(R.string.ble_data), "")); mDeviceService.setAdapter((SimpleExpandableListAdapter)null); } protected void displayData(byte[] data) { if (data != null && data.length > 0) { final String stringData = Arrays.toString(data); mDeviceData.setText(String.format(getString(R.string.ble_data), stringData.substring(1,stringData.length()-1))); } } protected void updateConnectState(@StringRes final int resourceId) { mDeviceStatus.setText(String.format(getString(R.string.ble_state), getString(resourceId))); } /** * 显示Gatt服务 * * @param gattServices */ protected void displayGattService(List<BluetoothGattService> gattServices) { if (gattServices == null) { return; } ArrayList<HashMap<String, String>> gattServiceData = new ArrayList<>(); ArrayList<List<HashMap<String, String>>> gattCharacteristicData = new ArrayList<>(); mGattCharacteristics = new ArrayList<>(); String LIST_PROPERTY = "PROPERTIES"; String LIST_UUID = "UUID"; for (BluetoothGattService gattService : gattServices) { final HashMap<String, String> currentServiceData = new HashMap<>(); String serviceUuid = gattService.getUuid().toString(); currentServiceData.put(LIST_UUID, serviceUuid); gattServiceData.add(currentServiceData); final List<HashMap<String, String>> gattCharacteristicGroupData = new ArrayList<>(); final List<BluetoothGattCharacteristic> gattCharacteristics = gattService.getCharacteristics(); final List<BluetoothGattCharacteristic> chars = new ArrayList<>(); for (BluetoothGattCharacteristic gattCharacteristic : gattCharacteristics) { chars.add(gattCharacteristic); final HashMap<String, String> currentCharaData = new HashMap<>(); String characteristicUuid = gattCharacteristic.getUuid().toString(); String property = gattCharacteristicPropertySwitch(gattCharacteristic); currentCharaData.put(LIST_PROPERTY, getString(R.string.ble_property) + property); currentCharaData.put(LIST_UUID, characteristicUuid); gattCharacteristicGroupData.add(currentCharaData); } mGattCharacteristics.add(chars); gattCharacteristicData.add(gattCharacteristicGroupData); } SimpleExpandableListAdapter gattServiceAdapter = new SimpleExpandableListAdapter(this, gattServiceData, android.R.layout.simple_expandable_list_item_1, new String[]{LIST_UUID}, new int[]{android.R.id.text1}, gattCharacteristicData, android.R.layout.simple_expandable_list_item_2, new String[]{LIST_PROPERTY, LIST_UUID}, new int[]{android.R.id.text1, android.R.id.text2}) { }; mDeviceService.setAdapter(gattServiceAdapter); } /** * 属性选择 * * @param gattCharacteristic BluetoothGattCharacteristic * @return 属性 */ protected String gattCharacteristicPropertySwitch(BluetoothGattCharacteristic gattCharacteristic) { int stringRes; switch (gattCharacteristic.getProperties()) { case BluetoothGattCharacteristic.PROPERTY_BROADCAST: stringRes = R.string.ble_property_broadcast; break; case BluetoothGattCharacteristic.PROPERTY_READ: stringRes = R.string.ble_property_read; break; case BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE: stringRes = R.string.ble_property_write_no_response; break; case BluetoothGattCharacteristic.PROPERTY_WRITE: case BluetoothGattCharacteristic.PROPERTY_SIGNED_WRITE: stringRes = R.string.ble_property_write; break; case BluetoothGattCharacteristic.PROPERTY_NOTIFY: stringRes = R.string.ble_property_notify; break; case BluetoothGattCharacteristic.PROPERTY_INDICATE: stringRes = R.string.ble_property_indicate; break; default: stringRes = R.string.ble_property_extended_props; break; } return getString(stringRes); } @Override public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, int childPosition, long id) { if (mGattCharacteristics == null || mGattCharacteristics.isEmpty()) { return false; } BluetoothGattCharacteristic notifyCharacteristic = null; final BluetoothGattCharacteristic characteristic = mGattCharacteristics.get(groupPosition).get(childPosition); final int properties = characteristic.getProperties(); if ((properties | BluetoothGattCharacteristic.PROPERTY_NOTIFY) > 0) { notifyCharacteristic = characteristic; mBluetoothService.setCharacteristicNotification(characteristic, true); } if ((properties | BluetoothGattCharacteristic.PERMISSION_READ) > 0) { //读取属性 if(notifyCharacteristic != null){ mBluetoothService.setCharacteristicNotification(notifyCharacteristic,false); notifyCharacteristic = null; } mBluetoothService.readCharacteristic(characteristic); } return true; } }