Updated to restore compatibility with Android V6 (removed use of Consumer for callbacks)

This commit is contained in:
Graham Jones
2022-03-01 23:34:46 +00:00
parent 8b196f4f37
commit 4b67646eea
7 changed files with 107 additions and 98 deletions

View File

@@ -6,7 +6,7 @@ android {
defaultConfig { defaultConfig {
applicationId "uk.org.openseizuredetector" applicationId "uk.org.openseizuredetector"
minSdkVersion 24 minSdkVersion 23
targetSdkVersion 30 targetSdkVersion 30
multiDexEnabled true multiDexEnabled true
} }

View File

@@ -3,7 +3,7 @@
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
package="uk.org.openseizuredetector" package="uk.org.openseizuredetector"
android:versionCode="94" android:versionCode="94"
android:versionName="4.0.0n"> android:versionName="4.0.0p">
<!-- android:allowBackup="false" --> <!-- android:allowBackup="false" -->
<uses-permission android:name="android.permission.BLUETOOTH" /> <uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />

View File

@@ -172,16 +172,19 @@ public class AuthenticateActivity extends AppCompatActivity {
String uname = mUnameEt.getText().toString(); String uname = mUnameEt.getText().toString();
String passwd = mPasswdEt.getText().toString(); String passwd = mPasswdEt.getText().toString();
Log.v(TAG,"onOK() - uname="+uname+", passwd="+passwd); Log.v(TAG,"onOK() - uname="+uname+", passwd="+passwd);
mWac.authenticate(uname,passwd, (String retVal) -> { mWac.authenticate(uname, passwd, new WebApiConnection.StringCallback() {
if (retVal != null) { @Override
Log.d(TAG,"Authentication Success - token is "+retVal); public void accept(String retVal) {
mUtil.showToast("Login Successful"); if (retVal != null) {
saveAuthToken(retVal); Log.d(TAG,"Authentication Success - token is "+retVal);
updateUi(); mUtil.showToast("Login Successful");
} else { saveAuthToken(retVal);
Log.e(TAG,"onOk: Authentication failure for "+uname+", "+passwd); updateUi();
mUtil.showToast("ERROR: Authentication Failed - Please Try Again"); } else {
mUtil.writeToSysLogFile("AuthActivity - Authorisation failed for "+uname+", "+passwd); Log.e(TAG,"onOk: Authentication failure for "+uname+", "+passwd);
mUtil.showToast("ERROR: Authentication Failed - Please Try Again");
mUtil.writeToSysLogFile("AuthActivity - Authorisation failed for "+uname+", "+passwd);
}
} }
}); });
//finish(); //finish();

View File

@@ -126,60 +126,61 @@ public class EditEventActivity extends AppCompatActivity {
// Retrieve the JSONObject containing the standard event types. // Retrieve the JSONObject containing the standard event types.
// Note this obscure syntax is to avoid having to create another interface, so it is worth it :) // Note this obscure syntax is to avoid having to create another interface, so it is worth it :)
// See https://medium.com/@pra4mesh/callback-function-in-java-20fa48b27797 // See https://medium.com/@pra4mesh/callback-function-in-java-20fa48b27797
mWac.getEventTypes((JSONObject eventTypesObj) -> { mWac.getEventTypes(new WebApiConnection.JSONObjectCallback() {
Log.v(TAG, "initialiseServiceConnection().onEventTypesReceived"); @Override
if (eventTypesObj == null) { public void accept(JSONObject eventTypesObj) {
Log.e(TAG, "initialiseServiceConnection().getEventTypes Callback: Error Retrieving event types"); Log.v(TAG, "initialiseServiceConnection().onEventTypesReceived");
mUtil.showToast("Error Retrieving Event Types from Server - Please Try Again Later!"); if (eventTypesObj == null) {
} else { Log.e(TAG, "initialiseServiceConnection().getEventTypes Callback: Error Retrieving event types");
Iterator<String> keys = eventTypesObj.keys(); mUtil.showToast("Error Retrieving Event Types from Server - Please Try Again Later!");
mEventTypesList = new ArrayList<String>(); } else {
mEventSubTypesHashMap = new HashMap<String, ArrayList<String>>(); Iterator<String> keys = eventTypesObj.keys();
while (keys.hasNext()) { mEventTypesList = new ArrayList<String>();
String key = keys.next(); mEventSubTypesHashMap = new HashMap<String, ArrayList<String>>();
Log.v(TAG, "initialiseServiceConnection().getEventTypes Callback: key=" + key); while (keys.hasNext()) {
mEventTypesList.add(key); String key = keys.next();
try { Log.v(TAG, "initialiseServiceConnection().getEventTypes Callback: key=" + key);
JSONArray eventSubTypes = eventTypesObj.getJSONArray(key); mEventTypesList.add(key);
ArrayList<String> eventSubtypesList = new ArrayList<String>(); try {
for (int i = 0; i < eventSubTypes.length(); i++) { JSONArray eventSubTypes = eventTypesObj.getJSONArray(key);
eventSubtypesList.add(eventSubTypes.getString(i)); ArrayList<String> eventSubtypesList = new ArrayList<String>();
for (int i = 0; i < eventSubTypes.length(); i++) {
eventSubtypesList.add(eventSubTypes.getString(i));
}
mEventSubTypesHashMap.put(key, eventSubtypesList);
mEventTypesListChanged = true;
} catch (JSONException e) {
Log.e(TAG, "initialiseServiceConnection().getEventTypes Callback: Error parsing JSONObject" + e.getMessage() + e.toString());
} }
mEventSubTypesHashMap.put(key, eventSubtypesList);
mEventTypesListChanged = true;
} catch (JSONException e) {
Log.e(TAG, "initialiseServiceConnection().getEventTypes Callback: Error parsing JSONObject" + e.getMessage() + e.toString());
} }
updateUi();
} }
updateUi();
} }
}); });
// Retrieve the event data to edit // Retrieve the event data to edit
try { try {
mWac.getEvent(mEventId, (JSONObject eventObj) -> { mWac.getEvent(mEventId, new WebApiConnection.JSONObjectCallback() {
Log.v(TAG,"onCreate.getEvent"); @Override
if (eventObj != null) { public void accept(JSONObject eventObj) {
mEventObj = eventObj; Log.v(TAG, "onCreate.getEvent");
Log.v(TAG, "onCreate.getEvent: eventObj=" + eventObj.toString()); if (eventObj != null) {
updateUi(); mEventObj = eventObj;
// FIXME: modify updateUi to use mEventObj Log.v(TAG, "onCreate.getEvent: eventObj=" + eventObj.toString());
} else { updateUi();
mUtil.showToast("Failed to Retrieve Event from Remote Database"); // FIXME: modify updateUi to use mEventObj
finish(); } else {
mUtil.showToast("Failed to Retrieve Event from Remote Database");
finish();
}
} }
}); });
} catch (Exception e) { } catch (Exception e) {
Log.e(TAG,"ERROR:"+e.getMessage()); Log.e(TAG, "ERROR:" + e.getMessage());
e.printStackTrace(); e.printStackTrace();
} }
} }
private void updateUi() { private void updateUi() {
Log.v(TAG, "updateUI"); Log.v(TAG, "updateUI");
TextView tv; TextView tv;
@@ -293,32 +294,28 @@ public class EditEventActivity extends AppCompatActivity {
try { try {
mWac.updateEvent(mEventObj, (JSONObject eventObj) -> { mWac.updateEvent(mEventObj, new WebApiConnection.JSONObjectCallback() {
Log.v(TAG,"onOk.updateEvent"); @Override
//mEventObj = eventObj; public void accept(JSONObject eventObj) {
if (eventObj != null) { Log.v(TAG, "onOk.updateEvent");
Log.v(TAG, "onOk.getEvent: eventObj=" + eventObj.toString()); //mEventObj = eventObj;
mUtil.showToast("Event Updated OK"); if (eventObj != null) {
finish(); Log.v(TAG, "onOk.getEvent: eventObj=" + eventObj.toString());
} else { mUtil.showToast("Event Updated OK");
Log.e(TAG,"onOk.updateEvent - Error - returned NULL"); finish();
mUtil.showToast("Error Updating Event"); } else {
updateUi(); Log.e(TAG, "onOk.updateEvent - Error - returned NULL");
} mUtil.showToast("Error Updating Event");
updateUi();
} }
); }
});
} catch (Exception e) { } catch (Exception e) {
Log.e(TAG,"ERROR:"+e.getMessage()); Log.e(TAG,"ERROR:"+e.getMessage());
e.printStackTrace(); e.printStackTrace();
mUtil.showToast("Error Updating Event"); mUtil.showToast("Error Updating Event");
updateUi(); updateUi();
} }
//String uname = mUnameEt.getText().toString();
//String passwd = mPasswdEt.getText().toString();
//Log.v(TAG,"onOK() - uname="+uname+", passwd="+passwd);
//mWac.authenticate(uname,passwd);
//finish();
} }
}; };

View File

@@ -45,7 +45,6 @@ import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Date; import java.util.Date;
import java.util.HashMap; import java.util.HashMap;
import java.util.function.Consumer;
//import static android.database.sqlite.SQLiteDatabase.openOrCreateDatabase; //import static android.database.sqlite.SQLiteDatabase.openOrCreateDatabase;
@@ -89,6 +88,13 @@ public class LogManager {
private boolean mAutoPruneDb; private boolean mAutoPruneDb;
private AutoPruneTimer mAutoPruneTimer; private AutoPruneTimer mAutoPruneTimer;
public interface CursorCallback {
void accept(Cursor retVal);
}
public interface ArrayListCallback {
void accept(ArrayList<HashMap<String, String>> retVal);
}
public LogManager(Context context, public LogManager(Context context,
boolean logRemote, boolean logRemoteMobile, String authToken, boolean logRemote, boolean logRemoteMobile, String authToken,
@@ -312,7 +318,7 @@ public class LogManager {
* *
* @return True on successful start or false if call fails. * @return True on successful start or false if call fails.
*/ */
public boolean getDatapointsByDate(String startDateStr, String endDateStr, Consumer<String> callback) { public boolean getDatapointsByDate(String startDateStr, String endDateStr, WebApiConnection.StringCallback callback) {
Log.d(TAG, "getDatapointsbyDate() - startDateStr=" + startDateStr + ", endDateStr=" + endDateStr); Log.d(TAG, "getDatapointsbyDate() - startDateStr=" + startDateStr + ", endDateStr=" + endDateStr);
String[] columns = {"*"}; String[] columns = {"*"};
String whereClause = "DataTime>? AND DataTime<?"; String whereClause = "DataTime>? AND DataTime<?";
@@ -336,7 +342,7 @@ public class LogManager {
* @param includeWarnings - whether to include warnings in the list of events, or just alarm conditions. * @param includeWarnings - whether to include warnings in the list of events, or just alarm conditions.
* @return True on successful start or false if call fails. * @return True on successful start or false if call fails.
*/ */
public boolean getEventsList(boolean includeWarnings, Consumer<ArrayList<HashMap<String, String>>> callback) { public boolean getEventsList(boolean includeWarnings, ArrayListCallback callback) {
Log.v(TAG, "getEventsList - includeWarnings=" + includeWarnings); Log.v(TAG, "getEventsList - includeWarnings=" + includeWarnings);
ArrayList<HashMap<String, String>> eventsList = new ArrayList<>(); ArrayList<HashMap<String, String>> eventsList = new ArrayList<>();
@@ -399,7 +405,7 @@ public class LogManager {
* @param includeWarnings - whether to include warnings in the list of events, or just alarm conditions. * @param includeWarnings - whether to include warnings in the list of events, or just alarm conditions.
* @return True on successful start or false if call fails. * @return True on successful start or false if call fails.
*/ */
public boolean getNextEventToUpload(boolean includeWarnings, Consumer<Long> callback) { public boolean getNextEventToUpload(boolean includeWarnings, WebApiConnection.LongCallback callback) {
Log.v(TAG, "getNextEventToUpload - includeWarnings=" + includeWarnings); Log.v(TAG, "getNextEventToUpload - includeWarnings=" + includeWarnings);
String[] whereArgsStatus = getEventWhereArgs(includeWarnings); String[] whereArgsStatus = getEventWhereArgs(includeWarnings);
@@ -448,7 +454,7 @@ public class LogManager {
* *
* @return True on successful start or false if call fails. * @return True on successful start or false if call fails.
*/ */
public boolean getNearestDatapointToDate(String dateStr, Consumer<Long> callback) { public boolean getNearestDatapointToDate(String dateStr, WebApiConnection.LongCallback callback) {
Log.v(TAG, "getNextEventToDate - dateStr=" + dateStr); Log.v(TAG, "getNextEventToDate - dateStr=" + dateStr);
String[] columns = {"*", "(julianday(dataTime)-julianday(datetime('" + dateStr + "'))) as ddiff"}; String[] columns = {"*", "(julianday(dataTime)-julianday(datetime('" + dateStr + "'))) as ddiff"};
//SQLStr = "SELECT *, (julianday(dataTime)-julianday(datetime('" + dateStr + "'))) as ddiff from " + mDbTableName + " order by ABS(ddiff) asc;"; //SQLStr = "SELECT *, (julianday(dataTime)-julianday(datetime('" + dateStr + "'))) as ddiff from " + mDbTableName + " order by ABS(ddiff) asc;";
@@ -481,7 +487,7 @@ public class LogManager {
* @param includeWarnings - whether to include warnings in the list of events, or just alarm conditions. * @param includeWarnings - whether to include warnings in the list of events, or just alarm conditions.
* @return True on successful start or false if call fails. * @return True on successful start or false if call fails.
*/ */
public boolean getLocalEventsCount(boolean includeWarnings, Consumer<Long> callback) { public boolean getLocalEventsCount(boolean includeWarnings, WebApiConnection.LongCallback callback) {
Log.v(TAG, "getLocalEventsCount- includeWarnings=" + includeWarnings); Log.v(TAG, "getLocalEventsCount- includeWarnings=" + includeWarnings);
String[] whereArgs = getEventWhereArgs(includeWarnings); String[] whereArgs = getEventWhereArgs(includeWarnings);
String whereClause = getEventWhereClause(includeWarnings); String whereClause = getEventWhereClause(includeWarnings);
@@ -504,7 +510,7 @@ public class LogManager {
* *
* @return True on successful start or false if call fails. * @return True on successful start or false if call fails.
*/ */
public boolean getLocalDatapointsCount(Consumer<Long> callback) { public boolean getLocalDatapointsCount(WebApiConnection.LongCallback callback) {
Log.v(TAG, "getLocalDatapointsCount"); Log.v(TAG, "getLocalDatapointsCount");
String[] whereArgs = null; String[] whereArgs = null;
String whereClause = null; String whereClause = null;
@@ -537,12 +543,12 @@ public class LogManager {
String mGroupBy; String mGroupBy;
String mHaving; String mHaving;
String mOrderBy; String mOrderBy;
Consumer<Cursor> mCallback; CursorCallback mCallback;
//query(String table, String[] columns, String selection, String[] selectionArgs, //query(String table, String[] columns, String selection, String[] selectionArgs,
// String groupBy, String having, String orderBy) // String groupBy, String having, String orderBy)
SelectQueryTask(String table, String[] columns, String selection, String[] selectionArgs, SelectQueryTask(String table, String[] columns, String selection, String[] selectionArgs,
String groupBy, String having, String orderBy, Consumer<Cursor> callback) { String groupBy, String having, String orderBy, CursorCallback callback) {
// list all the parameters like in normal class define // list all the parameters like in normal class define
this.mTable = table; this.mTable = table;
this.mColumns = columns; this.mColumns = columns;

View File

@@ -279,8 +279,6 @@ public class SdServer extends Service implements SdDataReceiver {
mUtil.writeToSysLogFile("SdServer.onStartCommand() - starting SdDataSource"); mUtil.writeToSysLogFile("SdServer.onStartCommand() - starting SdDataSource");
mSdDataSource.start(); mSdDataSource.start();
checkEvents();
// Initialise Notification channel for API level 26 and over // Initialise Notification channel for API level 26 and over
// from https://stackoverflow.com/questions/44443690/notificationcompat-with-api-26 // from https://stackoverflow.com/questions/44443690/notificationcompat-with-api-26
mNM = (NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE); mNM = (NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE);
@@ -349,6 +347,8 @@ public class SdServer extends Service implements SdDataReceiver {
mUtil.writeToSysLogFile("SdServer.onStartCommand() - mWakeLock is not null - this shouldn't happen???"); mUtil.writeToSysLogFile("SdServer.onStartCommand() - mWakeLock is not null - this shouldn't happen???");
} }
checkEvents();
return START_STICKY; return START_STICKY;
} }

View File

@@ -1,20 +1,15 @@
package uk.org.openseizuredetector; package uk.org.openseizuredetector;
import android.content.Context; import android.content.Context;
import android.content.SharedPreferences;
import android.icu.text.RelativeDateTimeFormatter;
import android.os.Handler; import android.os.Handler;
import android.preference.PreferenceManager;
import android.util.Log; import android.util.Log;
import com.android.volley.AuthFailureError; import com.android.volley.AuthFailureError;
import com.android.volley.Request; import com.android.volley.Request;
import com.android.volley.RequestQueue; import com.android.volley.RequestQueue;
import com.android.volley.Response; import com.android.volley.Response;
import com.android.volley.VolleyError; import com.android.volley.VolleyError;
import com.android.volley.VolleyLog; import com.android.volley.VolleyLog;
import com.android.volley.toolbox.JsonObjectRequest;
import com.android.volley.toolbox.StringRequest; import com.android.volley.toolbox.StringRequest;
import com.android.volley.toolbox.Volley; import com.android.volley.toolbox.Volley;
@@ -24,12 +19,10 @@ import org.json.JSONObject;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.text.DateFormat; import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.Date; import java.util.Date;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.function.Consumer;
// This class is intended to handle all interactions with the OSD WebAPI // This class is intended to handle all interactions with the OSD WebAPI
@@ -44,6 +37,18 @@ public class WebApiConnection {
private OsdUtil mUtil; private OsdUtil mUtil;
RequestQueue mQueue; RequestQueue mQueue;
public interface JSONObjectCallback {
public void accept(JSONObject retValObj);
}
public interface StringCallback {
public void accept(String retValStr);
}
public interface LongCallback {
public void accept(Long retVal);
}
public WebApiConnection(Context context) { public WebApiConnection(Context context) {
mContext = context; mContext = context;
mQueue = Volley.newRequestQueue(context); mQueue = Volley.newRequestQueue(context);
@@ -64,7 +69,7 @@ public class WebApiConnection {
* @param callback - call back function callback(String retVal) * @param callback - call back function callback(String retVal)
* @return true if request sent, or false if failed to send request. * @return true if request sent, or false if failed to send request.
*/ */
public boolean authenticate(final String uname, final String passwd, Consumer<String> callback) { public boolean authenticate(final String uname, final String passwd, StringCallback callback) {
// NOTE: the 'final' keyword is necessary for uname and passwd to be accessible to getParams below - I don't know why! // NOTE: the 'final' keyword is necessary for uname and passwd to be accessible to getParams below - I don't know why!
// We know that this command works, so we just need the Java equivalent: // We know that this command works, so we just need the Java equivalent:
// curl -X POST -d 'login=graham4&password=testpwd1' https://osdapi.ddns.net/api/accounts/login/ // curl -X POST -d 'login=graham4&password=testpwd1' https://osdapi.ddns.net/api/accounts/login/
@@ -148,7 +153,7 @@ public class WebApiConnection {
// Create a new event in the remote database, based on the provided parameters. // Create a new event in the remote database, based on the provided parameters.
public boolean createEvent(final int osdAlarmState, final Date eventDate, final String eventDesc, Consumer<String> callback) { public boolean createEvent(final int osdAlarmState, final Date eventDate, final String eventDesc, StringCallback callback) {
Log.v(TAG, "createEvent()"); Log.v(TAG, "createEvent()");
String urlStr = mUrlBase + "/api/events/"; String urlStr = mUrlBase + "/api/events/";
Log.v(TAG, "urlStr=" + urlStr); Log.v(TAG, "urlStr=" + urlStr);
@@ -227,7 +232,7 @@ public class WebApiConnection {
return (true); return (true);
} }
public boolean getEvent(Long eventId, Consumer<JSONObject> callback) { public boolean getEvent(Long eventId, JSONObjectCallback callback) {
//Long eventId=Long.valueOf(285); //Long eventId=Long.valueOf(285);
Log.v(TAG, "getEvent()"); Log.v(TAG, "getEvent()");
String urlStr = mUrlBase + "/api/events/" + eventId; String urlStr = mUrlBase + "/api/events/" + eventId;
@@ -287,7 +292,7 @@ public class WebApiConnection {
* @param callback * @param callback
* @return true on success or false on failure to initiate the request. * @return true on success or false on failure to initiate the request.
*/ */
public boolean getEvents(Consumer<JSONObject> callback) { public boolean getEvents(JSONObjectCallback callback) {
//Long eventId=Long.valueOf(285); //Long eventId=Long.valueOf(285);
Log.v(TAG, "getEvents()"); Log.v(TAG, "getEvents()");
String urlStr = mUrlBase + "/api/events/"; String urlStr = mUrlBase + "/api/events/";
@@ -348,7 +353,7 @@ public class WebApiConnection {
} }
public boolean updateEvent(final JSONObject eventObj, Consumer<JSONObject> callback) { public boolean updateEvent(final JSONObject eventObj, JSONObjectCallback callback) {
Long eventId; Long eventId;
Log.v(TAG, "updateEvent()"); Log.v(TAG, "updateEvent()");
final String authtoken = getStoredToken(); final String authtoken = getStoredToken();
@@ -447,7 +452,7 @@ public class WebApiConnection {
} }
public boolean createDatapoint(JSONObject dataObj, int eventId, Consumer<String> callback) { public boolean createDatapoint(JSONObject dataObj, int eventId, StringCallback callback) {
Log.v(TAG, "createDatapoint()"); Log.v(TAG, "createDatapoint()");
// Create a new event in the remote database, based on the provided parameters. // Create a new event in the remote database, based on the provided parameters.
String urlStr = mUrlBase + "/api/datapoints/"; String urlStr = mUrlBase + "/api/datapoints/";
@@ -537,7 +542,7 @@ public class WebApiConnection {
* @param callback - function to be called with a JSONObject as a parameter that contains the user profile data. * @param callback - function to be called with a JSONObject as a parameter that contains the user profile data.
* @return true if request sent successfully, or else false. * @return true if request sent successfully, or else false.
*/ */
public boolean getUserProfile(Consumer<JSONObject> callback) { public boolean getUserProfile(JSONObjectCallback callback) {
Log.v(TAG, "getUserProfile()"); Log.v(TAG, "getUserProfile()");
String urlStr = mUrlBase + "/api/accounts/profile/"; String urlStr = mUrlBase + "/api/accounts/profile/";
Log.v(TAG, "getUserProfile(): urlStr=" + urlStr); Log.v(TAG, "getUserProfile(): urlStr=" + urlStr);
@@ -595,12 +600,10 @@ public class WebApiConnection {
/** /**
* Retrieve the file containing the standard event types from the server. * Retrieve the file containing the standard event types from the server.
* Calls the specified callback function, passing a JSONObject as a parameter when the data has been received and parsed. * Calls the specified callback function, passing a JSONObject as a parameter when the data has been received and parsed.
* Note it uses a Consumer callback function to avoid having to create another interface
* - see https://medium.com/@pra4mesh/callback-function-in-java-20fa48b27797
* *
* @return true if request sent successfully or else false. * @return true if request sent successfully or else false.
*/ */
public boolean getEventTypes(Consumer<JSONObject> callback) { public boolean getEventTypes(JSONObjectCallback callback) {
Log.v(TAG, "getEventTypes()"); Log.v(TAG, "getEventTypes()");
String urlStr = mUrlBase + "/static/eventTypes.json"; String urlStr = mUrlBase + "/static/eventTypes.json";
Log.v(TAG, "urlStr=" + urlStr); Log.v(TAG, "urlStr=" + urlStr);