Added authorisation dialog - doesn't do anything yet, which is a shame considering how much code it took!

This commit is contained in:
Graham Jones
2020-03-11 19:41:48 +00:00
parent a2073314cf
commit 95f3dd7d96
16 changed files with 451 additions and 14 deletions

View File

@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="uk.org.openseizuredetector"
android:versionCode="70"
android:versionName="3.2.0">
@@ -26,7 +27,8 @@
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/Theme.AppCompat"
>
<activity android:name=".DBQueryActivity"></activity>
<!-- android:usesCleartextTraffic="true" -->
<activity android:name=".StartupActivity">

View File

@@ -0,0 +1,78 @@
package uk.org.openseizuredetector;
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.support.v4.app.DialogFragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
public class AuthDialog extends DialogFragment {
private String TAG = "AuthDialog";
private AuthDialogInterface mListener;
private Context mContext;
private EditText mUnameEt;
private EditText mPasswdEt;
@Override
public View onCreateView(
LayoutInflater inflater,
ViewGroup container,
Bundle savedInstanceState) {
Log.v(TAG, "onCreateView()");
View v = inflater.inflate(R.layout.dialog_authenticate,
container, false);
Button cancelBtn =
(Button) v.findViewById(R.id.cancelBtn);
cancelBtn.setOnClickListener(onCancel);
Button OKBtn = (Button) v.findViewById(R.id.OKBtn);
OKBtn.setOnClickListener(onOK);
mUnameEt = (EditText) v.findViewById(R.id.username);
mPasswdEt = (EditText) v.findViewById(R.id.password);
return v;
}
View.OnClickListener onCancel =
new View.OnClickListener() {
@Override
public void onClick(View view) {
Log.v(TAG, "onCancel");
//m_status=false;
mListener.onDialogDone(false);
dismiss();
}
};
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);
mListener.onDialogDone(true);
dismiss();
}
};
@Override
public void onAttach(Context context) {
super.onAttach(context);
try {
mListener = (AuthDialogInterface) context;
} catch (ClassCastException e) {
throw new ClassCastException(context.toString()
+ " must implement dialogDoneistener");
}
}
}

View File

@@ -0,0 +1,5 @@
package uk.org.openseizuredetector;
public interface AuthDialogInterface {
void onDialogDone(boolean state);
}

View File

@@ -175,6 +175,21 @@ public class LogManager {
uploadSdData();
}
/**
* Authenticate using the WebAPI to obtain a token for future API requests.
* @param uname - user name
* @param passwd - password
*/
public void authenticate(String uname, String passwd) {
Log.v(TAG, "authenticate()");
// FIXME - this does not work!!!!
String dataStr = "data string to upload";
//new PostDataTask().execute("http://" + mOSDUrl + ":8080/data", dataStr, mOSDUname, mOSDPasswd);
new PostDataTask().execute("http://192.168.43.175:8765/datapoints/add", dataStr, mOSDUname, mOSDPasswd);
}
/**
* Upload a batch of seizure detector data records to the server..
* Uses the UploadSdDataTask class to upload the data in the

View File

@@ -1,22 +1,25 @@
package uk.org.openseizuredetector;
import android.app.Activity;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ListView;
import java.util.Date;
import uk.org.openseizuredetector.EventLogManager.EventLogListAdapter;
import uk.org.openseizuredetector.EventLogManager.EventLogManager;
import uk.org.openseizuredetector.EventLogManager.LogEntryModel;
public class LogManagerActivity extends Activity {
public class LogManagerActivity extends FragmentActivity
implements AuthDialogInterface {
private String TAG = "LogManagerActivity";
private EventLogListAdapter mEventLogListAdapter;
private ListView mEventLogListView;
private EventLogManager mElm;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -28,15 +31,32 @@ public class LogManagerActivity extends Activity {
lem.setDataJSON("[]");
lem.setAlarmState(1);
mElm = new EventLogManager(this);
mElm.addRow(lem);
//mElm = new EventLogManager(this);
//mElm.addRow(lem);
mEventLogListAdapter = new EventLogListAdapter(this);
mEventLogListView = (ListView) findViewById(R.id.eventLogListView);
mEventLogListView.setAdapter(mEventLogListAdapter);
//mEventLogListAdapter = new EventLogListAdapter(this);
//mEventLogListView = (ListView) findViewById(R.id.eventLogListView);
//mEventLogListView.setAdapter(mEventLogListAdapter);
Button b;
b = (Button) findViewById(R.id.authenticate_button);
b.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Log.v(TAG, "authenticate button clicked");
AuthDialog authDialog = new AuthDialog();
authDialog.show(getSupportFragmentManager(),"authDialog");
}
});
}
public void updateUi() {
Log.v(TAG, "updateUi");
}
}
public void onDialogDone(boolean State) {
Log.v(TAG,"onDialogDOne()");
}
}

View File

@@ -266,6 +266,17 @@ public class MainActivity extends AppCompatActivity {
Log.i(TAG, "exception starting log manager activity " + ex.toString());
}
return true;
case R.id.action_logmanager:
Log.i(TAG, "action_logmanager");
try {
Intent intent = new Intent(
MainActivity.this,
LogManagerActivity.class);
this.startActivity(intent);
} catch (Exception ex) {
Log.i(TAG, "exception starting log manager activity " + ex.toString());
}
return true;
case R.id.action_settings:
Log.i(TAG, "action_settings");
try {

View File

@@ -0,0 +1,29 @@
package uk.org.openseizuredetector.data;
import uk.org.openseizuredetector.data.model.LoggedInUser;
import java.io.IOException;
/**
* Class that handles authentication w/ login credentials and retrieves user information.
*/
public class LoginDataSource {
public Result<LoggedInUser> login(String username, String password) {
try {
// TODO: handle loggedInUser authentication
LoggedInUser fakeUser =
new LoggedInUser(
java.util.UUID.randomUUID().toString(),
"Jane Doe");
return new Result.Success<>(fakeUser);
} catch (Exception e) {
return new Result.Error(new IOException("Error logging in", e));
}
}
public void logout() {
// TODO: revoke authentication
}
}

View File

@@ -0,0 +1,54 @@
package uk.org.openseizuredetector.data;
import uk.org.openseizuredetector.data.model.LoggedInUser;
/**
* Class that requests authentication and user information from the remote data source and
* maintains an in-memory cache of login status and user credentials information.
*/
public class LoginRepository {
private static volatile LoginRepository instance;
private LoginDataSource dataSource;
// If user credentials will be cached in local storage, it is recommended it be encrypted
// @see https://developer.android.com/training/articles/keystore
private LoggedInUser user = null;
// private constructor : singleton access
private LoginRepository(LoginDataSource dataSource) {
this.dataSource = dataSource;
}
public static LoginRepository getInstance(LoginDataSource dataSource) {
if (instance == null) {
instance = new LoginRepository(dataSource);
}
return instance;
}
public boolean isLoggedIn() {
return user != null;
}
public void logout() {
user = null;
dataSource.logout();
}
private void setLoggedInUser(LoggedInUser user) {
this.user = user;
// If user credentials will be cached in local storage, it is recommended it be encrypted
// @see https://developer.android.com/training/articles/keystore
}
public Result<LoggedInUser> login(String username, String password) {
// handle login
Result<LoggedInUser> result = dataSource.login(username, password);
if (result instanceof Result.Success) {
setLoggedInUser(((Result.Success<LoggedInUser>) result).getData());
}
return result;
}
}

View File

@@ -0,0 +1,48 @@
package uk.org.openseizuredetector.data;
/**
* A generic class that holds a result success w/ data or an error exception.
*/
public class Result<T> {
// hide the private constructor to limit subclass types (Success, Error)
private Result() {
}
@Override
public String toString() {
if (this instanceof Result.Success) {
Result.Success success = (Result.Success) this;
return "Success[data=" + success.getData().toString() + "]";
} else if (this instanceof Result.Error) {
Result.Error error = (Result.Error) this;
return "Error[exception=" + error.getError().toString() + "]";
}
return "";
}
// Success sub-class
public final static class Success<T> extends Result {
private T data;
public Success(T data) {
this.data = data;
}
public T getData() {
return this.data;
}
}
// Error sub-class
public final static class Error extends Result {
private Exception error;
public Error(Exception error) {
this.error = error;
}
public Exception getError() {
return this.error;
}
}
}

View File

@@ -0,0 +1,23 @@
package uk.org.openseizuredetector.data.model;
/**
* Data class that captures user information for logged in users retrieved from LoginRepository
*/
public class LoggedInUser {
private String userId;
private String displayName;
public LoggedInUser(String userId, String displayName) {
this.userId = userId;
this.displayName = displayName;
}
public String getUserId() {
return userId;
}
public String getDisplayName() {
return displayName;
}
}

View File

@@ -9,18 +9,37 @@
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="uk.org.openseizuredetector.LogManager">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text="Large Text"
android:id="@+id/textView2"
android:text="@string/not_authenticated"
android:id="@+id/authStatusTv"
/>
<Button
android:id="@+id/authenticate_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/authenticate" />
<!--
<ListView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/eventLogListView"
android:layout_marginTop="97dp" />
<EditText
android:id="@+id/editText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:ems="10"
android:inputType="textPersonName"
android:text="Name" />
-->
</LinearLayout>

View File

@@ -0,0 +1,52 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:src="@drawable/star_of_life_24x24"
android:layout_width="match_parent"
android:layout_height="64dp"
android:scaleType="center"
android:background="#FFFFBB33"
android:contentDescription="@string/app_name" />
<EditText
android:id="@+id/username"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:layout_marginLeft="4dp"
android:layout_marginRight="4dp"
android:layout_marginBottom="4dp"
android:hint="username" />
<EditText
android:id="@+id/password"
android:inputType="textPassword"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:layout_marginLeft="4dp"
android:layout_marginRight="4dp"
android:layout_marginBottom="16dp"
android:fontFamily="sans-serif"
android:hint="password"/>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<Button
android:id="@+id/cancelBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/cancel" />
<Button
android:id="@+id/OKBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/authenticate" />
</LinearLayout>
</LinearLayout>

View File

@@ -46,6 +46,13 @@
android:showAsAction="never|withText"
android:title="Test SMS Alarm Notification" />
<item
android:id="@+id/action_logmanager"
android:icon="@drawable/ic_action_settings"
android:showAsAction="never|withText"
android:title="Data Log Manager"
android:enabled="true"
/>
<item
android:id="@+id/action_logs"

View File

@@ -2,4 +2,7 @@
<!-- Default screen margins, per the Android Design guidelines. -->
<dimen name="activity_horizontal_margin">16dp</dimen>
<dimen name="activity_vertical_margin">16dp</dimen>
<!-- Default screen margins, per the Android Design guidelines. -->
<dimen name="fragment_horizontal_margin">16dp</dimen>
<dimen name="fragment_vertical_margin">16dp</dimen>
</resources>

View File

@@ -79,4 +79,16 @@
<string name="CancelAudibleAlarms">Cancel Audible Alarms (temporarily)</string>
<string name="AudibleAlarmsOff">Audible Alarms OFF</string>
<string name="Fault">FAULT</string>
<string name="authenticate">Authenticate</string>
<string name="not_authenticated">Not Authenticated</string>
<string name="cancel">Cancel</string>
<!-- Strings related to login -->
<string name="prompt_email">Email</string>
<string name="prompt_password">Password</string>
<string name="action_sign_in">Sign in or register</string>
<string name="action_sign_in_short">Sign in</string>
<string name="welcome">"Welcome!"</string>
<string name="invalid_username">Not a valid username</string>
<string name="invalid_password">Password must be >5 characters</string>
<string name="login_failed">"Login failed"</string>
</resources>

View File

@@ -0,0 +1,59 @@
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<EditTextPreference
android:defaultValue="https://osd.dynu.net/"
android:key="serverUrl"
android:title="Server URL"
android:summary="URL of OpenSeizureDetector Data Log Server"
/>
<CheckBoxPreference
android:defaultValue="true"
android:key="LogToServer"
android:summary="Log Data to OpenSeizureDetector Server"
android:title="Log to Server" />
<CheckBoxPreference
android:defaultValue="false"
android:key="UploadOverMobileNetwork"
android:summary="Upload Data when using Mobile Network"
android:title="Use Mobile Network" />
<EditTextPreference
android:defaultValue="password"
android:key="OSDPasswd"
android:summary="Password for remote data logging."
android:title="Remote Password" />
<CheckBoxPreference
android:defaultValue="false"
android:key="PreventSleep"
android:summary="Prevent the screen from blanking while the application is running."
android:title="Prevent the screen from blanking." />
<EditTextPreference
android:defaultValue="1000"
android:key="UpdatePeriod"
android:summary="Display update period in miliseconds."
android:title="Display Update Period (ms)." />
<CheckBoxPreference
android:defaultValue="false"
android:key="AutoStart"
android:summary="Auto Start App on Boot"
android:title="Auto Start App on Boot"
android:enabled="true"
/>
<EditTextPreference
android:defaultValue=""
android:key="AppVersionName"
android:summary="App Version Number - used to decide whether to display the welcome message or not."
android:title="App Version Number" />
<!--
<CheckBoxPreference
android:defaultValue="false"
android:key="UseIpCamera"
android:summary="Use IP Camera to View Images"
android:title="Enable IP Camera"
android:enabled="false"
/>
-->
</PreferenceScreen>