// Copyright 2012 (C) Matthew Brejza
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
package com.brejza.matt.habmodem;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import com.brejza.matt.habmodem.BluetoothLeService.LocalBinderBt;
import com.brejza.matt.habmodem.Dsp_service.LocalBinder;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.annotation.TargetApi;
import android.app.Activity;
import android.app.FragmentManager;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothManager;
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.content.pm.PackageManager;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.LinearLayout.LayoutParams;
import android.widget.ListView;
import android.widget.TableLayout;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.AdapterView.OnItemClickListener;
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2) public class BtScreen extends Activity {
private static final int REQUEST_ENABLE_BT = 54632;
private static final long SCAN_PERIOD = 10000;
Dsp_service mService;
boolean mBound = false;
BluetoothLeService mBtService;
boolean mBtBound = false;
boolean isReg = false;
boolean mConnected = false;
Handler handler;
Menu _menu;
private BluetoothAdapter mBluetoothAdapter;
private boolean mScanning;
private Handler mHandler;
ListView list;
ArrayAdapter<String> adapter;
boolean initList = false;
ListView listviewDeviceList;
ArrayAdapter<String> lvAdapter;
List<String> lvValues;
private StringRxReceiver strrxReceiver;
List<String> characteristic_list = new ArrayList<String>();
private ArrayList<ArrayList<BluetoothGattCharacteristic>> mGattCharacteristics =
new ArrayList<ArrayList<BluetoothGattCharacteristic>>();
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_bt_screen);
getActionBar().setDisplayHomeAsUpEnabled(true);
handler = new Handler();
listviewDeviceList = (ListView)findViewById(R.id.lstDevices);
lvValues = new ArrayList<String>();
lvValues.add("a");
lvAdapter = new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1,android.R.id.text1,lvValues);
listviewDeviceList.setAdapter(lvAdapter);
final Button btnConenct = (Button) findViewById(R.id.btnScan);
btnConenct.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
if (mConnected)
mBtService.disconnect();
else if (mScanning == false)
scanLeDevice(true);
}
});
/*final Button btnScan = (Button) findViewById(R.id.btnConnect);
btnScan.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
ListView lv = (ListView)findViewById(R.id.lstDevices);
//lv.getItemAtPosition(lv.getCheckedItemPosition());
mBtService.connect(lv.getItemAtPosition(lv.getCheckedItemPosition()).toString());
}
});
*/
listviewDeviceList.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view,int position, long id) {
ListView lv = (ListView)findViewById(R.id.lstDevices);
String idd = lv.getItemAtPosition(position).toString();
mBtService.connect(idd);
}
});
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main_menu, menu);
_menu = menu;
MenuItem item = menu.findItem(R.id.btconnect_screen);
item.setVisible(false);
item = menu.findItem(R.id.toggle_online);
item.setVisible(false);
item = menu.findItem(R.id.location_dialog);
item.setVisible(false);
item = menu.findItem(R.id.refresh_button);
item.setVisible(false);
item = menu.findItem(R.id.btconnect_screen);
item.setVisible(false);
item = menu.findItem(R.id.graphs_button);
item.setVisible(false);
this.invalidateOptionsMenu();
if (mService != null){
if (mService.enableUploader)
_menu.findItem(R.id.toggle_online).setChecked(true);
}
return true;
}
@Override
protected void onStop() {
super.onStop();
// Unbind from the service
if (mBound) {
unbindService(mConnection);
mBound = false;
}
if (mBtBound) {
unbindService(mBtConnection);
mBtBound = false;
}
}
@Override
public void onResume() {
super.onResume();
// Bind to LocalService
if (!mBound){
Intent intent = new Intent(this, Dsp_service.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}
// Bind to LocalService
if (!mBtBound){
Intent intent = new Intent(this, BluetoothLeService.class);
bindService(intent, mBtConnection, Context.BIND_AUTO_CREATE);
}
registerReceiver(mGattUpdateReceiver, makeGattUpdateIntentFilter());
if (strrxReceiver == null) strrxReceiver = new StringRxReceiver();
IntentFilter intentFilter1 = new IntentFilter(Dsp_service.TELEM_RX);
if (!isReg) { registerReceiver(strrxReceiver, intentFilter1); isReg = true;}
//scan for BTLE devices
//check if supported
if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
Toast.makeText(this, "BT LE not supported".toString(), Toast.LENGTH_SHORT).show();
}
else
{
final BluetoothManager bluetoothManager =
(BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
mBluetoothAdapter = bluetoothManager.getAdapter();
//make sure BT is enabled
if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
//TODO: get some sorta callback from the window to start a scan when done
}
else
scanLeDevice(true);
}
}
@Override
protected void onPause() {
super.onPause();
unregisterReceiver(mGattUpdateReceiver);
if (isReg){
if (strrxReceiver != null) unregisterReceiver(strrxReceiver);
isReg = false;
}
}
private void scanLeDevice(final boolean enable) {
if (enable) {
// Stops scanning after a pre-defined scan period.
if (!mConnected){
lvValues.clear();
lvAdapter.notifyDataSetChanged();
if (mHandler == null)
mHandler = new Handler();
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
mScanning = false;
updateConnectionState();
mBluetoothAdapter.stopLeScan(mLeScanCallback);
}
}, SCAN_PERIOD);
mScanning = true;
updateConnectionState();
mBluetoothAdapter.startLeScan(mLeScanCallback);
}
} else {
mScanning = false;
updateConnectionState();
mBluetoothAdapter.stopLeScan(mLeScanCallback);
}
}
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();
Log.i("BTLE", "FOUND SOMETHING!!!!!!!1! " + device.toString());
lvValues.add(device.toString()); //will cause issues as not modifying from UI thread
lvAdapter.notifyDataSetChanged();
}
});
}
};
/** Defines callbacks for service binding, passed to bindService() */
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName className,
IBinder service) {
// We've bound to LocalService, cast the IBinder and get LocalService instance
LocalBinder binder = (LocalBinder) service;
mService = binder.getService();
mBound = true;
updateListView();
if (mService.enableUploader && _menu != null)
_menu.findItem(R.id.toggle_online).setChecked(true);
}
@Override
public void onServiceDisconnected(ComponentName arg0) {
mBound = false;
}
};
private ServiceConnection mBtConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName className,
IBinder service) {
// We've bound to LocalService, cast the IBinder and get LocalService instance
LocalBinderBt binder = (LocalBinderBt) service;
mBtService = binder.getService();
mBtBound = true;
mBtService.initialize();
if (mBtService.isConnected())
mConnected = true;
else
mConnected = false;
updateConnectionState();
}
@Override
public void onServiceDisconnected(ComponentName arg0) {
mBtBound = false;
}
};
// 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();
scanLeDevice(false);
lvValues.clear();
lvAdapter.notifyDataSetChanged();
//invalidateOptionsMenu();
} else if (BluetoothLeService.ACTION_GATT_DISCONNECTED.equals(action)) {
mConnected = false;
updateConnectionState();
//invalidateOptionsMenu();
//clearUI();
} else if (BluetoothLeService.
ACTION_GATT_SERVICES_DISCOVERED.equals(action)) {
// Show all the supported services and characteristics on the
// user interface.
Log.i("BTLE",mBtService.getSupportedGattServices().toString());
List<BluetoothGattService> l = mBtService.getSupportedGattServices();
for (int i = 0; i < l.size(); i++)
{
Log.i("BTLE GATT",(l.get(i)).getUuid().toString());
List<BluetoothGattCharacteristic> clist = l.get(i).getCharacteristics();
for (int k = 0; k < clist.size(); k++)
{
String c = clist.get(k).getUuid().toString();
//if (c.equals("00002a37-0000-1000-8000-00805f9b34fb"))
// mBtService.setCharacteristicNotification( clist.get(k), true);
if (LoraBsGattAttributes.UUID_TELEMETRY_STRING_ASCII.equals(clist.get(k).getUuid()))
mBtService.setCharacteristicNotification( clist.get(k), true);
characteristic_list.add(c);
}
}
displayGattServices(l);
} else if (BluetoothLeService.ACTION_DATA_AVAILABLE.equals(action)) {
Log.i("BTLE",intent.getStringExtra(BluetoothLeService.EXTRA_DATA));
}
}
};
private void displayGattServices(List<BluetoothGattService> gattServices) {
if (gattServices == null) return;
String uuid = null;
String unknownServiceString = "unknown service";
String unknownCharaString = "unknown characteristic";
ArrayList<HashMap<String, String>> gattServiceData = new ArrayList<HashMap<String, String>>();
ArrayList<ArrayList<HashMap<String, String>>> gattCharacteristicData = new ArrayList<ArrayList<HashMap<String, String>>>();
mGattCharacteristics = new ArrayList<ArrayList<BluetoothGattCharacteristic>>();
// Loops through available GATT Services.
for (BluetoothGattService gattService : gattServices) {
HashMap<String, String> currentServiceData =
new HashMap<String, String>();
uuid = gattService.getUuid().toString();
currentServiceData.put(
"NAME", SampleGattAttributes.
lookup(uuid, unknownServiceString));
currentServiceData.put("UUID", uuid);
gattServiceData.add(currentServiceData);
ArrayList<HashMap<String, String>> gattCharacteristicGroupData =
new ArrayList<HashMap<String, String>>();
List<BluetoothGattCharacteristic> gattCharacteristics =
gattService.getCharacteristics();
ArrayList<BluetoothGattCharacteristic> charas =
new ArrayList<BluetoothGattCharacteristic>();
// Loops through available Characteristics.
for (BluetoothGattCharacteristic gattCharacteristic :
gattCharacteristics) {
charas.add(gattCharacteristic);
HashMap<String, String> currentCharaData =
new HashMap<String, String>();
uuid = gattCharacteristic.getUuid().toString();
currentCharaData.put(
"NAME", SampleGattAttributes.lookup(uuid,
unknownCharaString));
currentCharaData.put("UUID", uuid);
gattCharacteristicGroupData.add(currentCharaData);
}
mGattCharacteristics.add(charas);
gattCharacteristicData.add(gattCharacteristicGroupData);
}
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle item selection
Intent intent;
if (item.getItemId() == R.id.status_screen) {
return true; }
else if (item.getItemId() == R.id.map_screen) {
finish();
return true; }
else if (item.getItemId() == R.id.location_dialog) {
FragmentManager fm = getFragmentManager();
LocationSelectFragment di = new LocationSelectFragment();
di.enChase = mService.getEnableChase();
di.enPos = mService.getEnablePosition();
di.show(fm, "Location Settings");
return true; }
else if (item.getItemId() == R.id.refresh_button) {
mService.updateActivePayloadsHabitat();
return true; }
//else if (item.getItemId() == R.id.graphs_button) {
// if ( mService.getActivePayloadList().size() > 0)
// {
// showGraphDialog(mService.getActivePayloadList().get(0));
// }}
else if (item.getItemId() == R.id.log_screen) {
FragmentManager fm = getFragmentManager();
ViewLogFragment di = new ViewLogFragment();
di.setLogList(mService.getLog());
di.show(fm, "View Logs");}
else if (item.getItemId() == R.id.settings_screen) {
intent = new Intent(this,Preferences_activity.class);
startActivity(intent);
return true;}
else if (item.getItemId() == R.id.toggle_online){
//CheckBox chk = (CheckBox) findViewById(R.id.toggle_online);
if (mService.enableUploader){
mService.enableUploader = false;
item.setChecked(false);
}else{
mService.enableUploader = true;
item.setChecked(true);
}
return true;}
return super.onOptionsItemSelected(item);
}
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;
}
private class StringRxReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Dsp_service.TELEM_RX)) {
//Do stuff
System.out.println("GOT INTENT telem");
// list.add
updateListView();
}
}
}
private ArrayAdapter<String> initAdapter()
{
return new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1, android.R.id.text1, mService.listRxStr);
}
public void updateListView()
{
if (mService.listRxStr == null)
return;
if (mService.listRxStr.size() < 1)
return;
handler.post(new Runnable() {
@Override
public void run() {
if (!initList)
{
list = (ListView) findViewById(R.id.lstBtTelem);
adapter = initAdapter();
// Assign adapter to ListView
list.setAdapter(adapter);
list.setTranscriptMode(ListView.TRANSCRIPT_MODE_ALWAYS_SCROLL);
initList = true;
}
else
adapter.notifyDataSetChanged();
}
});
}
private void updateConnectionState()
{
final TextView tstat = (TextView) findViewById(R.id.txtBtStatus);
final Button btnConenct = (Button) findViewById(R.id.btnScan);
if (mConnected){
tstat.setText(getString(R.string.connected) + " to " + mBtService.getMacConnected());
btnConenct.setText("Disconnect");
listviewDeviceList.setLayoutParams(new TableLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT, 0.01f));
}
else if (mScanning)
{
tstat.setText("Scanning...");
listviewDeviceList.setLayoutParams(new TableLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT, 0.2f));
}
else
{
btnConenct.setText("Scan");
tstat.setText(getString(R.string.disconnected));
listviewDeviceList.setLayoutParams(new TableLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT, 0.2f));
}
}
}