finished network layer, some ui changes

This commit is contained in:
aj 2020-02-01 16:37:10 +00:00
parent d3bff0333c
commit 6385aac6b2
25 changed files with 708 additions and 176 deletions

View File

@ -6,7 +6,7 @@ android {
buildToolsVersion "29.0.2" buildToolsVersion "29.0.2"
defaultConfig { defaultConfig {
applicationId "com.example.applogin" applicationId "com.example.applogin"
minSdkVersion 15 minSdkVersion 16
targetSdkVersion 29 targetSdkVersion 29
versionCode 1 versionCode 1
versionName "1.0" versionName "1.0"
@ -22,14 +22,13 @@ android {
dependencies { dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar']) implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'androidx.appcompat:appcompat:1.0.2' implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'com.google.android.material:material:1.0.0' implementation 'com.google.android.material:material:1.0.0'
implementation 'androidx.annotation:annotation:1.0.2' implementation 'androidx.annotation:annotation:1.1.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3' implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation 'androidx.lifecycle:lifecycle-extensions:2.0.0' implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
implementation 'com.google.firebase:firebase-messaging:17.3.4' implementation 'com.google.firebase:firebase-messaging:20.1.0'
testImplementation 'junit:junit:4.12' testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.0' androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1' androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
implementation 'com.android.volley:volley:1.1.1'
} }

View File

@ -14,6 +14,14 @@
} }
}, },
"oauth_client": [ "oauth_client": [
{
"client_id": "151349644451-8jsl5et8sopsa1l4tmnak31cumrr9u3b.apps.googleusercontent.com",
"client_type": 1,
"android_info": {
"package_name": "com.example.applogin",
"certificate_hash": "e1a0e69f1e3d968c6e4de49ee01928f235a6801d"
}
},
{ {
"client_id": "151349644451-mnpur4ea4fv7g18h6uu9p8o5b00bs5jb.apps.googleusercontent.com", "client_id": "151349644451-mnpur4ea4fv7g18h6uu9p8o5b00bs5jb.apps.googleusercontent.com",
"client_type": 1, "client_type": 1,

View File

@ -26,10 +26,11 @@
<activity android:name=".ui.login.ConfirmationActivity" /> <activity android:name=".ui.login.ConfirmationActivity" />
<activity android:name=".WaitingActivity" /> <activity android:name=".WaitingActivity" />
<activity android:name=".JoinQueueActivity" /> <activity android:name=".JoinQueueActivity" />
<activity android:name=".FullActivity" />
<service <service
android:name="com.example.applogin.EVFirebase" android:name="com.example.applogin.EVFirebase"
android:exported="true" > android:exported="false" >
<intent-filter android:priority="-500" > <intent-filter android:priority="-500" >
<action android:name="com.google.firebase.MESSAGING_EVENT" /> <action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter> </intent-filter>

View File

@ -2,17 +2,24 @@ package com.example.applogin;
import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.app.AppCompatActivity;
import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle; import android.os.Bundle;
import android.os.CountDownTimer; import android.os.CountDownTimer;
import android.widget.TextView; import android.widget.TextView;
import java.util.Timer; import com.example.applogin.model.User;
import com.example.applogin.network.GetUserTask;
import com.example.applogin.ui.login.ConfirmationActivity;
import java.util.concurrent.ExecutionException;
public class ChargingActivity extends AppCompatActivity { public class ChargingActivity extends AppCompatActivity {
TextView coundownTime; TextView coundownTime;
TextView chargeState; TextView chargeState;
Thread pollingThread;
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
@ -37,7 +44,71 @@ public class ChargingActivity extends AppCompatActivity {
End_criteria(); End_criteria();
} }
}.start(); }.start();
final SharedPreferences preferences = getApplicationContext().getSharedPreferences("scheduler_preferences", Context.MODE_PRIVATE);
final long timeInterval = 2000;
Runnable runnable = new Runnable() {
public void run() {
boolean changed = false;
while (!changed) {
GetUserTask task = new GetUserTask(preferences.getString("api_key", null));
task.execute();
try {
User user = task.get();
Intent intent;
switch(user.getState()){
case inactive:
intent = new Intent(ChargingActivity.this, JoinQueueActivity.class);
startActivity(intent);
changed = true;
break;
case in_queue:
intent = new Intent(ChargingActivity.this, WaitingActivity.class);
startActivity(intent);
changed = true;
break;
case assigned:
intent = new Intent(ChargingActivity.this, ConfirmationActivity.class);
startActivity(intent);
changed = true;
break;
case connected_full:
intent = new Intent(ChargingActivity.this, FullActivity.class);
startActivity(intent);
changed = true;
break;
} }
} catch (ExecutionException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
Thread.sleep(timeInterval);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
pollingThread = new Thread(runnable);
pollingThread.start();
}
@Override
protected void onDestroy() {
super.onDestroy();
if(pollingThread.isAlive()){
pollingThread.interrupt();
}
}
//Move vehicle if timer runs out or the car is full (need to add the car full situation) //Move vehicle if timer runs out or the car is full (need to add the car full situation)
private void End_criteria() private void End_criteria()
{ {

View File

@ -1,28 +1,27 @@
package com.example.applogin; package com.example.applogin;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context; import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.os.Build;
import android.widget.Toast; import android.widget.Toast;
import com.android.volley.AuthFailureError; import androidx.annotation.NonNull;
import com.android.volley.Request; import androidx.core.app.NotificationCompat;
import com.android.volley.RequestQueue;
import com.android.volley.Response; import com.example.applogin.network.UpdateNotificationTask;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.JsonObjectRequest;
import com.android.volley.toolbox.Volley;
import com.google.firebase.messaging.FirebaseMessagingService; import com.google.firebase.messaging.FirebaseMessagingService;
import com.google.firebase.messaging.RemoteMessage;
import org.json.JSONObject; import java.util.concurrent.ExecutionException;
import java.util.HashMap;
import java.util.Map;
public class EVFirebase extends FirebaseMessagingService { public class EVFirebase extends FirebaseMessagingService {
@Override @Override
public void onNewToken(String token) { public void onNewToken(String token) {
// If you want to send messages to this application instance or // If you want to send messages to this application instance or
// manage this apps subscriptions on the server side, send the // manage this apps subscriptions on the server side, send the
// Instance ID token to your app server. // Instance ID token to your app server.
@ -32,41 +31,43 @@ public class EVFirebase extends FirebaseMessagingService {
public void sendRegistrationToServer(String token){ public void sendRegistrationToServer(String token){
// Instantiate the RequestQueue. SharedPreferences preferences = getApplicationContext().getSharedPreferences("scheduler_preferences", Context.MODE_PRIVATE);
RequestQueue queue = Volley.newRequestQueue(this);
String url ="https://ev-scheduler.appspot.com/api/user";
HashMap<String, String> dict = new HashMap<>(); UpdateNotificationTask task = new UpdateNotificationTask(token, preferences.getString("api_key", null));
dict.put("notification_token", token);
JSONObject json = new JSONObject(dict);
// Request a string response from the provided URL. task.execute();
final JsonObjectRequest stringRequest = new JsonObjectRequest(Request.Method.PUT, url, json,
new Response.Listener<JSONObject>() { try {
@Override if(!task.get()){
public void onResponse(JSONObject response) { Toast.makeText(EVFirebase.this, "error sending notification token", Toast.LENGTH_SHORT).show();
}else{
Toast.makeText(EVFirebase.this, "notification sent", Toast.LENGTH_SHORT).show();
}
} catch (ExecutionException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
} }
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
Toast.makeText(EVFirebase.this, Integer.toString(error.networkResponse.statusCode), Toast.LENGTH_SHORT).show();
}
}){
@Override @Override
public Map<String, String> getHeaders() throws AuthFailureError { public void onMessageReceived(@NonNull RemoteMessage remoteMessage) {
super.onMessageReceived(remoteMessage);
HashMap<String, String> headers = new HashMap<>(); Intent intent = new Intent(this, JoinQueueActivity.class);
SharedPreferences context = getApplicationContext().getSharedPreferences("scheduler_preferences", Context.MODE_PRIVATE); intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
headers.put("Authorization", "Bearer " + context.getString("api_key", "")); PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_ONE_SHOT);
return headers; String channelId = "Default";
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, channelId)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle(remoteMessage.getNotification().getTitle())
.setContentText(remoteMessage.getNotification().getBody()).setAutoCancel(true).setContentIntent(pendingIntent);;
NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel(channelId, "Scheduler", NotificationManager.IMPORTANCE_DEFAULT);
manager.createNotificationChannel(channel);
} }
manager.notify(0, builder.build());
};
} }
} }

View File

@ -0,0 +1,90 @@
package com.example.applogin;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.os.CountDownTimer;
import androidx.appcompat.app.AppCompatActivity;
import com.example.applogin.model.User;
import com.example.applogin.network.GetUserTask;
import java.util.concurrent.ExecutionException;
public class FullActivity extends AppCompatActivity {
Thread pollingThread;
CountDownTimer timer;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_full);
final SharedPreferences preferences = getApplicationContext().getSharedPreferences("scheduler_preferences", Context.MODE_PRIVATE);
final long timeInterval = 2000;
Runnable runnable = new Runnable() {
public void run() {
boolean changed = false;
while (!changed) {
GetUserTask task = new GetUserTask(preferences.getString("api_key", null));
task.execute();
try {
User user = task.get();
Intent intent;
switch(user.getState()){
case inactive:
intent = new Intent(FullActivity.this, JoinQueueActivity.class);
startActivity(intent);
changed = true;
break;
case in_queue:
intent = new Intent(FullActivity.this, WaitingActivity.class);
startActivity(intent);
changed = true;
break;
case assigned:
intent = new Intent(FullActivity.this, PluginWait_Activity.class);
startActivity(intent);
changed = true;
break;
case connected_charging:
intent = new Intent(FullActivity.this, ChargingActivity.class);
startActivity(intent);
changed = true;
break;
}
} catch (ExecutionException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
Thread.sleep(timeInterval);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
pollingThread = new Thread(runnable);
pollingThread.start();
}
@Override
protected void onDestroy() {
super.onDestroy();
if(pollingThread.isAlive()){
pollingThread.interrupt();
}
timer.cancel();
}
}

View File

@ -1,6 +1,5 @@
package com.example.applogin; package com.example.applogin;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.app.AppCompatActivity;
import android.content.Context; import android.content.Context;
@ -11,24 +10,10 @@ import android.view.View;
import android.widget.Button; import android.widget.Button;
import android.widget.Toast; import android.widget.Toast;
import com.android.volley.AuthFailureError; import com.example.applogin.model.User;
import com.android.volley.Request; import com.example.applogin.network.GetUserTask;
import com.android.volley.RequestQueue; import com.example.applogin.network.QueueTask;
import com.android.volley.Response; import java.util.concurrent.ExecutionException;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.JsonObjectRequest;
import com.android.volley.toolbox.Volley;
import com.example.applogin.ui.login.LoginActivity;
import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.Task;
import com.google.firebase.iid.FirebaseInstanceId;
import com.google.firebase.iid.InstanceIdResult;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.HashMap;
import java.util.Map;
public class JoinQueueActivity extends AppCompatActivity { public class JoinQueueActivity extends AppCompatActivity {
@ -37,69 +22,48 @@ public class JoinQueueActivity extends AppCompatActivity {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setContentView(R.layout.activity_join_queue); setContentView(R.layout.activity_join_queue);
FirebaseInstanceId.getInstance().getInstanceId()
.addOnCompleteListener(new OnCompleteListener<InstanceIdResult>() {
@Override
public void onComplete(@NonNull Task<InstanceIdResult> task) {
if (!task.isSuccessful()) {
return;
}
// Get new Instance ID token
String token = task.getResult().getToken();
// Instantiate the RequestQueue.
RequestQueue network_queue = Volley.newRequestQueue(JoinQueueActivity.this);
String url ="https://ev-scheduler.appspot.com/api/user";
HashMap<String, String> dict = new HashMap<>();
dict.put("notification_token", token);
JSONObject json = new JSONObject(dict);
// Request a string response from the provided URL.
final JsonObjectRequest stringRequest = new JsonObjectRequest(Request.Method.PUT, url, json,
new Response.Listener<JSONObject>() {
@Override
public void onResponse(JSONObject response) {
Toast.makeText(JoinQueueActivity.this, "token sent", Toast.LENGTH_SHORT).show();
}
},
new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
Toast.makeText(JoinQueueActivity.this, Integer.toString(error.networkResponse.statusCode), Toast.LENGTH_SHORT).show();
//Put error message (failed login, 3 different messages)
//if error.networkResponse.statusCode == 401 , message wrong password (auth_blueprint.py)
}
}){
@Override
public Map<String, String> getHeaders() throws AuthFailureError {
HashMap<String, String> headers = new HashMap<>();
SharedPreferences context = getApplicationContext().getSharedPreferences("scheduler_preferences", Context.MODE_PRIVATE);
headers.put("Authorization", "Bearer " + context.getString("api_key", ""));
return headers;
}
};
network_queue.add(stringRequest);
}
});
final Button joinButton = findViewById(R.id.join_queue); final Button joinButton = findViewById(R.id.join_queue);
joinButton.setOnClickListener(new View.OnClickListener() { joinButton.setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
//Toast.makeText(JoinQueueActivity.this, "testtttt", Toast.LENGTH_SHORT).show();
SharedPreferences preferences = getApplicationContext().getSharedPreferences("scheduler_preferences", Context.MODE_PRIVATE);
QueueTask task = new QueueTask("location1", preferences.getString("api_key", null));
task.execute();
try {
if (task.get()){
Intent myIntent = new Intent(JoinQueueActivity.this, WaitingActivity.class); Intent myIntent = new Intent(JoinQueueActivity.this, WaitingActivity.class);
startActivity(myIntent); startActivity(myIntent);
} }
else{
Toast.makeText(JoinQueueActivity.this, "error queueing", Toast.LENGTH_SHORT).show();
}
} catch (ExecutionException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}); });
SharedPreferences preferences = getApplicationContext().getSharedPreferences("scheduler_preferences", Context.MODE_PRIVATE);
GetUserTask task = new GetUserTask(preferences.getString("api_key", null));
task.execute();
try {
User user = task.get();
if(user.getState() != User.State.inactive){
joinButton.setEnabled(false);
}
} catch (ExecutionException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
} }
} }

View File

@ -1,5 +1,6 @@
package com.example.applogin; package com.example.applogin;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat; import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat; import androidx.core.content.ContextCompat;
@ -13,13 +14,25 @@ import android.os.Bundle;
import android.view.View; import android.view.View;
import android.widget.Button; import android.widget.Button;
import android.widget.EditText; import android.widget.EditText;
import android.widget.ProgressBar;
import android.widget.Toast; import android.widget.Toast;
import com.example.applogin.model.User;
import com.example.applogin.network.GetUserTask;
import com.example.applogin.network.LoginTask; import com.example.applogin.network.LoginTask;
import com.example.applogin.network.UpdateNotificationTask;
import com.example.applogin.ui.login.ConfirmationActivity;
import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.Task;
import com.google.firebase.iid.FirebaseInstanceId;
import com.google.firebase.iid.InstanceIdResult;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
public class Login2Activity extends AppCompatActivity { public class Login2Activity extends AppCompatActivity {
ProgressBar loading;
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
@ -45,6 +58,7 @@ public class Login2Activity extends AppCompatActivity {
final Button signInButton = findViewById(R.id.login); final Button signInButton = findViewById(R.id.login);
final EditText usernameEditText = findViewById(R.id.username); final EditText usernameEditText = findViewById(R.id.username);
final EditText passwordEditText = findViewById(R.id.password); final EditText passwordEditText = findViewById(R.id.password);
loading = findViewById(R.id.loading);
signInButton.setOnClickListener(new View.OnClickListener() { signInButton.setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
@ -78,11 +92,12 @@ public class Login2Activity extends AppCompatActivity {
private void tryLogin(String username, String password) { private void tryLogin(String username, String password) {
LoginTask task = new LoginTask(username, password); NativeLoginTask task = new NativeLoginTask(username, password);
task.execute(); task.execute();
try { try {
String result = task.get(); final String result = task.get();
if (result == null) { if (result == null) {
@ -94,8 +109,60 @@ public class Login2Activity extends AppCompatActivity {
SharedPreferences.Editor editor = context.edit(); SharedPreferences.Editor editor = context.edit();
editor.putString("api_key", result); editor.putString("api_key", result);
editor.apply(); editor.apply();
Intent myIntent = new Intent(Login2Activity.this, JoinQueueActivity.class);
startActivity(myIntent); FirebaseInstanceId.getInstance().getInstanceId()
.addOnCompleteListener(new OnCompleteListener<InstanceIdResult>() {
@Override
public void onComplete(@NonNull Task<InstanceIdResult> task) {
if (!task.isSuccessful()) {
return;
}
// Get new Instance ID token
String token = task.getResult().getToken();
UpdateNotificationTask sendToken = new UpdateNotificationTask(token, result);
sendToken.execute();
try {
if(!sendToken.get()){
Toast.makeText(Login2Activity.this, "error sending token", Toast.LENGTH_SHORT).show();
}
} catch (ExecutionException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
GetUserTask userTask = new GetUserTask(result);
userTask.execute();
User user = userTask.get();
Intent intent;
switch(user.getState()){
case inactive:
intent = new Intent(Login2Activity.this, JoinQueueActivity.class);
startActivity(intent);
break;
case in_queue:
intent = new Intent(Login2Activity.this, WaitingActivity.class);
startActivity(intent);
break;
case assigned:
intent = new Intent(Login2Activity.this, ConfirmationActivity.class);
startActivity(intent);
break;
case connected_charging:
intent = new Intent(Login2Activity.this, ChargingActivity.class);
startActivity(intent);
break;
case connected_full:
intent = new Intent(Login2Activity.this, FullActivity.class);
startActivity(intent);
break;
}
} }
} catch (ExecutionException e) { } catch (ExecutionException e) {
@ -106,5 +173,24 @@ public class Login2Activity extends AppCompatActivity {
} }
class NativeLoginTask extends LoginTask {
public NativeLoginTask(String username, String password){
super(username, password);
} }
@Override
protected void onPreExecute(){
loading.setVisibility(View.VISIBLE);
}
@Override
protected void onPostExecute(String result){
loading.setVisibility(View.INVISIBLE);
}
}
}

View File

@ -2,23 +2,34 @@ package com.example.applogin;
import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.app.AppCompatActivity;
import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle; import android.os.Bundle;
import android.os.CountDownTimer; import android.os.CountDownTimer;
import android.widget.TextView; import android.widget.TextView;
import android.widget.Toast;
import com.example.applogin.model.User;
import com.example.applogin.network.GetUserTask;
import com.example.applogin.network.KillSessionTask;
import com.example.applogin.ui.login.ConfirmationActivity; import com.example.applogin.ui.login.ConfirmationActivity;
import java.util.concurrent.ExecutionException;
public class PluginWait_Activity extends AppCompatActivity { public class PluginWait_Activity extends AppCompatActivity {
Thread pollingThread;
CountDownTimer timer;
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setContentView(R.layout.activity_plugin_wait_); setContentView(R.layout.activity_plugin_wait_);
final TextView acceptCoundown = findViewById(R.id.accept_timer); final TextView acceptCoundown = findViewById(R.id.plugin_countdown);
new CountDownTimer(900000, 1000) { timer = new CountDownTimer(900000, 1000) {
public void onTick(long millisUntilFinished) { public void onTick(long millisUntilFinished) {
int secondsLeft = (int) millisUntilFinished / 1000; int secondsLeft = (int) millisUntilFinished / 1000;
@ -29,9 +40,90 @@ public class PluginWait_Activity extends AppCompatActivity {
} }
public void onFinish() { public void onFinish() {
SharedPreferences preferences = getApplicationContext().getSharedPreferences("scheduler_preferences", Context.MODE_PRIVATE);
KillSessionTask task = new KillSessionTask("location1", "charger1", preferences.getString("api_key", null));
task.execute();
try {
if(task.get()){
Intent myIntent = new Intent(PluginWait_Activity.this, JoinQueueActivity.class); Intent myIntent = new Intent(PluginWait_Activity.this, JoinQueueActivity.class);
startActivity(myIntent); startActivity(myIntent);
}else{
Toast.makeText(PluginWait_Activity.this, "error killing session", Toast.LENGTH_SHORT).show();
}
} catch (ExecutionException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
} }
}.start(); }.start();
final SharedPreferences preferences = getApplicationContext().getSharedPreferences("scheduler_preferences", Context.MODE_PRIVATE);
final long timeInterval = 2000;
Runnable runnable = new Runnable() {
public void run() {
boolean changed = false;
while (!changed) {
GetUserTask task = new GetUserTask(preferences.getString("api_key", null));
task.execute();
try {
User user = task.get();
Intent intent;
switch(user.getState()){
case inactive:
intent = new Intent(PluginWait_Activity.this, JoinQueueActivity.class);
startActivity(intent);
changed = true;
break;
case in_queue:
intent = new Intent(PluginWait_Activity.this, WaitingActivity.class);
startActivity(intent);
changed = true;
break;
case connected_charging:
intent = new Intent(PluginWait_Activity.this, ChargingActivity.class);
startActivity(intent);
changed = true;
break;
case connected_full:
intent = new Intent(PluginWait_Activity.this, FullActivity.class);
startActivity(intent);
changed = true;
break;
}
} catch (ExecutionException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
Thread.sleep(timeInterval);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
pollingThread = new Thread(runnable);
pollingThread.start();
}
@Override
protected void onDestroy() {
super.onDestroy();
if(pollingThread.isAlive()){
pollingThread.interrupt();
}
timer.cancel();
} }
} }

View File

@ -2,20 +2,26 @@ package com.example.applogin;
import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.app.AppCompatActivity;
import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle; import android.os.Bundle;
import android.widget.Button; import android.widget.Button;
import android.widget.TextView; import android.widget.TextView;
import com.example.applogin.model.User;
import com.example.applogin.network.GetUserTask;
import com.example.applogin.ui.login.ConfirmationActivity; import com.example.applogin.ui.login.ConfirmationActivity;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.concurrent.ExecutionException;
public class WaitingActivity extends AppCompatActivity { public class WaitingActivity extends AppCompatActivity {
List<String> queue; List<String> queue;
TextView queuePosition; TextView queuePosition;
Thread pollingThread;
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
@ -28,6 +34,61 @@ public class WaitingActivity extends AppCompatActivity {
//do initial update //do initial update
UpdateQueue(); UpdateQueue();
final SharedPreferences preferences = getApplicationContext().getSharedPreferences("scheduler_preferences", Context.MODE_PRIVATE);
final long timeInterval = 2000;
Runnable runnable = new Runnable() {
public void run() {
boolean changed = false;
while (!changed) {
GetUserTask task = new GetUserTask(preferences.getString("api_key", null));
task.execute();
try {
User user = task.get();
Intent intent;
switch(user.getState()){
case inactive:
intent = new Intent(WaitingActivity.this, JoinQueueActivity.class);
startActivity(intent);
changed = true;
break;
case assigned:
intent = new Intent(WaitingActivity.this, ConfirmationActivity.class);
startActivity(intent);
changed = true;
break;
case connected_charging:
intent = new Intent(WaitingActivity.this, ChargingActivity.class);
startActivity(intent);
changed = true;
break;
case connected_full:
intent = new Intent(WaitingActivity.this, FullActivity.class);
startActivity(intent);
changed = true;
break;
}
} catch (ExecutionException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
Thread.sleep(timeInterval);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
pollingThread = new Thread(runnable);
pollingThread.start();
} }
//Need to fill in queue data, currently assuming we are first position in queue //Need to fill in queue data, currently assuming we are first position in queue
private void UpdateQueue() { private void UpdateQueue() {
@ -42,4 +103,12 @@ public class WaitingActivity extends AppCompatActivity {
startActivity(myIntent); startActivity(myIntent);
} }
} }
@Override
protected void onDestroy() {
super.onDestroy();
if(pollingThread.isAlive()){
pollingThread.interrupt();
}
}
} }

View File

@ -0,0 +1,28 @@
package com.example.applogin.network;
import java.util.HashMap;
public class KillSessionTask extends AbstractNetworkTask<Void, Boolean> {
private String api_key;
private String location_id;
private String charger_id;
public KillSessionTask(String location_id, String charger_id, String api_key){
super();
this.api_key = api_key;
this.location_id = location_id;
this.charger_id = charger_id;
}
@Override
protected Boolean doInBackground(Void... params) {
HashMap<String, String> body = new HashMap<>();
body.put("state", "available");
Result result = makeAuthenticatedRequest(getAPIUrl(String.format("api/location/%s/charger/%s", location_id, charger_id)), HTTPMethod.PUT, body, null, api_key);
return 200 <= result.statusCode && result.statusCode < 300;
}
}

View File

@ -6,8 +6,8 @@ import java.util.HashMap;
public class LoginTask extends AbstractNetworkTask<Void, String> { public class LoginTask extends AbstractNetworkTask<Void, String> {
private String username; protected String username;
private String password; protected String password;
public LoginTask(String username, String password){ public LoginTask(String username, String password){
super(); super();

View File

@ -0,0 +1,27 @@
package com.example.applogin.network;
import java.util.HashMap;
public class UpdateNotificationTask extends AbstractNetworkTask<Void, Boolean> {
private String api_key;
private String notification_key;
public UpdateNotificationTask(String notification_key, String api_key){
super();
this.notification_key = notification_key;
this.api_key = api_key;
}
@Override
protected Boolean doInBackground(Void... params) {
HashMap<String, String> body = new HashMap<>();
body.put("notification_token", notification_key);
Result result = makeAuthenticatedRequest(getAPIUrl("api/user"), HTTPMethod.PUT, body, null, api_key);
return 200 <= result.statusCode && result.statusCode < 300;
}
}

View File

@ -2,7 +2,9 @@ package com.example.applogin.ui.login;
import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.app.AppCompatActivity;
import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle; import android.os.Bundle;
import android.os.CountDownTimer; import android.os.CountDownTimer;
import android.view.View; import android.view.View;
@ -10,10 +12,12 @@ import android.widget.Button;
import android.widget.TextView; import android.widget.TextView;
import android.widget.Toast; import android.widget.Toast;
import com.example.applogin.ChargingActivity;
import com.example.applogin.JoinQueueActivity; import com.example.applogin.JoinQueueActivity;
import com.example.applogin.PluginWait_Activity;
import com.example.applogin.R; import com.example.applogin.R;
import com.example.applogin.WaitingActivity; import com.example.applogin.network.KillSessionTask;
import java.util.concurrent.ExecutionException;
public class ConfirmationActivity extends AppCompatActivity { public class ConfirmationActivity extends AppCompatActivity {
@ -33,7 +37,7 @@ public class ConfirmationActivity extends AppCompatActivity {
int minutesLeft = secondsLeft / 60; int minutesLeft = secondsLeft / 60;
secondsLeft %= 60; secondsLeft %= 60;
acceptCountdown.setText("Time Remaining: " + minutesLeft + ":" + secondsLeft); acceptCountdown.setText(minutesLeft + ":" + secondsLeft);
} }
public void onFinish() { public void onFinish() {
@ -47,7 +51,7 @@ public class ConfirmationActivity extends AppCompatActivity {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
countdownTimer.cancel(); countdownTimer.cancel();
Intent myIntent = new Intent(ConfirmationActivity.this, ChargingActivity.class); Intent myIntent = new Intent(ConfirmationActivity.this, PluginWait_Activity.class);
startActivity(myIntent); startActivity(myIntent);
} }
}); });
@ -57,8 +61,25 @@ public class ConfirmationActivity extends AppCompatActivity {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
countdownTimer.cancel(); countdownTimer.cancel();
SharedPreferences preferences = getApplicationContext().getSharedPreferences("scheduler_preferences", Context.MODE_PRIVATE);
KillSessionTask task = new KillSessionTask("location1", "charger1", preferences.getString("api_key", null));
task.execute();
try {
if(task.get()){
Intent myIntent = new Intent(ConfirmationActivity.this, JoinQueueActivity.class); Intent myIntent = new Intent(ConfirmationActivity.this, JoinQueueActivity.class);
startActivity(myIntent); startActivity(myIntent);
}else{
Toast.makeText(ConfirmationActivity.this, "error cancelling session", Toast.LENGTH_SHORT).show();
}
} catch (ExecutionException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
} }
}); });
} }

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
<corners
android:radius="14dp"/>
<solid
android:color="@color/uiGreen"/>
<padding
android:left="0dp"
android:top="0dp"
android:right="0dp"
android:bottom="0dp"/>
<size
android:width="270dp"
android:height="60dp"/>
<stroke
android:width="3dp"
android:color="#878787"/>
</shape>

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
<corners
android:radius="14dp"/>
<solid
android:color="@color/uiRed"/>
<padding
android:left="0dp"
android:top="0dp"
android:right="0dp"
android:bottom="0dp"/>
<size
android:width="270dp"
android:height="60dp"/>
<stroke
android:width="3dp"
android:color="#878787"/>
</shape>

View File

@ -18,12 +18,14 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="Car charging" android:text="Car charging"
android:textAlignment="center"
android:textSize="32dp"></TextView> android:textSize="32dp"></TextView>
<TextView <TextView
android:id="@+id/charge_time" android:id="@+id/charge_time"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="Time Remaining" android:text="Time Remaining"
android:textAlignment="center"
android:textSize="32dp"></TextView> android:textSize="32dp"></TextView>
</LinearLayout> </LinearLayout>

View File

@ -10,24 +10,29 @@
<LinearLayout <LinearLayout
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginBottom="289dp"
android:orientation="vertical" android:orientation="vertical"
android:padding="50dp"> android:padding="50dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<TextView <TextView
android:layout_width="wrap_content" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="Charging station available, accept within time remaining " android:text="Charging station available, accept within: "
android:textSize="32dp"> android:textAlignment="center"
</TextView> android:textSize="32dp"></TextView>
<TextView <TextView
android:id="@+id/accept_timer" android:id="@+id/accept_timer"
android:layout_width="wrap_content" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:paddingTop="20dp" android:paddingTop="20dp"
android:text="Time Remaining:" android:text="time"
android:textSize="32dp"> android:textAlignment="center"
</TextView> android:textSize="32dp"></TextView>
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
@ -37,29 +42,29 @@
<Button <Button
android:id="@+id/Accept_btn" android:id="@+id/Accept_btn"
android:background="@drawable/buttonbackground" android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="0.5"
android:background="@drawable/greenbutton"
android:shadowColor="#A8A8A8" android:shadowColor="#A8A8A8"
android:shadowDx="0" android:shadowDx="0"
android:shadowDy="0" android:shadowDy="0"
android:shadowRadius="5" android:shadowRadius="5"
android:layout_width="match_parent" android:text="Accept"
android:layout_height="match_parent" android:textSize="30dp"></Button>
android:layout_weight="0.5"
android:textSize="30dp"
android:text="Accept">
</Button>
<Button <Button
android:id="@+id/Decline_btn" android:id="@+id/Decline_btn"
android:background="@drawable/buttonbackground" android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="0.5"
android:background="@drawable/redbutton"
android:shadowColor="#A8A8A8" android:shadowColor="#A8A8A8"
android:shadowDx="0" android:shadowDx="0"
android:shadowDy="0" android:shadowDy="0"
android:shadowRadius="5" android:shadowRadius="5"
android:layout_width="match_parent" android:text="Decline"
android:layout_height="match_parent" android:textSize="30dp">
android:layout_weight="0.5"
android:textSize="30dp"
android:text="Decline">
</Button> </Button>
</LinearLayout> </LinearLayout>

View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/gradientbackground"
tools:context=".FullActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="32dp">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:textSize="32dp"
android:textAlignment="center"
android:text="Your vehicle is full. Please remove it from the space."></TextView>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -14,16 +14,18 @@
android:orientation="vertical"> android:orientation="vertical">
<TextView <TextView
android:layout_width="wrap_content" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="Welcome!" android:text="Welcome!"
android:textAlignment="center"
android:textSize="34dp"> android:textSize="34dp">
</TextView> </TextView>
<TextView <TextView
android:layout_width="wrap_content" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="Press join queue to request a charger" android:text="Press join queue to request a charger"
android:textAlignment="center"
android:textSize="34dp"> android:textSize="34dp">
</TextView> </TextView>

View File

@ -69,6 +69,7 @@
<ProgressBar <ProgressBar
android:id="@+id/loading" android:id="@+id/loading"
style="?android:attr/progressBarStyleLarge"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="center" android:layout_gravity="center"

View File

@ -10,19 +10,22 @@
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:orientation="vertical"> android:orientation="vertical"
android:padding="32dp">
<TextView <TextView
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:textSize="32dp" android:textSize="32dp"
android:text="You have accepted a session waiting for plugin"></TextView> android:textAlignment="center"
android:text="You have accepted a session waiting for plug-in"></TextView>
<TextView <TextView
android:id="@+id/plugin_countdown" android:id="@+id/plugin_countdown"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:textSize="32dp" android:textSize="32dp"
android:text="You have accepted a session waiting for plugin"></TextView> android:textAlignment="center"
android:text="time"></TextView>
</LinearLayout> </LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -4,4 +4,6 @@
<color name="colorPrimaryDark">#00574B</color> <color name="colorPrimaryDark">#00574B</color>
<color name="colorAccent">#D81B60</color> <color name="colorAccent">#D81B60</color>
<color name="startcolor">#3aa8c1</color> <color name="startcolor">#3aa8c1</color>
<color name="uiRed">#C91900</color>
<color name="uiGreen">#00D007</color>
</resources> </resources>

View File

@ -1,5 +1,5 @@
<resources> <resources>
<string name="app_name">AppLogin</string> <string name="app_name">Smart Charger</string>
<!-- Strings related to login --> <!-- Strings related to login -->
<string name="prompt_email">Email</string> <string name="prompt_email">Email</string>
<string name="prompt_password">Password</string> <string name="prompt_password">Password</string>

View File

@ -7,8 +7,8 @@ buildscript {
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:3.5.2' classpath 'com.android.tools.build:gradle:3.5.3'
classpath 'com.google.gms:google-services:4.2.0' classpath 'com.google.gms:google-services:4.3.3'
// NOTE: Do not place your application dependencies here; they belong // NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files // in the individual module build.gradle files