diff --git a/app/build.gradle b/app/build.gradle index 897d30f..c8a9f62 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -6,7 +6,7 @@ android { buildToolsVersion "29.0.2" defaultConfig { applicationId "com.example.applogin" - minSdkVersion 15 + minSdkVersion 16 targetSdkVersion 29 versionCode 1 versionName "1.0" @@ -22,14 +22,13 @@ android { dependencies { 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 'androidx.annotation:annotation:1.0.2' + implementation 'androidx.annotation:annotation:1.1.0' implementation 'androidx.constraintlayout:constraintlayout:1.1.3' - implementation 'androidx.lifecycle:lifecycle-extensions:2.0.0' - implementation 'com.google.firebase:firebase-messaging:17.3.4' + implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0' + implementation 'com.google.firebase:firebase-messaging:20.1.0' testImplementation 'junit:junit:4.12' - androidTestImplementation 'androidx.test.ext:junit:1.1.0' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1' - implementation 'com.android.volley:volley:1.1.1' + androidTestImplementation 'androidx.test.ext:junit:1.1.1' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' } diff --git a/app/google-services.json b/app/google-services.json index 21b99d7..6b13d26 100644 --- a/app/google-services.json +++ b/app/google-services.json @@ -14,6 +14,14 @@ } }, "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_type": 1, diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index a792adc..30e03d4 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -26,10 +26,11 @@ + + android:exported="false" > diff --git a/app/src/main/java/com/example/applogin/ChargingActivity.java b/app/src/main/java/com/example/applogin/ChargingActivity.java index d455129..f394d77 100644 --- a/app/src/main/java/com/example/applogin/ChargingActivity.java +++ b/app/src/main/java/com/example/applogin/ChargingActivity.java @@ -2,17 +2,24 @@ package com.example.applogin; import androidx.appcompat.app.AppCompatActivity; +import android.content.Context; import android.content.Intent; +import android.content.SharedPreferences; import android.os.Bundle; import android.os.CountDownTimer; 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 { TextView coundownTime; TextView chargeState; + Thread pollingThread; @Override protected void onCreate(Bundle savedInstanceState) { @@ -30,14 +37,78 @@ public class ChargingActivity extends AppCompatActivity { int minutesLeft = (secondsLeft % 3600)/60; secondsLeft %= 60; - coundownTime.setText("Time remaining: " + String.format("%d:%d:%02d", hoursLeft, minutesLeft,secondsLeft)); + coundownTime.setText("Time remaining: " + String.format("%d:%d:%02d", hoursLeft, minutesLeft, secondsLeft)); } public void onFinish() { End_criteria(); } }.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) private void End_criteria() { diff --git a/app/src/main/java/com/example/applogin/EVFirebase.java b/app/src/main/java/com/example/applogin/EVFirebase.java index 910e3ba..9b983aa 100644 --- a/app/src/main/java/com/example/applogin/EVFirebase.java +++ b/app/src/main/java/com/example/applogin/EVFirebase.java @@ -1,28 +1,27 @@ package com.example.applogin; +import android.app.NotificationChannel; +import android.app.NotificationManager; +import android.app.PendingIntent; import android.content.Context; +import android.content.Intent; import android.content.SharedPreferences; +import android.os.Build; import android.widget.Toast; -import com.android.volley.AuthFailureError; -import com.android.volley.Request; -import com.android.volley.RequestQueue; -import com.android.volley.Response; -import com.android.volley.VolleyError; -import com.android.volley.toolbox.JsonObjectRequest; -import com.android.volley.toolbox.Volley; +import androidx.annotation.NonNull; +import androidx.core.app.NotificationCompat; + +import com.example.applogin.network.UpdateNotificationTask; import com.google.firebase.messaging.FirebaseMessagingService; +import com.google.firebase.messaging.RemoteMessage; -import org.json.JSONObject; - -import java.util.HashMap; -import java.util.Map; +import java.util.concurrent.ExecutionException; public class EVFirebase extends FirebaseMessagingService { @Override public void onNewToken(String token) { - // If you want to send messages to this application instance or // manage this apps subscriptions on the server side, send the // Instance ID token to your app server. @@ -32,41 +31,43 @@ public class EVFirebase extends FirebaseMessagingService { public void sendRegistrationToServer(String token){ - // Instantiate the RequestQueue. - RequestQueue queue = Volley.newRequestQueue(this); - String url ="https://ev-scheduler.appspot.com/api/user"; + SharedPreferences preferences = getApplicationContext().getSharedPreferences("scheduler_preferences", Context.MODE_PRIVATE); - HashMap dict = new HashMap<>(); - dict.put("notification_token", token); - JSONObject json = new JSONObject(dict); + UpdateNotificationTask task = new UpdateNotificationTask(token, preferences.getString("api_key", null)); - // Request a string response from the provided URL. - final JsonObjectRequest stringRequest = new JsonObjectRequest(Request.Method.PUT, url, json, - new Response.Listener() { - @Override - public void onResponse(JSONObject response) { - - } - }, new Response.ErrorListener() { - @Override - public void onErrorResponse(VolleyError error) { - Toast.makeText(EVFirebase.this, Integer.toString(error.networkResponse.statusCode), Toast.LENGTH_SHORT).show(); + task.execute(); + try { + if(!task.get()){ + Toast.makeText(EVFirebase.this, "error sending notification token", Toast.LENGTH_SHORT).show(); + }else{ + Toast.makeText(EVFirebase.this, "notification sent", Toast.LENGTH_SHORT).show(); } - }){ - - @Override - public Map getHeaders() throws AuthFailureError { - - HashMap headers = new HashMap<>(); - SharedPreferences context = getApplicationContext().getSharedPreferences("scheduler_preferences", Context.MODE_PRIVATE); - headers.put("Authorization", "Bearer " + context.getString("api_key", "")); - return headers; - - } - - }; + } catch (ExecutionException e) { + e.printStackTrace(); + } catch (InterruptedException e) { + e.printStackTrace(); + } } + @Override + public void onMessageReceived(@NonNull RemoteMessage remoteMessage) { + super.onMessageReceived(remoteMessage); + Intent intent = new Intent(this, JoinQueueActivity.class); + intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); + PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_ONE_SHOT); + 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()); + } + } diff --git a/app/src/main/java/com/example/applogin/FullActivity.java b/app/src/main/java/com/example/applogin/FullActivity.java new file mode 100644 index 0000000..3645f62 --- /dev/null +++ b/app/src/main/java/com/example/applogin/FullActivity.java @@ -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(); + } +} diff --git a/app/src/main/java/com/example/applogin/JoinQueueActivity.java b/app/src/main/java/com/example/applogin/JoinQueueActivity.java index 11b2e00..df4a0f5 100644 --- a/app/src/main/java/com/example/applogin/JoinQueueActivity.java +++ b/app/src/main/java/com/example/applogin/JoinQueueActivity.java @@ -1,6 +1,5 @@ package com.example.applogin; -import androidx.annotation.NonNull; import androidx.appcompat.app.AppCompatActivity; import android.content.Context; @@ -11,24 +10,10 @@ import android.view.View; import android.widget.Button; import android.widget.Toast; -import com.android.volley.AuthFailureError; -import com.android.volley.Request; -import com.android.volley.RequestQueue; -import com.android.volley.Response; -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; +import com.example.applogin.model.User; +import com.example.applogin.network.GetUserTask; +import com.example.applogin.network.QueueTask; +import java.util.concurrent.ExecutionException; public class JoinQueueActivity extends AppCompatActivity { @@ -37,69 +22,48 @@ public class JoinQueueActivity extends AppCompatActivity { super.onCreate(savedInstanceState); setContentView(R.layout.activity_join_queue); - FirebaseInstanceId.getInstance().getInstanceId() - .addOnCompleteListener(new OnCompleteListener() { - @Override - public void onComplete(@NonNull Task 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 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() { - @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 getHeaders() throws AuthFailureError { - - HashMap 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); joinButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - //Toast.makeText(JoinQueueActivity.this, "testtttt", Toast.LENGTH_SHORT).show(); - Intent myIntent = new Intent(JoinQueueActivity.this, WaitingActivity.class); - startActivity(myIntent); + 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); + 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(); + } + } } diff --git a/app/src/main/java/com/example/applogin/Login2Activity.java b/app/src/main/java/com/example/applogin/Login2Activity.java index 9c3b3a9..06feb2b 100644 --- a/app/src/main/java/com/example/applogin/Login2Activity.java +++ b/app/src/main/java/com/example/applogin/Login2Activity.java @@ -1,5 +1,6 @@ package com.example.applogin; +import androidx.annotation.NonNull; import androidx.appcompat.app.AppCompatActivity; import androidx.core.app.ActivityCompat; import androidx.core.content.ContextCompat; @@ -13,13 +14,25 @@ import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.EditText; +import android.widget.ProgressBar; 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.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; public class Login2Activity extends AppCompatActivity { + ProgressBar loading; + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -45,6 +58,7 @@ public class Login2Activity extends AppCompatActivity { final Button signInButton = findViewById(R.id.login); final EditText usernameEditText = findViewById(R.id.username); final EditText passwordEditText = findViewById(R.id.password); + loading = findViewById(R.id.loading); signInButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { @@ -78,11 +92,12 @@ public class Login2Activity extends AppCompatActivity { private void tryLogin(String username, String password) { - LoginTask task = new LoginTask(username, password); + NativeLoginTask task = new NativeLoginTask(username, password); + task.execute(); try { - String result = task.get(); + final String result = task.get(); if (result == null) { @@ -94,8 +109,60 @@ public class Login2Activity extends AppCompatActivity { SharedPreferences.Editor editor = context.edit(); editor.putString("api_key", result); editor.apply(); - Intent myIntent = new Intent(Login2Activity.this, JoinQueueActivity.class); - startActivity(myIntent); + + FirebaseInstanceId.getInstance().getInstanceId() + .addOnCompleteListener(new OnCompleteListener() { + @Override + public void onComplete(@NonNull Task 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) { @@ -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); + } + } + } + + diff --git a/app/src/main/java/com/example/applogin/PluginWait_Activity.java b/app/src/main/java/com/example/applogin/PluginWait_Activity.java index 79548ed..d871122 100644 --- a/app/src/main/java/com/example/applogin/PluginWait_Activity.java +++ b/app/src/main/java/com/example/applogin/PluginWait_Activity.java @@ -2,36 +2,128 @@ package com.example.applogin; import androidx.appcompat.app.AppCompatActivity; +import android.content.Context; import android.content.Intent; +import android.content.SharedPreferences; import android.os.Bundle; import android.os.CountDownTimer; 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 java.util.concurrent.ExecutionException; + public class PluginWait_Activity extends AppCompatActivity { + Thread pollingThread; + CountDownTimer timer; + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); 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) { int secondsLeft = (int) millisUntilFinished / 1000; int minutesLeft = secondsLeft / 60; secondsLeft %= 60; - acceptCoundown.setText("Time remaining: " + String.format("%d:%02d", minutesLeft,secondsLeft)); + acceptCoundown.setText("Time remaining: " + String.format("%d:%02d", minutesLeft, secondsLeft)); } public void onFinish() { - Intent myIntent = new Intent(PluginWait_Activity.this, JoinQueueActivity.class); - startActivity(myIntent); + + 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); + 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(); + + + 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(); } } diff --git a/app/src/main/java/com/example/applogin/WaitingActivity.java b/app/src/main/java/com/example/applogin/WaitingActivity.java index 1ccec3a..0108a65 100644 --- a/app/src/main/java/com/example/applogin/WaitingActivity.java +++ b/app/src/main/java/com/example/applogin/WaitingActivity.java @@ -2,20 +2,26 @@ package com.example.applogin; import androidx.appcompat.app.AppCompatActivity; +import android.content.Context; import android.content.Intent; +import android.content.SharedPreferences; import android.os.Bundle; import android.widget.Button; import android.widget.TextView; +import com.example.applogin.model.User; +import com.example.applogin.network.GetUserTask; import com.example.applogin.ui.login.ConfirmationActivity; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.ExecutionException; public class WaitingActivity extends AppCompatActivity { List queue; TextView queuePosition; + Thread pollingThread; @Override protected void onCreate(Bundle savedInstanceState) { @@ -28,6 +34,61 @@ public class WaitingActivity extends AppCompatActivity { //do initial update 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 private void UpdateQueue() { @@ -42,4 +103,12 @@ public class WaitingActivity extends AppCompatActivity { startActivity(myIntent); } } + + @Override + protected void onDestroy() { + super.onDestroy(); + if(pollingThread.isAlive()){ + pollingThread.interrupt(); + } + } } diff --git a/app/src/main/java/com/example/applogin/network/KillSessionTask.java b/app/src/main/java/com/example/applogin/network/KillSessionTask.java new file mode 100644 index 0000000..806eef2 --- /dev/null +++ b/app/src/main/java/com/example/applogin/network/KillSessionTask.java @@ -0,0 +1,28 @@ +package com.example.applogin.network; + +import java.util.HashMap; + +public class KillSessionTask extends AbstractNetworkTask { + + 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 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; + + } +} diff --git a/app/src/main/java/com/example/applogin/network/LoginTask.java b/app/src/main/java/com/example/applogin/network/LoginTask.java index 037bdf7..ba94239 100644 --- a/app/src/main/java/com/example/applogin/network/LoginTask.java +++ b/app/src/main/java/com/example/applogin/network/LoginTask.java @@ -6,8 +6,8 @@ import java.util.HashMap; public class LoginTask extends AbstractNetworkTask { - private String username; - private String password; + protected String username; + protected String password; public LoginTask(String username, String password){ super(); diff --git a/app/src/main/java/com/example/applogin/network/UpdateNotificationTask.java b/app/src/main/java/com/example/applogin/network/UpdateNotificationTask.java new file mode 100644 index 0000000..3bdba18 --- /dev/null +++ b/app/src/main/java/com/example/applogin/network/UpdateNotificationTask.java @@ -0,0 +1,27 @@ +package com.example.applogin.network; + +import java.util.HashMap; + +public class UpdateNotificationTask extends AbstractNetworkTask { + + 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 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; + } +} diff --git a/app/src/main/java/com/example/applogin/ui/login/ConfirmationActivity.java b/app/src/main/java/com/example/applogin/ui/login/ConfirmationActivity.java index cb90606..dcccbb9 100644 --- a/app/src/main/java/com/example/applogin/ui/login/ConfirmationActivity.java +++ b/app/src/main/java/com/example/applogin/ui/login/ConfirmationActivity.java @@ -2,7 +2,9 @@ package com.example.applogin.ui.login; import androidx.appcompat.app.AppCompatActivity; +import android.content.Context; import android.content.Intent; +import android.content.SharedPreferences; import android.os.Bundle; import android.os.CountDownTimer; import android.view.View; @@ -10,10 +12,12 @@ import android.widget.Button; import android.widget.TextView; import android.widget.Toast; -import com.example.applogin.ChargingActivity; import com.example.applogin.JoinQueueActivity; +import com.example.applogin.PluginWait_Activity; 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 { @@ -33,7 +37,7 @@ public class ConfirmationActivity extends AppCompatActivity { int minutesLeft = secondsLeft / 60; secondsLeft %= 60; - acceptCountdown.setText("Time Remaining: " + minutesLeft + ":" + secondsLeft); + acceptCountdown.setText(minutesLeft + ":" + secondsLeft); } public void onFinish() { @@ -47,7 +51,7 @@ public class ConfirmationActivity extends AppCompatActivity { @Override public void onClick(View v) { countdownTimer.cancel(); - Intent myIntent = new Intent(ConfirmationActivity.this, ChargingActivity.class); + Intent myIntent = new Intent(ConfirmationActivity.this, PluginWait_Activity.class); startActivity(myIntent); } }); @@ -57,8 +61,25 @@ public class ConfirmationActivity extends AppCompatActivity { @Override public void onClick(View v) { countdownTimer.cancel(); - Intent myIntent = new Intent(ConfirmationActivity.this, JoinQueueActivity.class); - startActivity(myIntent); + + 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); + startActivity(myIntent); + + }else{ + Toast.makeText(ConfirmationActivity.this, "error cancelling session", Toast.LENGTH_SHORT).show(); + } + } catch (ExecutionException e) { + e.printStackTrace(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } }); } diff --git a/app/src/main/res/drawable/greenbutton.xml b/app/src/main/res/drawable/greenbutton.xml new file mode 100644 index 0000000..6ea88a2 --- /dev/null +++ b/app/src/main/res/drawable/greenbutton.xml @@ -0,0 +1,18 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/redbutton.xml b/app/src/main/res/drawable/redbutton.xml new file mode 100644 index 0000000..2bb0eb8 --- /dev/null +++ b/app/src/main/res/drawable/redbutton.xml @@ -0,0 +1,18 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_charging.xml b/app/src/main/res/layout/activity_charging.xml index 7a597c2..cfad557 100644 --- a/app/src/main/res/layout/activity_charging.xml +++ b/app/src/main/res/layout/activity_charging.xml @@ -18,12 +18,14 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Car charging" + android:textAlignment="center" android:textSize="32dp"> diff --git a/app/src/main/res/layout/activity_confirmation.xml b/app/src/main/res/layout/activity_confirmation.xml index 799031f..0b66585 100644 --- a/app/src/main/res/layout/activity_confirmation.xml +++ b/app/src/main/res/layout/activity_confirmation.xml @@ -10,24 +10,29 @@ + android:padding="50dp" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent"> - + android:text="Charging station available, accept within: " + android:textAlignment="center" + android:textSize="32dp"> - + android:text="time" + android:textAlignment="center" + android:textSize="32dp"> - + android:text="Accept" + android:textSize="30dp"> + diff --git a/app/src/main/res/layout/activity_full.xml b/app/src/main/res/layout/activity_full.xml new file mode 100644 index 0000000..97602a3 --- /dev/null +++ b/app/src/main/res/layout/activity_full.xml @@ -0,0 +1,24 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_join_queue.xml b/app/src/main/res/layout/activity_join_queue.xml index 0e97dbd..8e72a4d 100644 --- a/app/src/main/res/layout/activity_join_queue.xml +++ b/app/src/main/res/layout/activity_join_queue.xml @@ -14,16 +14,18 @@ android:orientation="vertical"> diff --git a/app/src/main/res/layout/activity_login2.xml b/app/src/main/res/layout/activity_login2.xml index 5c5da93..5749453 100644 --- a/app/src/main/res/layout/activity_login2.xml +++ b/app/src/main/res/layout/activity_login2.xml @@ -69,6 +69,7 @@ + android:orientation="vertical" + android:padding="32dp"> + android:textAlignment="center" + android:text="You have accepted a session waiting for plug-in"> + android:textAlignment="center" + android:text="time"> \ No newline at end of file diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index 7831a57..e49595d 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -4,4 +4,6 @@ #00574B #D81B60 #3aa8c1 + #C91900 + #00D007 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 4e1ba15..9a18a72 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,5 +1,5 @@ - AppLogin + Smart Charger Email Password diff --git a/build.gradle b/build.gradle index f10a55f..63bc63e 100644 --- a/build.gradle +++ b/build.gradle @@ -7,8 +7,8 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:3.5.2' - classpath 'com.google.gms:google-services:4.2.0' + classpath 'com.android.tools.build:gradle:3.5.3' + classpath 'com.google.gms:google-services:4.3.3' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files