Browse Source

Refactored AccountRecoveryActivity. Changed default activity to GettingStarted. Cleaned up redirection logic (in case user starts in other activities). Renamed theme. Validation added to background tasks.

Víctor Hernández 3 years ago
parent
commit
cf183642fa

+ 12
- 12
app/src/main/AndroidManifest.xml View File

@@ -13,20 +13,20 @@
13 13
         android:label="TANIA"
14 14
         android:roundIcon="@mipmap/ic_launcher"
15 15
         android:supportsRtl="true"
16
-        android:theme="@style/Theme.MarleApp"
16
+        android:theme="@style/Theme.TANIA"
17 17
         android:usesCleartextTraffic="true">
18 18
 
19 19
         <activity
20 20
             android:name=".activities.ConsentPdfViewerActivity"
21 21
             android:label="@string/title_activity_consent_pdf_viewer"
22
-            android:theme="@style/Theme.MarleApp.NoActionBar" />
23
-        <activity android:name=".activities.GettingStartedActivity" />
24
-        <activity android:name=".activities.MainActivity">
22
+            android:theme="@style/Theme.TANIA.NoActionBar" />
23
+        <activity android:name=".activities.GettingStartedActivity">
25 24
             <intent-filter>
26 25
                 <category android:name="android.intent.category.LAUNCHER" />
27 26
                 <action android:name="android.intent.action.MAIN" />
28 27
             </intent-filter>
29
-
28
+        </activity>
29
+        <activity android:name=".activities.MainActivity">
30 30
             <intent-filter>
31 31
                 <action android:name="android.intent.action.VIEW" />
32 32
 
@@ -41,13 +41,13 @@
41 41
         <activity
42 42
             android:name="org.researchstack.backbone.ui.ViewTaskActivity"
43 43
             android:parentActivityName=".activities.MainActivity"
44
-            android:theme="@style/Theme.MarleApp"
44
+            android:theme="@style/Theme.TANIA"
45 45
             android:windowSoftInputMode="adjustResize" />
46 46
         <activity
47 47
             android:name="org.researchstack.backbone.ui.ViewWebDocumentActivity"
48 48
             android:label="@string/appName"
49 49
             android:parentActivityName=".activities.MainActivity"
50
-            android:theme="@style/Theme.MarleApp" />
50
+            android:theme="@style/Theme.TANIA" />
51 51
         <activity
52 52
             android:name=".activities.RegisterActivity"
53 53
             android:parentActivityName=".activities.GettingStartedActivity">
@@ -56,7 +56,7 @@
56 56
             </intent-filter>
57 57
         </activity>
58 58
         <activity
59
-            android:name=".activities.LoginActivity"
59
+            android:name=".activities.AccountRecoveryActivity"
60 60
             android:parentActivityName=".activities.GettingStartedActivity">
61 61
             <intent-filter>
62 62
                 <category android:name="android.intent.category.DEFAULT" />
@@ -64,8 +64,8 @@
64 64
         </activity>
65 65
         <activity
66 66
             android:name=".activities.ForgotPasswordActivity"
67
-            android:parentActivityName=".activities.LoginActivity"
68
-            android:theme="@style/Theme.MarleApp">
67
+            android:parentActivityName=".activities.AccountRecoveryActivity"
68
+            android:theme="@style/Theme.TANIA">
69 69
             <intent-filter>
70 70
                 <category android:name="android.intent.category.DEFAULT" />
71 71
             </intent-filter>
@@ -73,7 +73,7 @@
73 73
         <activity
74 74
             android:name=".activities.ResetPasswordActivity"
75 75
             android:parentActivityName=".activities.ResetPasswordActivity"
76
-            android:theme="@style/Theme.MarleApp">
76
+            android:theme="@style/Theme.TANIA">
77 77
             <intent-filter>
78 78
                 <action android:name="android.intent.action.VIEW" />
79 79
 
@@ -88,7 +88,7 @@
88 88
         <activity
89 89
             android:name=".activities.ExperienceRegistrationActivity"
90 90
             android:parentActivityName=".activities.ExperienceRegistrationActivity"
91
-            android:theme="@style/Theme.MarleApp">
91
+            android:theme="@style/Theme.TANIA">
92 92
             <intent-filter>
93 93
                 <action android:name="android.intent.action.VIEW" />
94 94
 

+ 18
- 0
app/src/main/java/uprrp/tania/App.java View File

@@ -1,10 +1,14 @@
1 1
 package uprrp.tania;
2 2
 
3 3
 import android.app.Application;
4
+import android.content.Intent;
5
+import android.content.SharedPreferences;
6
+import android.os.Build;
4 7
 import android.util.Log;
5 8
 import android.widget.Toast;
6 9
 
7 10
 import androidx.annotation.NonNull;
11
+import androidx.annotation.RequiresApi;
8 12
 
9 13
 import com.amazonaws.auth.CognitoCachingCredentialsProvider;
10 14
 import com.amazonaws.regions.Regions;
@@ -22,6 +26,8 @@ import org.researchstack.backbone.storage.file.PinCodeConfig;
22 26
 import org.researchstack.backbone.storage.file.SimpleFileAccess;
23 27
 import org.researchstack.backbone.storage.file.UnencryptedProvider;
24 28
 
29
+import uprrp.tania.activities.GettingStartedActivity;
30
+
25 31
 public class App extends Application {
26 32
 
27 33
     private static final String TAG = "App";
@@ -79,5 +85,17 @@ public class App extends Application {
79 85
                     }
80 86
                 });
81 87
 
88
+        // If user hasn't already registered, redirect accordingly,
89
+        // JUST IN CASE user starts non-default activity from somewhere else (like a browser)
90
+        // TODO: find a way to not redirect twice to GettingStarted
91
+        SharedPreferences prefs = getSharedPreferences("prefs", MODE_PRIVATE);
92
+        boolean needsToRegister = prefs.getBoolean("needsToRegister", true);
93
+        if(needsToRegister) {
94
+            Log.wtf(TAG, "Redirecting to GettingStarted");
95
+            Intent intent = new Intent(this, GettingStartedActivity.class);
96
+            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
97
+            startActivity(intent);
98
+        }
99
+
82 100
     }
83 101
 }

+ 0
- 137
app/src/main/java/uprrp/tania/SendLoginToServer.java View File

@@ -1,137 +0,0 @@
1
-/*************************************************************
2
- * By: Coralys Cubero Rivera
3
- * Date: 2019
4
- *************************************************************/
5
-
6
-package uprrp.tania;
7
-
8
-import android.content.Context;
9
-import android.content.Intent;
10
-import android.content.SharedPreferences;
11
-import android.content.res.Resources;
12
-import android.os.AsyncTask;
13
-import android.os.Environment;
14
-import android.util.Base64;
15
-import android.util.Log;
16
-import android.widget.Toast;
17
-
18
-import java.io.BufferedReader;
19
-import java.io.FileOutputStream;
20
-import java.io.IOException;
21
-import java.io.InputStreamReader;
22
-import java.io.OutputStreamWriter;
23
-import java.io.UnsupportedEncodingException;
24
-import java.net.URL;
25
-import java.net.URLConnection;
26
-import java.net.URLEncoder;
27
-
28
-import uprrp.tania.activities.MainActivity;
29
-
30
-public class SendLoginToServer extends AsyncTask<String, String, String> {
31
-
32
-    private static final String loginBaseURL = "https://tania.uprrp.edu/recoverAccount.php";
33
-    private Context context;
34
-
35
-    public SendLoginToServer(Context context){
36
-        this.context = context.getApplicationContext();
37
-    }
38
-
39
-    @Override
40
-    protected String doInBackground(String... strings) {
41
-
42
-        String json  = null;
43
-        try {
44
-            json = URLEncoder.encode("data", "UTF-8") + "=" + URLEncoder.encode(strings[0], "UTF-8");
45
-            Log.d("RECOVER ACCOUNT", json);
46
-        } catch (UnsupportedEncodingException e) {
47
-            Log.e("RECOVER ACCOUNT ERROR", e.getMessage());
48
-        }
49
-
50
-        String text = "";
51
-        BufferedReader reader = null;
52
-
53
-        // Send data
54
-        try
55
-        {
56
-            // Defined URL  where to send data
57
-            URL url = new URL(loginBaseURL);
58
-
59
-            // Send POST data request
60
-            URLConnection conn = url.openConnection();
61
-            conn.setDoOutput(true);
62
-            OutputStreamWriter wr = new OutputStreamWriter(conn.getOutputStream());
63
-            assert json != null;
64
-            wr.write(json);
65
-            wr.flush();
66
-
67
-            // Get the server response
68
-            reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
69
-            StringBuilder sb = new StringBuilder();
70
-            String line;
71
-
72
-            // Read Server Response
73
-            while((line = reader.readLine()) != null)
74
-            {
75
-                // Append server response in string
76
-                sb.append(line).append("\n");
77
-            }
78
-
79
-            text = sb.toString();
80
-        }
81
-        catch(Exception ex) {
82
-            Log.e("RECOVER ACCOUNT ERROR", ex.getMessage());
83
-        }
84
-        finally
85
-        {
86
-            try
87
-            {
88
-//                assert reader != null;
89
-                reader.close();
90
-            }
91
-            catch(Exception ex) {
92
-                Log.e("RECOVER ACCOUNT ERROR", ex.getMessage());
93
-            }
94
-        }
95
-
96
-        return text;
97
-
98
-    }
99
-
100
-    @Override
101
-    protected void onPostExecute(String s) {
102
-        Log.d("RECOVER ACCOUNT RESPOND", "The server's response is: " + s);
103
-
104
-        String se = s.substring(0, 5);
105
-        if (!se.equals("Error")) {
106
-
107
-            try {
108
-
109
-                FileOutputStream consentForm = new FileOutputStream(Environment.getExternalStorageDirectory().getPath() + "/consent-tania-app.pdf");
110
-
111
-                byte[] consentBytes = Base64.decode(s, Base64.NO_WRAP);
112
-                consentForm.write(consentBytes);
113
-                consentForm.close();
114
-
115
-                SharedPreferences prefs = context.getSharedPreferences("prefs", Context.MODE_PRIVATE);
116
-                SharedPreferences.Editor editor = prefs.edit();
117
-                editor.putBoolean("needsToRegister", false);
118
-                editor.apply();
119
-
120
-                Intent intent = new Intent(context, MainActivity.class);
121
-                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
122
-                context.startActivity(intent);
123
-
124
-            } catch (IOException e) {
125
-                Log.e("RECOVER CONSENT LOGIN", "File not found!");
126
-            }
127
-        }
128
-
129
-        else
130
-            {
131
-                Toast.makeText(context, "Can't recover account! Try again later. ", Toast.LENGTH_LONG).show();
132
-            }
133
-        }
134
-
135
-
136
-
137
-}

+ 135
- 0
app/src/main/java/uprrp/tania/activities/AccountRecoveryActivity.java View File

@@ -0,0 +1,135 @@
1
+package uprrp.tania.activities;
2
+
3
+import android.app.ProgressDialog;
4
+import android.content.Context;
5
+import android.content.Intent;
6
+import android.content.SharedPreferences;
7
+import android.os.Bundle;
8
+import android.os.Environment;
9
+import android.util.Base64;
10
+import android.util.Log;
11
+import android.view.View;
12
+import android.widget.Button;
13
+import android.widget.EditText;
14
+import android.widget.Toast;
15
+
16
+import androidx.appcompat.app.AppCompatActivity;
17
+
18
+import java.io.FileNotFoundException;
19
+import java.io.FileOutputStream;
20
+import java.io.IOException;
21
+
22
+import uprrp.tania.GlobalValues;
23
+import uprrp.tania.R;
24
+import uprrp.tania.networking.SendAccountRecovery;
25
+import uprrp.tania.utils.URLEventListener;
26
+
27
+public class AccountRecoveryActivity extends AppCompatActivity {
28
+
29
+    private static final String TAG = "AccountRecoveryActivity";
30
+
31
+    @Override
32
+    protected void onCreate(Bundle savedInstanceState) {
33
+
34
+        // Start constructor
35
+        super.onCreate(savedInstanceState);
36
+        setContentView(R.layout.activity_account_recovery);
37
+
38
+        // Change all caps text to normal capitalization and add onClick listeners
39
+        final Button recoverButton = findViewById(R.id.recoverButton);
40
+        final Button forgotPasswordButton = findViewById(R.id.forgotPasswordButton);
41
+        recoverButton.setTransformationMethod(null); // TODO: this is a workaround I found, any other acceptable solution is welcome
42
+        forgotPasswordButton.setTransformationMethod(null); // TODO: this is a workaround I found, any other acceptable solution is welcome
43
+        recoverButton.setOnClickListener(new View.OnClickListener() {
44
+            @Override
45
+            public void onClick(View v) {
46
+                sendAccountRecoveryRequest();
47
+            }
48
+        });
49
+        forgotPasswordButton.setOnClickListener(new View.OnClickListener() {
50
+            @Override
51
+            public void onClick(View v) {
52
+                Intent intent = new Intent(AccountRecoveryActivity.this, ForgotPasswordActivity.class);
53
+                startActivity(intent);
54
+            }
55
+        });
56
+
57
+    }
58
+
59
+    private void sendAccountRecoveryRequest() {
60
+
61
+        final EditText emailText = findViewById(R.id.emailTextRecover);
62
+        final EditText passwordText = findViewById(R.id.passwordTextRecover);
63
+
64
+        // Email and password are needed (make sure user knows); else, proceed
65
+        if(emailText.getText().toString().equals("") || passwordText.getText().toString().equals("")) {
66
+            Toast.makeText(AccountRecoveryActivity.this, "All fields are needed!", Toast.LENGTH_LONG).show();
67
+        } else {
68
+
69
+            // Initiate progress dialog
70
+            // TODO: find substitute for this deprecated dialog box
71
+            final ProgressDialog progressDialog = ProgressDialog.show(AccountRecoveryActivity.this,
72
+                    "Recovering Account",
73
+                    "This shouldn't take long");
74
+
75
+            // Send request to server
76
+            SendAccountRecovery accountRecoveryTask = new SendAccountRecovery(new URLEventListener() {
77
+
78
+                @Override
79
+                public void onSuccess(String response) {
80
+
81
+                    progressDialog.dismiss();
82
+                    restoreConsentForm(response);
83
+
84
+                    // Change user preferences to reflect login
85
+                    Context context = AccountRecoveryActivity.this;
86
+                    SharedPreferences prefs = context.getSharedPreferences("prefs", Context.MODE_PRIVATE);
87
+                    SharedPreferences.Editor editor = prefs.edit();
88
+                    editor.putBoolean("needsToRegister", false);
89
+                    editor.apply();
90
+
91
+                    // Start MainActivity
92
+                    Intent intent = new Intent(context, MainActivity.class);
93
+                    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
94
+                    context.startActivity(intent);
95
+                    Toast.makeText(getApplicationContext(), "Login successful!", Toast.LENGTH_LONG).show();
96
+
97
+                }
98
+
99
+                @Override
100
+                public void onFailure(Exception e) {
101
+                    progressDialog.dismiss();
102
+                    Toast.makeText(AccountRecoveryActivity.this, "Couldn't recover account!\nTry again later with the correct credentials...", Toast.LENGTH_LONG).show();
103
+                    Log.e(TAG, "Error occurred while sending account recovery request to server...");
104
+                    e.printStackTrace();
105
+                }
106
+
107
+            });
108
+
109
+            // Start task
110
+            String deviceToken = GlobalValues.getInstance().getDeviceToken();
111
+            String email = emailText.getText().toString();
112
+            String password = passwordText.getText().toString();
113
+            accountRecoveryTask.execute(deviceToken, email, password);
114
+
115
+        }
116
+
117
+    }
118
+
119
+    // TODO: IO should be moved to a background task
120
+    private void restoreConsentForm(String response) {
121
+        try {
122
+            byte[] consentBytes = Base64.decode(response, Base64.NO_WRAP);
123
+            FileOutputStream consentForm = new FileOutputStream(Environment.getExternalStorageDirectory().getPath() + getString(R.string.consentFileName));
124
+            consentForm.write(consentBytes);
125
+            consentForm.close();
126
+        } catch (FileNotFoundException e) {
127
+            Log.e(TAG, "Couldn't find consent form (we were going to write to it)!");
128
+            e.printStackTrace();
129
+        } catch (IOException e) {
130
+            Log.e(TAG, "Couldn't rewrite consent form!");
131
+            e.printStackTrace();
132
+        }
133
+    }
134
+
135
+}

+ 17
- 7
app/src/main/java/uprrp/tania/activities/ExperienceRegistrationActivity.java View File

@@ -3,6 +3,7 @@ package uprrp.tania.activities;
3 3
 import android.app.ProgressDialog;
4 4
 import android.content.Context;
5 5
 import android.content.Intent;
6
+import android.content.SharedPreferences;
6 7
 import android.net.Uri;
7 8
 import android.os.Bundle;
8 9
 import android.util.Log;
@@ -19,13 +20,13 @@ import java.util.Observer;
19 20
 
20 21
 import uprrp.tania.GlobalValues;
21 22
 import uprrp.tania.R;
22
-import uprrp.tania.URLEventListener;
23
+import uprrp.tania.utils.URLEventListener;
23 24
 import uprrp.tania.networking.SendExperienceRegistration;
24 25
 
25 26
 public class ExperienceRegistrationActivity  extends AppCompatActivity implements Observer {
26 27
 
27 28
     private static final String TAG = "ExperienceRegistrationActivity";
28
-    private String EXPERIENCE_ID;
29
+    private String EXPERIENCE_TOKEN;
29 30
 
30 31
     @Override
31 32
     protected void onCreate(@Nullable Bundle savedInstanceState) {
@@ -34,26 +35,32 @@ public class ExperienceRegistrationActivity  extends AppCompatActivity implement
34 35
         super.onCreate(savedInstanceState);
35 36
         setContentView(R.layout.activity_experience_registration);
36 37
 
37
-        // Fetch experience ID from URL (only if we launched this Activity from Browser)
38
+
39
+        // Fetch experience token from URL (only if we launched this Activity from Browser)
38 40
         Intent intent = getIntent();
39 41
         if(Intent.ACTION_VIEW.equals(intent.getAction())) {
40 42
             Uri uri = intent.getData();
41 43
             assert uri != null; // TODO: figure out if this causes crashes...
42
-            EXPERIENCE_ID = uri.getQueryParameter("id");
43
-            Log.wtf("EXPERIENCE ID", EXPERIENCE_ID);
44
+            EXPERIENCE_TOKEN = uri.getQueryParameter("id");
45
+            Log.d(TAG, "Experience Token is " + EXPERIENCE_TOKEN);
46
+        } else {
47
+            Log.wtf(TAG, "Activity started from somewhere other than the browser!");
48
+            disableInteraction();
44 49
         }
45 50
 
51
+
46 52
         // Listen for device token changes
47 53
         this.startObservingGlobals();
48 54
 
55
+
49 56
         // Disable interaction initially while token is being fetched
50 57
         if(GlobalValues.getInstance().getDeviceToken() == null) {
51
-            Log.wtf("EXPERIENCE ID", "DISABLING");
52 58
             disableInteractionTemporarily();
53 59
         } else {
54 60
             enableInteraction();
55 61
         }
56 62
 
63
+
57 64
         // Change all caps text to normal capitalization and add onClick listener
58 65
         final Button experienceRegistrationButton = findViewById(R.id.buttonEnterExperience);
59 66
         experienceRegistrationButton.setTransformationMethod(null); // TODO: this is a workaround I found, any other acceptable solution is welcome
@@ -140,7 +147,10 @@ public class ExperienceRegistrationActivity  extends AppCompatActivity implement
140 147
             }
141 148
         });
142 149
 
143
-        experienceRegistrationTask.execute(GlobalValues.getInstance().getDeviceToken(), this.EXPERIENCE_ID);
150
+        // Start task
151
+        String deviceToken = GlobalValues.getInstance().getDeviceToken();
152
+        String experienceToken = this.EXPERIENCE_TOKEN;
153
+        experienceRegistrationTask.execute(deviceToken, experienceToken);
144 154
 
145 155
         // UNCOMMENT THIS FOR TESTING (REMEMBER TO COMMENT .execute() LINE)
146 156
         /*

+ 12
- 2
app/src/main/java/uprrp/tania/activities/GettingStartedActivity.java View File

@@ -74,6 +74,15 @@ public class GettingStartedActivity extends AppCompatActivity {
74 74
         String[] permissions = { Manifest.permission.WRITE_EXTERNAL_STORAGE };
75 75
         requestPermissions(permissions, 1);
76 76
 
77
+        // If user is already logged in, go to MainActivity
78
+        SharedPreferences prefs = getSharedPreferences("prefs", MODE_PRIVATE);
79
+        boolean needsToRegister = prefs.getBoolean("needsToRegister", true);
80
+        if(!needsToRegister) {
81
+            Intent intent = new Intent(GettingStartedActivity.this, MainActivity.class);
82
+            startActivity(intent);
83
+            return;
84
+        }
85
+
77 86
         // Attach onClick listeners to buttons
78 87
         Button createAccountButton = findViewById(R.id.buttonCreateAccount);
79 88
         Button loginAccountButton = findViewById(R.id.buttonRecoverAccount);
@@ -88,7 +97,7 @@ public class GettingStartedActivity extends AppCompatActivity {
88 97
         loginAccountButton.setOnClickListener(new View.OnClickListener() {
89 98
             @Override
90 99
             public void onClick(View v) {
91
-                Intent loginAccountIntent = new Intent(GettingStartedActivity.this, LoginActivity.class);
100
+                Intent loginAccountIntent = new Intent(GettingStartedActivity.this, AccountRecoveryActivity.class);
92 101
                 startActivity(loginAccountIntent);
93 102
             }
94 103
         });
@@ -115,6 +124,7 @@ public class GettingStartedActivity extends AppCompatActivity {
115 124
 
116 125
 
117 126
     // TODO: decide which parts in this function to move to a background task
127
+    // TODO: define a model for the JSON and use Gson to encode it
118 128
     private void processConsentResult(TaskResult result) {
119 129
 
120 130
         boolean consented = (boolean) result.getStepResult(CONSENT_DOC).getResult();
@@ -328,7 +338,7 @@ public class GettingStartedActivity extends AppCompatActivity {
328 338
 
329 339
     }
330 340
 
331
-
341
+    // TODO: IO should be moved to a background task
332 342
     private String createPdf(byte[] signatureBytes, String consentDate) {
333 343
 
334 344
         try {

+ 0
- 78
app/src/main/java/uprrp/tania/activities/LoginActivity.java View File

@@ -1,78 +0,0 @@
1
-/*************************************************************
2
- * By: Coralys Cubero Rivera
3
- * Date: 2019
4
- *************************************************************/
5
-
6
-package uprrp.tania.activities;
7
-
8
-import android.content.Intent;
9
-import android.os.Bundle;
10
-import android.util.Log;
11
-import android.view.View;
12
-import android.widget.Button;
13
-import android.widget.EditText;
14
-import android.widget.Toast;
15
-
16
-import androidx.appcompat.app.AppCompatActivity;
17
-
18
-import org.json.JSONException;
19
-import org.json.JSONObject;
20
-
21
-import uprrp.tania.GlobalValues;
22
-import uprrp.tania.R;
23
-import uprrp.tania.SendLoginToServer;
24
-
25
-
26
-public class LoginActivity extends AppCompatActivity {
27
-
28
-    private JSONObject recoverAccount = new JSONObject();
29
-
30
-    @Override
31
-    protected void onCreate(Bundle savedInstanceState) {
32
-        super.onCreate(savedInstanceState);
33
-        setContentView(R.layout.activity_login);
34
-
35
-        final EditText emailText = findViewById(R.id.emailTextRecover);
36
-        final EditText passwordText = findViewById(R.id.passwordTextRecover);
37
-
38
-        final Button recoverButton = findViewById(R.id.recoverButton);
39
-        recoverButton.setOnClickListener(new View.OnClickListener() {
40
-            @Override
41
-            public void onClick(View v) {
42
-                try {
43
-
44
-                    //As long as the email and password have been provided, then we can log in
45
-                    if (!emailText.getText().toString().equals("")&& !passwordText.getText().toString().equals("")) {
46
-                        recoverAccount.put("email", emailText.getText());
47
-                        recoverAccount.put("password", passwordText.getText());
48
-                        recoverAccount.put("token", GlobalValues.getInstance().getDeviceToken());
49
-
50
-                        //Log.d("LOGIN ACCOUNT JSON", recoverAccount.toString());
51
-                        new SendLoginToServer(getApplicationContext()).execute(recoverAccount.toString());
52
-
53
-                    } else {
54
-                        Toast.makeText(LoginActivity.this, "All fields are needed to complete the login.", Toast.LENGTH_LONG).show();
55
-                    }
56
-
57
-
58
-                } catch (JSONException e) {
59
-                    Log.e("LOGIN ACCOUNT ERROR", e.getMessage());
60
-
61
-                }
62
-            }
63
-
64
-        });
65
-
66
-        //If by some chance they don't remember their password, then lets take them to the recovery activity
67
-        final Button forgotPasswordButton = findViewById(R.id.forgotPasswordButton);
68
-        forgotPasswordButton.setOnClickListener(new View.OnClickListener() {
69
-            @Override
70
-            public void onClick(View v) {
71
-
72
-                Intent needsRegisterIntent = new Intent(LoginActivity.this, ForgotPasswordActivity.class);
73
-                startActivity(needsRegisterIntent);
74
-
75
-            }
76
-        });
77
-    }
78
-}

+ 0
- 10
app/src/main/java/uprrp/tania/activities/MainActivity.java View File

@@ -31,16 +31,6 @@ public class MainActivity extends PinCodeActivity {
31 31
         setContentView(R.layout.activity_main);
32 32
 
33 33
 
34
-        // We need to know if the user has already registered, otherwise they need to do that first
35
-        SharedPreferences prefs = getSharedPreferences("prefs", MODE_PRIVATE);
36
-        boolean needsToRegister = prefs.getBoolean("needsToRegister", true);
37
-        if(needsToRegister) {
38
-            Intent needsRegisterIntent = new Intent(this, GettingStartedActivity.class);
39
-            startActivity(needsRegisterIntent);
40
-            return;
41
-        }
42
-
43
-
44 34
         // Create toolbar
45 35
         Toolbar toolbar = findViewById(R.id.toolbar);
46 36
         setSupportActionBar(toolbar);

+ 1
- 1
app/src/main/java/uprrp/tania/fragments/AssessmentsFragment.java View File

@@ -38,7 +38,7 @@ import java.util.Observer;
38 38
 
39 39
 import uprrp.tania.GlobalValues;
40 40
 import uprrp.tania.R;
41
-import uprrp.tania.URLEventListener;
41
+import uprrp.tania.utils.URLEventListener;
42 42
 import uprrp.tania.models.AnsweredAssessmentModel;
43 43
 import uprrp.tania.models.AnsweredQuestionModel;
44 44
 import uprrp.tania.models.AssessmentModel;

+ 1
- 1
app/src/main/java/uprrp/tania/fragments/WithdrawFragment.java View File

@@ -25,7 +25,7 @@ import java.util.Observer;
25 25
 
26 26
 import uprrp.tania.GlobalValues;
27 27
 import uprrp.tania.R;
28
-import uprrp.tania.URLEventListener;
28
+import uprrp.tania.utils.URLEventListener;
29 29
 import uprrp.tania.activities.GettingStartedActivity;
30 30
 import uprrp.tania.networking.SendWithdrawal;
31 31
 

+ 1
- 1
app/src/main/java/uprrp/tania/networking/FetchAssessment.java View File

@@ -18,7 +18,7 @@ import java.net.URL;
18 18
 
19 19
 import javax.net.ssl.HttpsURLConnection;
20 20
 
21
-import uprrp.tania.URLEventListener;
21
+import uprrp.tania.utils.URLEventListener;
22 22
 import uprrp.tania.models.AssessmentModel;
23 23
 import uprrp.tania.models.EmptyAssessmentModel;
24 24
 

+ 1
- 1
app/src/main/java/uprrp/tania/networking/FetchUserStatus.java View File

@@ -19,7 +19,7 @@ import java.net.URL;
19 19
 
20 20
 import javax.net.ssl.HttpsURLConnection;
21 21
 
22
-import uprrp.tania.URLEventListener;
22
+import uprrp.tania.utils.URLEventListener;
23 23
 import uprrp.tania.models.EmptyUserStatusModel;
24 24
 import uprrp.tania.models.UserStatusModel;
25 25
 

+ 151
- 0
app/src/main/java/uprrp/tania/networking/SendAccountRecovery.java View File

@@ -0,0 +1,151 @@
1
+package uprrp.tania.networking;
2
+
3
+import android.os.AsyncTask;
4
+import android.util.Log;
5
+
6
+import org.json.JSONException;
7
+import org.json.JSONObject;
8
+
9
+import java.io.BufferedReader;
10
+import java.io.InputStreamReader;
11
+import java.io.OutputStreamWriter;
12
+import java.io.UnsupportedEncodingException;
13
+import java.net.URL;
14
+import java.net.URLConnection;
15
+import java.net.URLEncoder;
16
+
17
+import uprrp.tania.utils.URLEventListener;
18
+
19
+public class SendAccountRecovery extends AsyncTask<String, String, String> {
20
+
21
+    private static final String TAG = "SendAccountRecovery";
22
+    private static final String loginBaseURL = "https://tania.uprrp.edu/recoverAccount.php";
23
+    private final URLEventListener myCallback;
24
+
25
+    public SendAccountRecovery(URLEventListener callback) {
26
+        this.myCallback = callback;
27
+    }
28
+
29
+    private boolean validInputs(String... strings) {
30
+
31
+        if(strings.length != 3) {
32
+            Log.e(TAG, "Invalid string array length!");
33
+            return false;
34
+        }
35
+
36
+        String deviceToken = strings[0];
37
+        String email = strings[1];
38
+        String password = strings[2];
39
+
40
+        if(email == null) {
41
+            Log.e(TAG, "Encountered null email!");
42
+            return false;
43
+        } else if (deviceToken == null) {
44
+            Log.e(TAG, "Encountered null device token!");
45
+            return false;
46
+        } else if (password == null) {
47
+            Log.e(TAG, "Encountered null password!");
48
+            return false;
49
+        }
50
+
51
+        return true;
52
+
53
+    }
54
+
55
+    // TODO: instead of making a normal POST request with
56
+    //  the body data=<JSON>, we should just send the JSON itself
57
+    //  This is adding unnecessary layers of complexity when decoding AND encoding
58
+    /*
59
+        JSON format:
60
+        {
61
+            "email": String,
62
+            "password": String,
63
+            "token": String,
64
+        }
65
+    */
66
+    @Override
67
+    protected String doInBackground(String... strings) {
68
+
69
+        // Validation
70
+        if(!validInputs(strings)) {
71
+            Log.e(TAG, "Invalid inputs given!");
72
+            return null;
73
+        }
74
+
75
+        // Extract variables
76
+        String deviceToken = strings[0];
77
+        String email = strings[1];
78
+        String password = strings[2];
79
+
80
+        try {
81
+
82
+            // Create JSON
83
+            JSONObject accountRecoveryJSON = new JSONObject();
84
+            accountRecoveryJSON.put("email", email);
85
+            accountRecoveryJSON.put("password", password);
86
+            accountRecoveryJSON.put("token", deviceToken);
87
+            Log.d(TAG, "RecoveryJSON: " + accountRecoveryJSON.toString());
88
+
89
+            // Encode data
90
+            String encodedRequestBody = URLEncoder.encode("data", "UTF-8") + "=" + URLEncoder.encode(accountRecoveryJSON.toString(), "UTF-8");
91
+
92
+            // Send POST data request
93
+            URL url = new URL(loginBaseURL);
94
+            URLConnection conn = url.openConnection();
95
+            conn.setDoOutput(true);
96
+            OutputStreamWriter wr = new OutputStreamWriter(conn.getOutputStream());
97
+            wr.write(encodedRequestBody);
98
+            wr.flush();
99
+
100
+            // Get the server response
101
+            BufferedReader serverReader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
102
+            StringBuilder serverResponse = new StringBuilder();
103
+
104
+            String line = "";
105
+            while(line != null) {
106
+                serverResponse.append(line);
107
+                line = serverReader.readLine();
108
+            }
109
+
110
+            String response = serverResponse.toString();
111
+            Log.d(TAG, "The server's response is: " + response);
112
+            if(response.contains("Error")) {
113
+                return null;
114
+            } else {
115
+                return response;
116
+            }
117
+
118
+        } catch (JSONException e) {
119
+            Log.e(TAG, "Couldn't prepare accountRecoveryJSON!");
120
+            e.printStackTrace();
121
+            return null;
122
+        } catch (UnsupportedEncodingException e) {
123
+            Log.e(TAG, "Couldn't encode accountRecoveryJSON!");
124
+            e.printStackTrace();
125
+            return null;
126
+        } catch(Exception e) {
127
+            Log.e(TAG, "Couldn't communicate with server while recovering account!");
128
+            e.printStackTrace();
129
+            return null;
130
+        }
131
+
132
+    }
133
+
134
+    @Override
135
+    protected void onPostExecute(String response) {
136
+
137
+        if(this.myCallback == null) {
138
+            Log.e(TAG, "Callback wasn't initialized first!");
139
+            return;
140
+        }
141
+
142
+        if(response == null) {
143
+            this.myCallback.onFailure(new Exception("Error occurred during transaction!"));
144
+            return;
145
+        }
146
+
147
+        this.myCallback.onSuccess(response);
148
+
149
+    }
150
+
151
+}

+ 1
- 1
app/src/main/java/uprrp/tania/networking/SendAnswers.java View File

@@ -18,7 +18,7 @@ import java.net.URLEncoder;
18 18
 
19 19
 import javax.net.ssl.HttpsURLConnection;
20 20
 
21
-import uprrp.tania.URLEventListener;
21
+import uprrp.tania.utils.URLEventListener;
22 22
 import uprrp.tania.models.AnsweredAssessmentModel;
23 23
 
24 24
 public class SendAnswers extends AsyncTask<AnsweredAssessmentModel, Void, String> {

+ 30
- 9
app/src/main/java/uprrp/tania/networking/SendExperienceRegistration.java View File

@@ -15,7 +15,7 @@ import java.net.URLEncoder;
15 15
 
16 16
 import javax.net.ssl.HttpsURLConnection;
17 17
 
18
-import uprrp.tania.URLEventListener;
18
+import uprrp.tania.utils.URLEventListener;
19 19
 
20 20
 public class SendExperienceRegistration extends AsyncTask<String, String, String> {
21 21
 
@@ -27,6 +27,28 @@ public class SendExperienceRegistration extends AsyncTask<String, String, String
27 27
         this.myCallback = callback;
28 28
     }
29 29
 
30
+    private boolean validInputs(String... strings) {
31
+
32
+        if(strings.length != 2) {
33
+            Log.e(TAG, "Invalid string array length!");
34
+            return false;
35
+        }
36
+
37
+        String deviceToken = strings[0];
38
+        String experienceID = strings[1];
39
+
40
+        if(experienceID == null) {
41
+            Log.e(TAG, "Encountered null experience ID!");
42
+            return false;
43
+        } else if (deviceToken == null) {
44
+            Log.e(TAG, "Encountered null device token!");
45
+            return false;
46
+        }
47
+
48
+        return true;
49
+
50
+    }
51
+
30 52
     // TODO: instead of making a normal POST request with
31 53
     //  the body data=<JSON>, we should just send the JSON itself
32 54
     //  This is adding unnecessary layers of complexity when decoding AND encoding
@@ -40,17 +62,16 @@ public class SendExperienceRegistration extends AsyncTask<String, String, String
40 62
     @Override
41 63
     protected String doInBackground(String... strings) {
42 64
 
43
-        String deviceToken = strings[0];
44
-        String experienceID = strings[1];
45
-
46
-        if(experienceID == null) {
47
-            Log.e(TAG, "Encountered null experience ID!");
48
-            return null;
49
-        } else if (deviceToken == null) {
50
-            Log.e(TAG, "Encountered null device token!");
65
+        // Validation
66
+        if(!validInputs(strings)) {
67
+            Log.e(TAG, "Invalid inputs given!");
51 68
             return null;
52 69
         }
53 70
 
71
+        // Extract variables
72
+        String deviceToken = strings[0];
73
+        String experienceID = strings[1];
74
+
54 75
         try {
55 76
 
56 77
             // Create JSON

+ 1
- 1
app/src/main/java/uprrp/tania/networking/SendWithdrawal.java View File

@@ -18,7 +18,7 @@ import java.nio.charset.StandardCharsets;
18 18
 
19 19
 import javax.net.ssl.HttpsURLConnection;
20 20
 
21
-import uprrp.tania.URLEventListener;
21
+import uprrp.tania.utils.URLEventListener;
22 22
 
23 23
 public class SendWithdrawal extends AsyncTask<String, String, String> {
24 24
 

app/src/main/java/uprrp/tania/URLEventListener.java → app/src/main/java/uprrp/tania/utils/URLEventListener.java View File

@@ -1,10 +1,11 @@
1
-package uprrp.tania;
1
+package uprrp.tania.utils;
2 2
 
3 3
 import uprrp.tania.models.AssessmentModel;
4 4
 import uprrp.tania.models.UserStatusModel;
5 5
 
6 6
 public class URLEventListener {
7 7
     public void onSuccess() {}
8
+    public void onSuccess(String response) {}
8 9
     public void onSuccess(AssessmentModel assessment) {}
9 10
     public void onSuccess(UserStatusModel userStatus) {}
10 11
     public void onFailure(Exception e) {}

app/src/main/res/layout/activity_login.xml → app/src/main/res/layout/activity_account_recovery.xml View File


+ 2
- 2
app/src/main/res/layout/activity_consent_pdf_viewer.xml View File

@@ -24,7 +24,7 @@
24 24
         android:id="@+id/appBarLayout"
25 25
         android:layout_width="match_parent"
26 26
         android:layout_height="61dp"
27
-        android:theme="@style/Theme.MarleApp.AppBarOverlay"
27
+        android:theme="@style/Theme.TANIA.AppBarOverlay"
28 28
         app:layout_constraintEnd_toEndOf="parent"
29 29
         app:layout_constraintStart_toStartOf="parent"
30 30
         app:layout_constraintTop_toTopOf="parent">
@@ -34,7 +34,7 @@
34 34
             android:layout_width="match_parent"
35 35
             android:layout_height="match_parent"
36 36
             android:background="?attr/colorPrimary"
37
-            app:popupTheme="@style/Theme.MarleApp.PopupOverlay" />
37
+            app:popupTheme="@style/Theme.TANIA.PopupOverlay" />
38 38
 
39 39
     </com.google.android.material.appbar.AppBarLayout>
40 40
 

+ 1
- 1
app/src/main/res/values/strings.xml View File

@@ -61,6 +61,7 @@
61 61
     <!--  Getting Started Activity  -->
62 62
     <string name="createAccountButtonText">Join the Study</string>
63 63
     <string name="recoverAccountButtonText">Login</string>
64
+    <string name="bubbleDescription">Just a blue bubble for decoration</string>
64 65
     <string name="overviewTitleText">Welcome</string>
65 66
     <string name="overviewConsentSectionSummaryText">You have been invited to participate in this study whose objectives are (1) to develop and demonstrate the utility of a mobile application (TANIA) to collect perception data of students participating in research experiences and (2) to use TANIA to determine the sources of self-efficacy that lead to career exploration and decision-making in undergraduate students.</string>
66 67
     <string name="overviewConsentSectionContentText">This study is been carried out under the supervision of Dr. Juan S. Ramírez Lugo, Department of Biology and Dr. Carlos Corrada Bravo, Department of Computer Sciences at the University of Puerto Rico, Río Piedras Campus. You were selected to participate in this study because you are enrolled in a course that offers a research experience or you voluntarily participate in research with a professor affiliated to the Río Piedras Campus.</string>
@@ -77,5 +78,4 @@
77 78
     <string name="dataUseConsentSectionSummaryText">The data obtained will be used to improve academic offerings and research experiences. The results of this study may be part of a scientific publication on science education strategies and will serve as a basis to improve the teaching curriculum.</string>
78 79
     <string name="dataUseConsentSectionContentText">It may be used to develop proposals for obtaining external funds for research. The officials of the Río Piedras Campus of the University of Puerto Rico and / or federal agencies responsible for ensuring the integrity of the research may require the researcher to prove the data obtained in this study, including this informed consent. The information handled by your device can be intervened or revised by third parties. These people can be people with legitimate or illegitimate access to the device and its content such as a family member, employer, hackers, intruders, etc. In addition, the device that you use may keep track of the information you access or send over the Internet.</string>
79 80
     <string name="generalTitleText">General</string>
80
-    <string name="bubbleDescription">Just a blue bubble for decoration</string>
81 81
 </resources>

+ 20
- 20
app/src/main/res/values/styles.xml View File

@@ -1,76 +1,76 @@
1 1
 <resources>
2 2
 
3 3
     <!-- Base application theme. -->
4
-    <style name="Theme.MarleApp" parent="Theme.Backbone">
4
+    <style name="Theme.TANIA" parent="Theme.Backbone">
5 5
         <!-- Customize your theme here. -->
6 6
         <item name="colorPrimary">@color/colorPrimary</item>
7 7
         <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
8 8
         <item name="colorAccent">@color/colorAccent</item>
9
-        <item name="alertDialogTheme">@style/Theme.MarleApp.Dialog</item>
10
-        <item name="toolbarTheme">@style/Theme.MarleApp.Toolbar</item>
9
+        <item name="alertDialogTheme">@style/Theme.TANIA.Dialog</item>
10
+        <item name="toolbarTheme">@style/Theme.TANIA.Toolbar</item>
11 11
         <item name="android:textColorSecondary">@color/textColor1</item>
12 12
     </style>
13 13
 
14
-    <style name="Theme.MarleApp.Survey">
15
-        <item name="toolbarTheme">@style/Theme.MarleApp.Toolbar.Transparent</item>
14
+    <style name="Theme.TANIA.Survey">
15
+        <item name="toolbarTheme">@style/Theme.TANIA.Toolbar.Transparent</item>
16 16
         <item name="android:windowBackground">@android:color/white</item>
17 17
         <item name="colorPrimaryDark">@color/dark_gray</item>
18 18
         <item name="android:windowContentOverlay">@null</item>
19 19
     </style>
20 20
 
21
-    <style name="Theme.MarleApp.Toolbar.Transparent">
21
+    <style name="Theme.TANIA.Toolbar.Transparent">
22 22
         <item name="colorControlNormal">@color/rsb_warm_gray</item>
23 23
         <item name="colorPrimary">@android:color/white</item>
24
-        <item name="toolbarStyle">@style/Widget.MarleApp.Toolbar.Transparent</item>
24
+        <item name="toolbarStyle">@style/Widget.TANIA.Toolbar.Transparent</item>
25 25
     </style>
26 26
 
27
-    <style name="Theme.MarleApp.Dialog" parent="Theme.AppCompat.Light.Dialog.Alert">
27
+    <style name="Theme.TANIA.Dialog" parent="Theme.AppCompat.Light.Dialog.Alert">
28 28
         <item name="colorAccent">@color/colorAccent</item>
29 29
         <item name="android:textColorPrimary">@color/rsb_warm_gray</item>
30 30
         <item name="android:background">@android:color/white</item>
31 31
     </style>
32 32
 
33
-    <style name="Theme.MarleApp.Toolbar">
33
+    <style name="Theme.TANIA.Toolbar">
34 34
         <item name="colorControlNormal">@android:color/white</item>
35
-        <item name="toolbarStyle">@style/Widget.MarleApp.Toolbar</item>
35
+        <item name="toolbarStyle">@style/Widget.TANIA.Toolbar</item>
36 36
     </style>
37 37
 
38
-    <style name="Base.Widget.MarleApp.Toolbar" parent="@style/Widget.AppCompat.Toolbar">
38
+    <style name="Base.Widget.TANIA.Toolbar" parent="@style/Widget.AppCompat.Toolbar">
39 39
         <item name="android:background">?attr/colorPrimary</item>
40 40
         <item name="android:minHeight">56dp</item>
41
-        <item name="titleTextAppearance">@style/TextAppearance.Widget.MarleApp.Toolbar.Title</item>
41
+        <item name="titleTextAppearance">@style/TextAppearance.Widget.TANIA.Toolbar.Title</item>
42 42
     </style>
43 43
 
44
-    <style name="TextAppearance.Widget.MarleApp.Toolbar.Title" parent="@style/TextAppearance.Widget.AppCompat.Toolbar.Title">
44
+    <style name="TextAppearance.Widget.TANIA.Toolbar.Title" parent="@style/TextAppearance.Widget.AppCompat.Toolbar.Title">
45 45
         <item name="android:textColor">@color/textColor1</item>
46 46
         <item name="android:textSize">20sp</item>
47 47
     </style>
48 48
 
49
-    <style name="TextAppearance.Widget.MarleApp.Toolbar.Title.Transparent">
49
+    <style name="TextAppearance.Widget.TANIA.Toolbar.Title.Transparent">
50 50
         <item name="android:textColor">@color/textColor1</item>
51 51
     </style>
52 52
 
53
-    <style name="Widget.MarleApp.Toolbar" parent="@style/Base.Widget.MarleApp.Toolbar">
53
+    <style name="Widget.TANIA.Toolbar" parent="@style/Base.Widget.TANIA.Toolbar">
54 54
         <item name="android:elevation">4dp</item>
55 55
         <item name="android:outlineProvider">bounds</item>
56 56
     </style>
57 57
 
58
-    <style name="Widget.MarleApp.Toolbar.Transparent" parent="@style/Base.Widget.MarleApp.Toolbar">
58
+    <style name="Widget.TANIA.Toolbar.Transparent" parent="@style/Base.Widget.TANIA.Toolbar">
59 59
         <item name="android:elevation">0dp</item>
60 60
         <item name="android:outlineProvider">none</item>
61 61
         <item name="titleTextAppearance">
62
-            @style/TextAppearance.Widget.MarleApp.Toolbar.Title.Transparent
62
+            @style/TextAppearance.Widget.TANIA.Toolbar.Title.Transparent
63 63
         </item>
64 64
     </style>
65 65
 
66
-    <style name="Theme.MarleApp.NoActionBar">
66
+    <style name="Theme.TANIA.NoActionBar">
67 67
         <item name="windowActionBar">false</item>
68 68
         <item name="windowNoTitle">true</item>
69 69
     </style>
70 70
 
71
-    <style name="Theme.MarleApp.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar" />
71
+    <style name="Theme.TANIA.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar" />
72 72
 
73
-    <style name="Theme.MarleApp.PopupOverlay" parent="ThemeOverlay.AppCompat.Light" />
73
+    <style name="Theme.TANIA.PopupOverlay" parent="ThemeOverlay.AppCompat.Light" />
74 74
 
75 75
 
76 76
 </resources>