/*
* Copyright (C) 2015 Iasc CHEN
*
* 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 me.iasc.microduino.blueledpad;
import android.app.Activity;
import android.app.AlertDialog;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattService;
import android.content.*;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;
import android.view.*;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import me.iasc.microduino.blueledpad.ble.BluetoothLeService;
public abstract class AbstractBleControlActivity extends Activity {
private final static String TAG = AbstractBleControlActivity.class.getSimpleName();
public static final String EXTRAS_DEVICE_NAME = "DEVICE_NAME";
public static final String EXTRAS_DEVICE_ADDRESS = "DEVICE_ADDRESS";
public static int BLE_MSG_SEND_INTERVAL = 100;
public static int BLE_MSG_BUFFER_LEN = 18;
protected String currDeviceName, currDeviceAddress;
protected Activity activity;
protected TextView isSerial, mConnectionState, returnText;
protected Button buttonSend;
protected ImageView infoButton;
protected BluetoothLeService mBluetoothLeService;
protected BluetoothGattCharacteristic characteristicTX, characteristicRX;
protected boolean mConnected = false, characteristicReady = false;
protected StringBuilder msgBuffer;
// Code to manage Service lifecycle.
protected 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(currDeviceAddress);
}
@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.
protected 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();
} else if (BluetoothLeService.ACTION_GATT_SERVICES_DISCOVERED.equals(action)) {
BluetoothGattService gattService = mBluetoothLeService.getSoftSerialService();
if (gattService == null) {
Toast.makeText(AbstractBleControlActivity.this, getString(R.string.without_service), Toast.LENGTH_SHORT).show();
return;
}
if (currDeviceName.startsWith("Microduino")) {
characteristicTX = gattService.getCharacteristic(BluetoothLeService.UUID_MD_RX_TX);
} else if (currDeviceName.startsWith("EtOH")) {
characteristicTX = gattService.getCharacteristic(BluetoothLeService.UUID_ETOH_RX_TX);
}
characteristicRX = characteristicTX;
if (characteristicTX != null) {
mBluetoothLeService.setCharacteristicNotification(characteristicTX, true);
isSerial.setText("Serial ready");
updateReadyState(R.string.ready);
} else {
isSerial.setText("Serial can't be found");
}
} else if (BluetoothLeService.ACTION_DATA_AVAILABLE.equals(action)) {
displayData(intent.getStringExtra(mBluetoothLeService.EXTRA_DATA));
}
}
};
protected 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;
}
protected View.OnClickListener onClickListener = new View.OnClickListener() {
public void onClick(View v) {
if (v == buttonSend) {
msgBuffer = new StringBuilder();
msgBuffer.append("Message send to BLE device"); // TODO change message
UploadAsyncTask asyncTask = new UploadAsyncTask();
asyncTask.execute();
}
}
};
@Override
public void onCreate(Bundle savedInstanceState) {
// setContentView(R.layout.activity_upload_matrix);
super.onCreate(savedInstanceState);
activity = this;
final Intent intent = getIntent();
currDeviceName = intent.getStringExtra(EXTRAS_DEVICE_NAME);
currDeviceAddress = intent.getStringExtra(EXTRAS_DEVICE_ADDRESS);
// Sets up UI references.
mConnectionState = (TextView) findViewById(R.id.connection_state);
// is serial present?
isSerial = (TextView) findViewById(R.id.isSerial);
returnText = (TextView) findViewById(R.id.textReturn);
buttonSend = (Button) findViewById(R.id.sendButton);
buttonSend.setOnClickListener(onClickListener);
infoButton = (ImageView) findViewById(R.id.infoImage);
infoButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
iascDialog();
}
});
getActionBar().setTitle(currDeviceName);
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(currDeviceAddress);
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(currDeviceAddress);
return true;
case R.id.menu_disconnect:
mBluetoothLeService.disconnect();
return true;
case android.R.id.home:
onBackPressed();
return true;
}
return super.onOptionsItemSelected(item);
}
protected void updateConnectionState(final int resourceId) {
runOnUiThread(new Runnable() {
@Override
public void run() {
mConnectionState.setText(resourceId);
}
});
}
protected void updateReadyState(final int resourceId) {
runOnUiThread(new Runnable() {
@Override
public void run() {
characteristicReady = true;
buttonSend.setEnabled(characteristicReady);
Toast.makeText(AbstractBleControlActivity.this, getString(resourceId), Toast.LENGTH_SHORT).show();
}
});
}
protected void displayData(String data) {
if (data != null) {
Log.v(TAG, "BLE Return Data : " + data);
returnText.setText(data);
}
}
public void wait_ble(int i) {
try {
Thread.sleep(i);
} catch (Exception e) {
// ignore
}
}
protected int getMsgBufferLen() {
return BLE_MSG_BUFFER_LEN;
}
protected void sendMessage(String msg) {
int msglen = msg.length();
Log.v(TAG, "sendMsg msg= " + msg);
int msgBufferLen = getMsgBufferLen();
if (characteristicReady && (mBluetoothLeService != null)
&& (characteristicTX != null) && (characteristicRX != null)) {
mBluetoothLeService.setCharacteristicNotification(characteristicRX, true);
String tmp;
for (int offset = 0; offset < msglen; offset += msgBufferLen) {
tmp = msg.substring(offset, Math.min(offset + msgBufferLen, msglen));
Log.v(TAG, "sendMsg tmp= " + tmp);
characteristicTX.setValue(tmp);
mBluetoothLeService.writeCharacteristic(characteristicTX);
wait_ble(BLE_MSG_SEND_INTERVAL);
}
} else {
Toast.makeText(AbstractBleControlActivity.this, getString(R.string.disconnected), Toast.LENGTH_SHORT).show();
}
}
protected void sendMessage(byte[] msgBytes, int bufferLen) {
int msglen = msgBytes.length;
Log.v(TAG, "sendMsg msgByteLen= " + msglen);
byte[] buffer = new byte[bufferLen];
if (characteristicReady && (mBluetoothLeService != null)
&& (characteristicTX != null) && (characteristicRX != null)) {
mBluetoothLeService.setCharacteristicNotification(characteristicRX, true);
for (int offset = 0; offset < msglen; offset += bufferLen) {
System.arraycopy(msgBytes, offset, buffer, 0, Math.min( bufferLen, msglen - offset));
Log.v(TAG, "sendMsg buffer= " + buffer);
characteristicTX.setValue(buffer);
mBluetoothLeService.writeCharacteristic(characteristicTX);
wait_ble(BLE_MSG_SEND_INTERVAL);
}
} else {
Toast.makeText(AbstractBleControlActivity.this, getString(R.string.disconnected), Toast.LENGTH_SHORT).show();
}
}
protected void iascDialog() {
LayoutInflater inflater = getLayoutInflater();
View layout = inflater.inflate(R.layout.iasc_dialog,
(ViewGroup) findViewById(R.id.dialog));
new AlertDialog.Builder(this).setView(layout)
.setPositiveButton("OK", null).show();
}
public void toastMessage(String msg) {
Toast.makeText(getApplicationContext(), msg, Toast.LENGTH_LONG).show();
}
public class UploadAsyncTask extends AsyncTask<Integer, Integer, String> {
@Override
protected String doInBackground(Integer... params) {
if (characteristicReady) {
sendMessage(msgBuffer.toString().getBytes(), BLE_MSG_BUFFER_LEN);
wait_ble(BLE_MSG_SEND_INTERVAL);
}
return "Done";
}
@Override
protected void onPostExecute(String result) {
Toast.makeText(AbstractBleControlActivity.this, getString(R.string.done), Toast.LENGTH_SHORT).show();
}
}
}