diff --git a/app/build.gradle b/app/build.gradle index 2ba54e6..cfea828 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -6,7 +6,7 @@ android { defaultConfig { applicationId "uk.org.openseizuredetector" - minSdkVersion 21 + minSdkVersion 24 targetSdkVersion 29 multiDexEnabled true } @@ -24,6 +24,10 @@ android { includeAndroidResources = true } } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } } dependencies { diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 4375192..069609f 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -65,6 +65,7 @@ android:exported="false" /> + diff --git a/app/src/main/java/uk/org/openseizuredetector/EditEventActivity.java b/app/src/main/java/uk/org/openseizuredetector/EditEventActivity.java new file mode 100644 index 0000000..caada9a --- /dev/null +++ b/app/src/main/java/uk/org/openseizuredetector/EditEventActivity.java @@ -0,0 +1,174 @@ +package uk.org.openseizuredetector; + +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.os.Bundle; +import android.os.Handler; +import android.support.v7.app.AppCompatActivity; +import android.util.Log; +import android.view.View; +import android.widget.AdapterView; +import android.widget.ArrayAdapter; +import android.widget.Button; +import android.widget.EditText; +import android.widget.LinearLayout; +import android.widget.ListAdapter; +import android.widget.ListView; +import android.widget.SimpleAdapter; +import android.widget.TextView; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; + +public class EditEventActivity extends AppCompatActivity + implements AuthCallbackInterface, EventCallbackInterface, DatapointCallbackInterface { + private String TAG = "EditEventActivity"; + private Context mContext; + private WebApiConnection mWac; + private LogManager mLm; + final Handler serverStatusHandler = new Handler(); + private OsdUtil mUtil; + private List mEventTypesList = null; + private HashMap> mEventSubTypesHashMap = null; + + + @Override + protected void onCreate(Bundle savedInstanceState) { + Log.v(TAG, "onCreate()"); + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_edit_event); + Bundle extras = getIntent().getExtras(); + if (extras != null) { + Long eventId = extras.getLong("eventId"); + Log.v(TAG, "onCreate - eventId=" + eventId); + } + mUtil = new OsdUtil(this, serverStatusHandler); + + Button cancelBtn = + (Button) findViewById(R.id.cancelBtn); + cancelBtn.setOnClickListener(onCancel); + Button OKBtn = (Button) findViewById(R.id.OKBtn); + OKBtn.setOnClickListener(onOK); + + ListView lv = (ListView) findViewById(R.id.eventTypeLv); + lv.setOnItemClickListener(onEventTypeClick); + + mWac = new WebApiConnection(this, this, this, this); + mLm = new LogManager(this); + + // 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 :) + // See https://medium.com/@pra4mesh/callback-function-in-java-20fa48b27797 + mWac.getEventTypes((JSONObject eventTypesObj) -> { + Log.v(TAG, "onCreate.onEventTypesReceived"); + + if (eventTypesObj == null) { + Log.e(TAG, "onCreate.getEventTypes Callback: Error Retrieving event types"); + mUtil.showToast("Error Retrieving Event Types from Server - Please Try Again Later!"); + } else { + Iterator keys = eventTypesObj.keys(); + mEventTypesList = new ArrayList(); + mEventSubTypesHashMap = new HashMap>(); + while (keys.hasNext()) { + String key = keys.next(); + Log.v(TAG, "onCreate.getEventTypes Callback: key=" + key); + mEventTypesList.add(key); + try { + JSONArray eventSubTypes = eventTypesObj.getJSONArray(key); + ArrayList eventSubtypesList = new ArrayList(); + for (int i = 0; i < eventSubTypes.length(); i++) { + eventSubtypesList.add(eventSubTypes.getString(i)); + } + mEventSubTypesHashMap.put(key, eventSubtypesList); + } catch (JSONException e) { + Log.e(TAG, "onCreate(getEventTypes Callback: Error parsing JSONObject" + e.getMessage() + e.toString()); + } + } + updateUi(); + } + }); + } + + @Override + protected void onStart() { + super.onStart(); + Log.v(TAG, "onStart()"); + updateUi(); + } + + public void authCallback(boolean authSuccess, String tokenStr) { + Log.v(TAG, "authCallback"); + updateUi(); + } + + public void eventCallback(boolean success, String eventStr) { + Log.v(TAG, "eventCallback"); + } + + public void datapointCallback(boolean success, String datapointStr) { + Log.v(TAG, "datapointCallback"); + } + + private void updateUi() { + Log.v(TAG, "updateUI"); + if (mEventTypesList != null) { + //TextView tv = (TextView) findViewById(R.id.tokenTv); + //tv.setText("Logged in with Token:" + storedAuthToken); + Log.v(TAG, "updateUi: " + mEventTypesList.toString()); + ListView lv = (ListView) findViewById(R.id.eventTypeLv); + ArrayAdapter adapter = new ArrayAdapter(this, + R.layout.event_type_list_item, R.id.eventTypeTv, mEventTypesList); + lv.setAdapter(adapter); + } + } + + View.OnClickListener onCancel = + new View.OnClickListener() { + @Override + public void onClick(View view) { + Log.v(TAG, "onCancel"); + //m_status=false; + finish(); + } + }; + + View.OnClickListener onOK = + new View.OnClickListener() { + @Override + public void onClick(View view) { + //m_status=true; + Log.v(TAG, "onOK()"); + //String uname = mUnameEt.getText().toString(); + //String passwd = mPasswdEt.getText().toString(); + //Log.v(TAG,"onOK() - uname="+uname+", passwd="+passwd); + //mWac.authenticate(uname,passwd); + //finish(); + } + }; + + private void setSubTypesLV(String eventType) { + ArrayList subtypesArrayList = mEventSubTypesHashMap.get(eventType); + Log.v(TAG,"setSubtypesLV - eventType="+eventType+", subtypes="+subtypesArrayList); + ListView lv = (ListView)findViewById(R.id.eventSubTypeLv); + ArrayAdapter adapter = new ArrayAdapter(this, + R.layout.event_sub_type_list_item, R.id.eventSubTypeLv, subtypesArrayList); + lv.setAdapter(adapter); + } + + AdapterView.OnItemClickListener onEventTypeClick = + new AdapterView.OnItemClickListener() { + public void onItemClick(AdapterView adapter, View v, int position, long id) { + Log.v(TAG, "onEventTypeClick() - Position=" + position + ", id=" + id);// Confirmation dialog based on: https://stackoverflow.com/a/12213536/2104584 + String selectedEventType = (String) adapter.getItemAtPosition(position); + Log.v(TAG,"onEventTypeClick - selected "+selectedEventType); + setSubTypesLV(selectedEventType); + } + }; +} \ No newline at end of file diff --git a/app/src/main/java/uk/org/openseizuredetector/LogManagerControlActivity.java b/app/src/main/java/uk/org/openseizuredetector/LogManagerControlActivity.java index a58b6bd..e76b768 100644 --- a/app/src/main/java/uk/org/openseizuredetector/LogManagerControlActivity.java +++ b/app/src/main/java/uk/org/openseizuredetector/LogManagerControlActivity.java @@ -210,7 +210,13 @@ public class LogManagerControlActivity extends AppCompatActivity { new AdapterView.OnItemClickListener() { public void onItemClick(AdapterView adapter, View v, int position, long id) { Log.v(TAG, "onItemClicKListener() - Position=" + position + ", id=" + id);// Confirmation dialog based on: https://stackoverflow.com/a/12213536/2104584 - AlertDialog.Builder builder = new AlertDialog.Builder(mContext); + HashMap eventObj = (HashMap)adapter.getItemAtPosition(position); + Long eventId = Long.parseLong(eventObj.get("uploaded")); + Log.d(TAG,"onItemClickListener(): eventId="+eventId+", eventObj="+eventObj); + Intent i = new Intent(getApplicationContext(), EditEventActivity.class); + i.putExtra("eventId",eventId); + startActivity(i); + /*AlertDialog.Builder builder = new AlertDialog.Builder(mContext); builder.setTitle("Edit Remote Event Details"); builder.setMessage("Edit this event details on the remote database?"); builder.setPositiveButton("YES", new DialogInterface.OnClickListener() { @@ -228,7 +234,8 @@ public class LogManagerControlActivity extends AppCompatActivity { }); AlertDialog alert = builder.create(); alert.show(); - + */ + //MyClass selItem = (MyClass) myList.getSelectedItem(); // //String value= selItem.getTheValue(); //getter method } diff --git a/app/src/main/java/uk/org/openseizuredetector/WebApiConnection.java b/app/src/main/java/uk/org/openseizuredetector/WebApiConnection.java index 2ce534b..677e682 100644 --- a/app/src/main/java/uk/org/openseizuredetector/WebApiConnection.java +++ b/app/src/main/java/uk/org/openseizuredetector/WebApiConnection.java @@ -27,6 +27,7 @@ import java.text.SimpleDateFormat; import java.util.Date; import java.util.HashMap; import java.util.Map; +import java.util.function.Consumer; // This class is intended to handle all interactions with the OSD WebAPI @@ -297,4 +298,60 @@ public class WebApiConnection { } + /** + * 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. + * 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. + */ + public boolean getEventTypes(Consumer callback) { + Log.v(TAG, "getEventTypes()"); + String urlStr = mUrlBase + "/static/eventTypes.json"; + Log.v(TAG, "urlStr=" + urlStr); + final String authtoken = getStoredToken(); + + if (!isLoggedIn()) { + Log.v(TAG, "not logged in - doing nothing"); + return (false); + } + + StringRequest req = new StringRequest(Request.Method.GET, urlStr, + new Response.Listener() { + @Override + public void onResponse(String response) { + Log.v(TAG, "getEventTypes.onResponse(): Response is: " + response); + try { + JSONObject retObj = new JSONObject(response); + callback.accept(retObj); + } catch (JSONException e) { + Log.e(TAG,"getEventTypes.onRespons(): Error: "+e.getMessage()+","+e.toString()); + callback.accept(null); + } + } + }, + new Response.ErrorListener() { + @Override + public void onErrorResponse(VolleyError error) { + String responseBody = new String(error.networkResponse.data); + Log.e(TAG, "getEventTypes.onErrorResponse(): " + error.toString() + ", message:" + error.getMessage() + ", Response Code:" + error.networkResponse.statusCode + ", Response: " + responseBody); + callback.accept(null); + } + }) { + // Note, this is overriding part of StringRequest, not one of the sub-classes above! + @Override + public Map getHeaders() throws AuthFailureError { + Map params = new HashMap(); + params.put("Content-Type", "application/json; charset=UTF-8"); + params.put("Authorization", "Token " + getStoredToken()); + return params; + } + }; + + mQueue.add(req); + return (true); + + } + + } diff --git a/app/src/main/res/layout/activity_edit_event.xml b/app/src/main/res/layout/activity_edit_event.xml new file mode 100644 index 0000000..3a6e4db --- /dev/null +++ b/app/src/main/res/layout/activity_edit_event.xml @@ -0,0 +1,79 @@ + + + + + + + + + + + + + + + + + + + + + +