Added button in settings to select BLE device. Note may have broken theme so UI looks odd - actionbar may be missing...

This commit is contained in:
Graham Jones
2020-08-08 21:31:34 +01:00
parent 3d9d47a757
commit 7e2dce8c67
12 changed files with 499 additions and 28 deletions

View File

@@ -5,6 +5,8 @@
android:versionCode="72"
android:versionName="3.4.0">
<!-- android:allowBackup="false" -->
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
@@ -27,8 +29,9 @@
android:icon="@drawable/star_of_life_48x48"
android:label="@string/app_name"
android:networkSecurityConfig="@xml/network_security_config"
android:theme="@style/Theme.AppCompat"
>
android:theme="@style/AppTheme"
> <!--@android:style/Theme.Holo.Light"-->
<activity android:name=".BLEScanActivity"></activity>
<activity android:name=".DBQueryActivity"></activity>
<!-- android:usesCleartextTraffic="true" -->
<activity android:name=".StartupActivity">

View File

@@ -0,0 +1,323 @@
package uk.org.openseizuredetector;
/*
* 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.
*/
import android.Manifest;
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.SharedPreferences;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.Handler;
import android.preference.PreferenceManager;
import android.support.v4.app.ActivityCompat;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
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 BLEScanActivity extends ListActivity {
private LeDeviceListAdapter mLeDeviceListAdapter;
private BluetoothAdapter mBluetoothAdapter;
private boolean mScanning;
private Handler mHandler;
private boolean mPermissionsRequested = false;
private final String TAG = "BLEScanActivity";
private final String[] REQUIRED_PERMISSIONS = {
Manifest.permission.ACCESS_COARSE_LOCATION,
Manifest.permission.BLUETOOTH,
Manifest.permission.BLUETOOTH_ADMIN,
};
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);
//this.getActionBar().setTitle(R.string.title_devices);
this.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.ble_scan_menu, 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()) {
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;
Log.v(TAG, "onListItemClick: Device=" + device.getName() + ", Addr=" + device.getAddress());
if (mScanning) {
mBluetoothAdapter.stopLeScan(mLeScanCallback);
mScanning = false;
}
Log.v(TAG,"Saving Device Details");
SharedPreferences.Editor SPE = PreferenceManager
.getDefaultSharedPreferences(this).edit();
try {
SPE.putString("BLE_Device_Addr", device.getAddress());
SPE.putString("BLE_Device_Name", device.getName());
SPE.apply();
SPE.commit();
Log.v(TAG, "Saved Device Name="+device.getName()+" and Address="+device.getAddress());
} catch (Exception ex) {
Log.e(TAG, "Error Saving Devie Name and Address!");
Toast toast = Toast.makeText(this, "Problem Saving Device Name and Address", Toast.LENGTH_SHORT);
toast.show();
}
SharedPreferences SP = PreferenceManager.getDefaultSharedPreferences((this));
Log.v(TAG,"Check of saved values - Name="+SP.getString("BLE_Device_Name","NOT SET")+", Addr="+SP.getString("BLE_Device_Addr","NOT SET"));
finish();
}
private void scanLeDevice(final boolean enable) {
requestPermissions(this);
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<BluetoothDevice> mLeDevices;
private LayoutInflater mInflator;
public LeDeviceListAdapter() {
super();
mLeDevices = new ArrayList<BluetoothDevice>();
mInflator = BLEScanActivity.this.getLayoutInflater();
}
public void addDevice(BluetoothDevice device) {
if (!mLeDevices.contains(device)) {
Log.v(TAG,"addDevice - "+device.getName());
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;
Log.v(TAG,"scanner getView i="+i);
// General ListView optimization code.
if (view == null) {
view = mInflator.inflate(R.layout.ble_list_item_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) {
Log.v(TAG,"LEScanCallback - device="+device.getName());
runOnUiThread(new Runnable() {
@Override
public void run() {
mLeDeviceListAdapter.addDevice(device);
mLeDeviceListAdapter.notifyDataSetChanged();
}
});
}
};
static class ViewHolder {
TextView deviceName;
TextView deviceAddress;
}
public void requestPermissions(Activity activity) {
if (mPermissionsRequested) {
Log.i(TAG, "requestPermissions() - request already sent - not doing anything");
} else {
Log.i(TAG, "requestPermissions() - requesting permissions");
for (int i = 0; i < REQUIRED_PERMISSIONS.length; i++) {
if (ActivityCompat.shouldShowRequestPermissionRationale(activity,
REQUIRED_PERMISSIONS[i])) {
Log.i(TAG, "shouldShowRationale for permission" + REQUIRED_PERMISSIONS[i]);
}
}
ActivityCompat.requestPermissions(activity,
REQUIRED_PERMISSIONS,
42);
mPermissionsRequested = true;
}
}
}

View File

@@ -34,16 +34,19 @@ import android.os.Bundle;
import android.preference.PreferenceFragment;
import android.preference.PreferenceManager;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
import java.util.List;
public class PrefActivity extends PreferenceActivity implements SharedPreferences.OnSharedPreferenceChangeListener {
public class PrefActivity extends PreferenceActivity implements SharedPreferences.OnSharedPreferenceChangeListener, View.OnClickListener {
private String TAG = "PreferenceActivity";
private OsdUtil mUtil;
private boolean mPrefChanged = false;
private Context mContext;
private Handler mHandler;
private Button mSelectBLEButton;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -118,6 +121,8 @@ public class PrefActivity extends PreferenceActivity implements SharedPreference
}
}
//mSelectBLEButton = findViewById(R.id.selectBLEDeviceButton);
//mSelectBLEButton.setOnClickListener(this);
}
@@ -217,6 +222,20 @@ public class PrefActivity extends PreferenceActivity implements SharedPreference
return true;
}
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.selectBLEDeviceButton:
Log.v(TAG,"onClick - SelectBLEDeviceButton");
final Intent intent = new Intent(this.mContext, BLEScanActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
mContext.startActivity(intent);
break;
default:
Log.e(TAG,"onClick - unrecognised button");
}
}
/**
* This fragment shows the preferences for the first header.
*/

View File

@@ -99,8 +99,8 @@ public abstract class SdDataSource {
private int mAlarmCount;
protected String mBleDeviceAddr;
protected String mBleDeviceName;
public SdDataSource(Context context, Handler handler, SdDataReceiver sdDataReceiver) {
@@ -660,6 +660,12 @@ public abstract class SdDataSource {
// Watch Settings
String prefStr;
prefStr = SP.getString("BLE_Device_Addr", "SET_FROM_XML");
mBleDeviceAddr = prefStr;
Log.v(TAG,"mBLEDeviceAddr="+mBleDeviceAddr);
prefStr = SP.getString("BLE_Device_Name", "SET_FROM_XML");
mBleDeviceName = prefStr;
Log.v(TAG,"mBLEDeviceName="+mBleDeviceName);
prefStr = SP.getString("PebbleDebug", "SET_FROM_XML");
if (prefStr != null) {

View File

@@ -70,8 +70,15 @@ public class SdDataSourceBLE extends SdDataSource {
*/
public void start() {
Log.i(TAG, "start()");
mUtil.writeToSysLogFile("SdDataSourceBLE.start()");
super.start();
mUtil.writeToSysLogFile("SdDataSourceBLE.start() - mBleDeviceAddr="+mBleDeviceAddr);
if (mBleDeviceAddr == "" || mBleDeviceAddr == null) {
final Intent intent = new Intent(this.mContext, BLEScanActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
mContext.startActivity(intent);
}
Log.i(TAG,"mBLEDevice is "+mBleDeviceName+", Addr="+mBleDeviceAddr);
}
/**

View File

@@ -0,0 +1,23 @@
<!--
Copyright 2013 Google Inc.
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.
-->
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="wrap_content"
android:layout_width="56dp"
android:minWidth="56dp">
<ProgressBar android:layout_width="32dp"
android:layout_height="32dp"
android:layout_gravity="center"/>
</FrameLayout>

View File

@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView android:id="@+id/device_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="24dp"/>
<TextView android:id="@+id/device_address"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="12dp"/>
</LinearLayout>

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<Button
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/selectBLEDeviceButton"
android:text="@string/select_ble_device_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="onClick"
>
</Button>

View File

@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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.
-->
<menu xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/menu_refresh"
android:checkable="false"
android:orderInCategory="1"
app:showAsAction="ifRoom" />
<item android:id="@+id/menu_scan"
android:title="@string/menu_scan"
android:orderInCategory="100"
app:showAsAction="ifRoom|withText" />
<item android:id="@+id/menu_stop"
android:title="@string/menu_stop"
android:orderInCategory="101"
app:showAsAction="ifRoom|withText" />
</menu>

View File

@@ -141,5 +141,13 @@
<string name="send_sms_last_location">Send SMS - last location is </string>
<string name="failed_to_send_sms">ERROR: FAILED TO SEND SMS MESSAGE</string>
<string name="sms_alarms_disabled">SMS Alarms Disabled - not doing anything!</string>
<string name="title_devices">BLE Devices</string>
<string name="ble_not_supported">BLE Not Supported</string>
<string name="error_bluetooth_not_supported">Bluetooth Not Supported</string>
<string name="menu_stop">STOP</string>
<string name="menu_scan">SCAN</string>
<string name="unknown_device">Unknown Device</string>
<string name="select_ble_device_title">Select BLE Device</string>
<string name="select_ble_device_desc">Select Bluetooth Low Energy (BLE) Device to provide seizure (acceleration and heart rate) data).</string>
</resources>

View File

@@ -8,6 +8,12 @@
android:entryValues="@array/datasource_list_values"
android:defaultValue="Pebble"
android:dialogTitle="Select Data Source" />
<Preference
android:key="SelectBLEDevice"
android:title="@string/select_ble_device_title"
android:summary="@string/select_ble_device_desc"
android:widgetLayout="@layout/pref_select_ble_device_button"
/>
<CheckBoxPreference
android:defaultValue="true"
android:key="LogAlarms"

View File

@@ -1,7 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- The ListPreference data is defined in pebble_datasource_values.xml -->
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android">
<?xml version="1.0" encoding="utf-8"?><!-- The ListPreference data is defined in pebble_datasource_values.xml -->
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<PreferenceCategory android:title="BLE Device Settings">
<EditTextPreference
android:defaultValue=""
android:key="BLE_Device_Addr"
android:summary="MAC Address of BLE Data Source Device"
android:title="Device Address" />
<EditTextPreference
android:defaultValue=""
android:key="BLE_Device_Name"
android:summary="Name of BLE Data Source Device"
android:title="Device Address" />
</PreferenceCategory>
<PreferenceCategory android:title="User Interface Settings">
<EditTextPreference
android:defaultValue="5"
@@ -58,23 +68,22 @@
android:summary="Period (in seconds) between data analyses"
android:title="SamplePeriod (sec)" />
<ListPreference
android:key="PebbleSdMode"
android:title="Seizure Detector Mode"
android:summary="Select one of the three available modes of operation."
android:defaultValue="0"
android:dialogTitle="Select Seizure Detector Mode"
android:entries="@array/pebble_sd_mode_list"
android:entryValues="@array/pebble_sd_mode_list_values"
android:defaultValue="0"
android:dialogTitle="Select Seizure Detector Mode" />
android:key="PebbleSdMode"
android:summary="Select one of the three available modes of operation."
android:title="Seizure Detector Mode" />
<ListPreference
android:key="SampleFreq"
android:title="Select Sample Frequency"
android:summary="Higher Frequency is more Accurate, but uses more battery power."
android:entries="@array/pebble_sample_freq_list"
android:entryValues="@array/pebble_sample_freq_list_values"
android:defaultValue="100"
android:dialogTitle="Select Sample Frequency"
android:enabled="true"
/>
android:entries="@array/pebble_sample_freq_list"
android:entryValues="@array/pebble_sample_freq_list_values"
android:key="SampleFreq"
android:summary="Higher Frequency is more Accurate, but uses more battery power."
android:title="Select Sample Frequency" />
</PreferenceCategory>
@@ -102,16 +111,15 @@
android:title="Fall Detection Window (milli-seconds)" />
</PreferenceCategory>
<PreferenceCategory
android:title="Watch Communications Settings">
<PreferenceCategory android:title="Watch Communications Settings">
<ListPreference
android:key="PebbleDebug"
android:title="Seizure Detector Debug Mode"
android:summary="Set Debug mode on or off."
android:defaultValue="0"
android:dialogTitle="Select Debug Mode"
android:entries="@array/pebble_debug_list"
android:entryValues="@array/pebble_debug_values"
android:defaultValue="0"
android:dialogTitle="Select Debug Mode" />
android:key="PebbleDebug"
android:summary="Set Debug mode on or off."
android:title="Seizure Detector Debug Mode" />
<EditTextPreference
android:defaultValue="10"
android:key="AppRestartTimeout"