Commit b605075e authored by Andres Käver's avatar Andres Käver
Browse files

Api client

parent 324dfe08
......@@ -35,6 +35,7 @@ dependencies {
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation "androidx.preference:preference-ktx:1.1.0"
implementation "com.google.android.material:material:1.0.0"
implementation 'com.android.volley:volley:1.1.1'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
......
......@@ -11,6 +11,7 @@
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.INTERNET" />
<application
android:allowBackup="true"
......
......@@ -19,7 +19,15 @@ class C {
const val LOCATION_UPDATE_ACTION_WP_TOTAL = PREFIX + "location_update.wp_total"
const val NOTIFICATION_ID = 4321
const val REQUEST_PERMISSIONS_REQUEST_CODE = 34;
const val REQUEST_PERMISSIONS_REQUEST_CODE = 34
const val REST_BASE_URL = "https://sportmap.akaver.com/api/v1.0/"
const val REST_USERNAME = "akaver@akaver.com"
const val REST_PASSWORD = "Kala.maja2020"
const val REST_LOCATIONID_LOC = "00000000-0000-0000-0000-000000000001"
const val REST_LOCATIONID_WP = "00000000-0000-0000-0000-000000000002"
const val REST_LOCATIONID_CP = "00000000-0000-0000-0000-000000000003"
}
}
\ No newline at end of file
......@@ -7,6 +7,7 @@ import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.location.Location
import android.os.Build
import android.os.IBinder
import android.os.Looper
import android.util.Log
......@@ -14,7 +15,13 @@ import android.widget.RemoteViews
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import androidx.localbroadcastmanager.content.LocalBroadcastManager
import com.android.volley.Request
import com.android.volley.Response
import com.android.volley.toolbox.JsonObjectRequest
import com.google.android.gms.location.*
import org.json.JSONObject
import java.text.SimpleDateFormat
import java.util.*
class LocationService : Service() {
companion object {
......@@ -46,6 +53,10 @@ class LocationService : Service() {
private var distanceWPDirect = 0f
private var distanceWPTotal = 0f
private var locationWP: Location? = null
private var jwt: String? = null
private var trackingSessionId: String? = null
private val dateFormat = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX", Locale.getDefault())
override fun onCreate() {
Log.d(TAG, "onCreate")
......@@ -68,6 +79,8 @@ class LocationService : Service() {
}
}
getRestToken();
getLastLocation()
createLocationRequest()
......@@ -75,7 +88,114 @@ class LocationService : Service() {
}
private fun getRestToken() {
var handler = WebApiSingletonHandler.getInstance(applicationContext)
val requestJsonParameters = JSONObject()
requestJsonParameters.put("email", C.REST_USERNAME)
requestJsonParameters.put("password", C.REST_PASSWORD)
var httpRequest = JsonObjectRequest(
Request.Method.POST,
C.REST_BASE_URL + "account/login",
requestJsonParameters,
Response.Listener { response ->
Log.d(TAG, response.toString())
jwt = response.getString("token")
startRestTrackingSession()
},
Response.ErrorListener { error ->
Log.d(TAG, error.toString())
}
)
handler.addToRequestQueue(httpRequest)
}
private fun startRestTrackingSession() {
var handler = WebApiSingletonHandler.getInstance(applicationContext)
val requestJsonParameters = JSONObject()
requestJsonParameters.put("name", Date().toString())
requestJsonParameters.put("description", Date().toString())
var httpRequest = object : JsonObjectRequest(
Request.Method.POST,
C.REST_BASE_URL + "GpsSessions",
requestJsonParameters,
Response.Listener { response ->
Log.d(TAG, response.toString())
trackingSessionId = response.getString("id")
},
Response.ErrorListener { error ->
Log.d(TAG, error.toString())
}
) {
override fun getHeaders(): MutableMap<String, String> {
val headers = HashMap<String, String>()
for ((key, value) in super.getHeaders()) {
headers[key] = value
}
headers["Authorization"] = "Bearer " + jwt!!
return headers
}
}
handler.addToRequestQueue(httpRequest)
}
private fun saveRestLocation(location: Location, location_type: String) {
if (jwt == null || trackingSessionId == null) {
return
}
var handler = WebApiSingletonHandler.getInstance(applicationContext)
val requestJsonParameters = JSONObject()
requestJsonParameters.put("recordedAt", dateFormat.format(Date(location.time)))
requestJsonParameters.put("latitude", location.latitude)
requestJsonParameters.put("longitude", location.longitude)
requestJsonParameters.put("accuracy", location.accuracy)
requestJsonParameters.put("altitude", location.altitude)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
requestJsonParameters.put("verticalAccuracy", location.verticalAccuracyMeters)
}
requestJsonParameters.put("gpsSessionId", trackingSessionId)
requestJsonParameters.put("gpsLocationTypeId", location_type)
var httpRequest = object : JsonObjectRequest(
Request.Method.POST,
C.REST_BASE_URL + "GpsLocations",
requestJsonParameters,
Response.Listener { response ->
Log.d(TAG, response.toString())
},
Response.ErrorListener { error ->
Log.d(TAG, error.toString())
}
) {
override fun getHeaders(): MutableMap<String, String> {
val headers = HashMap<String, String>()
for ((key, value) in super.getHeaders()) {
headers[key] = value
}
headers["Authorization"] = "Bearer " + jwt!!
return headers
}
}
handler.addToRequestQueue(httpRequest)
}
private fun requestLocationUpdates() {
Log.i(TAG, "Requesting location updates")
try {
......@@ -93,7 +213,7 @@ class LocationService : Service() {
private fun onNewLocation(location: Location) {
Log.i(TAG, "New location: $location")
if (currentLocation == null){
if (currentLocation == null) {
locationStart = location
locationCP = location
locationWP = location
......@@ -111,13 +231,14 @@ class LocationService : Service() {
currentLocation = location
showNotification()
saveRestLocation(location, C.REST_LOCATIONID_LOC)
// broadcast new location to UI
val intent = Intent(C.LOCATION_UPDATE_ACTION)
intent.putExtra(C.LOCATION_UPDATE_ACTION_OVERALL_DIRECT, distanceOverallDirect)
intent.putExtra(C.LOCATION_UPDATE_ACTION_OVERALL_TOTAL, distanceOverallTotal)
intent.putExtra(C.LOCATION_UPDATE_ACTION_CP_DIRECT, distanceCPDirect)
intent.putExtra(C.LOCATION_UPDATE_ACTION_CP_TOTAL,distanceCPTotal )
intent.putExtra(C.LOCATION_UPDATE_ACTION_CP_TOTAL, distanceCPTotal)
intent.putExtra(C.LOCATION_UPDATE_ACTION_WP_DIRECT, distanceWPDirect)
intent.putExtra(C.LOCATION_UPDATE_ACTION_WP_TOTAL, distanceWPTotal)
......@@ -135,15 +256,17 @@ class LocationService : Service() {
private fun getLastLocation() {
try {
mFusedLocationClient.lastLocation
.addOnCompleteListener { task -> if (task.isSuccessful) {
Log.w(TAG, "task successfull");
if (task.result != null){
onNewLocation(task.result!!)
.addOnCompleteListener { task ->
if (task.isSuccessful) {
Log.w(TAG, "task successfull");
if (task.result != null) {
onNewLocation(task.result!!)
}
} else {
Log.w(TAG, "Failed to get location." + task.exception)
}
} else {
Log.w(TAG, "Failed to get location." + task.exception)
}}
}
} catch (unlikely: SecurityException) {
Log.e(TAG, "Lost location permission.$unlikely")
}
......@@ -199,11 +322,11 @@ class LocationService : Service() {
}
override fun onBind(intent: Intent): IBinder {
Log.d(TAG, "onBind")
TODO("Return the communication channel to the service.")
}
override fun onRebind(intent: Intent?) {
Log.d(TAG, "onRebind")
super.onRebind(intent)
......@@ -215,7 +338,7 @@ class LocationService : Service() {
}
fun showNotification(){
fun showNotification() {
val intentStartStop = Intent(C.NOTIFICATION_ACTION_START_STOP)
val intentCp = Intent(C.NOTIFICATION_ACTION_CP)
val intentWp = Intent(C.NOTIFICATION_ACTION_WP)
......@@ -255,20 +378,22 @@ class LocationService : Service() {
}
private inner class InnerBroadcastReceiver: BroadcastReceiver() {
private inner class InnerBroadcastReceiver : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
Log.d(TAG, intent!!.action)
when(intent!!.action){
when (intent!!.action) {
C.NOTIFICATION_ACTION_WP -> {
locationWP = currentLocation
distanceWPDirect = 0f
distanceWPTotal = 0f
saveRestLocation(locationWP!!, C.REST_LOCATIONID_WP)
showNotification()
}
C.NOTIFICATION_ACTION_CP -> {
locationCP = currentLocation
distanceCPDirect = 0f
distanceCPTotal = 0f
saveRestLocation(locationCP!!, C.REST_LOCATIONID_WP)
showNotification()
}
}
......@@ -277,6 +402,4 @@ class LocationService : Service() {
}
}
package com.akaver.sportmap
import android.content.Context
import android.text.TextUtils
import android.util.Log
import com.android.volley.Request
import com.android.volley.RequestQueue
import com.android.volley.toolbox.Volley
class WebApiSingletonHandler {
companion object {
private val TAG = this::class.java.declaringClass!!.simpleName
private var instance: WebApiSingletonHandler? = null
private var mContext: Context? = null
@Synchronized
fun getInstance(context: Context): WebApiSingletonHandler {
if (instance == null) {
instance = WebApiSingletonHandler(context)
}
return instance!!
}
}
constructor(context: Context) {
mContext = context
}
private var requestQueue: RequestQueue? = null
get() {
if (field == null) {
field = Volley.newRequestQueue(mContext)
}
return field
}
fun <T> addToRequestQueue(request: Request<T>, tag: String) {
Log.d(TAG, request.url)
request.tag = if (TextUtils.isEmpty(tag)) TAG else tag
requestQueue?.add(request)
}
fun <T> addToRequestQueue(request: Request<T>) {
Log.d(TAG, request.url)
request.tag = TAG
requestQueue?.add(request)
}
fun cancelPendingRequest(tag: String) {
if (requestQueue != null) {
requestQueue!!.cancelAll(if (TextUtils.isEmpty(tag)) TAG else tag)
}
}
}
\ No newline at end of file
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment