diff --git a/android/app/build.gradle b/android/app/build.gradle index fa4d776..817bc89 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -35,13 +35,16 @@ android { dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" - implementation 'androidx.core:core-ktx:1.2.0' + implementation 'androidx.core:core-ktx:1.3.2' implementation 'androidx.appcompat:appcompat:1.1.0' implementation 'com.google.android.material:material:1.1.0' implementation 'androidx.constraintlayout:constraintlayout:1.1.3' implementation 'androidx.navigation:navigation-fragment-ktx:2.2.2' implementation 'androidx.navigation:navigation-ui-ktx:2.2.2' + implementation 'com.squareup.moshi:moshi:1.11.0' + implementation 'com.squareup.moshi:moshi-kotlin:1.11.0' implementation 'com.rabbitmq:amqp-client:5.9.0' + implementation "com.squareup.okhttp3:okhttp:4.9.0" testImplementation 'junit:junit:4.+' androidTestImplementation 'androidx.test.ext:junit:1.1.1' androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 61b823e..471906a 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -1,9 +1,16 @@ - - + + + + + + (R.id.button_first).setOnClickListener { - findNavController().navigate(R.id.action_FirstFragment_to_SecondFragment) - } - } -} \ No newline at end of file diff --git a/android/app/src/main/java/de/nicolasklier/livebeat/MainActivity.kt b/android/app/src/main/java/de/nicolasklier/livebeat/MainActivity.kt index 7d1a97d..0c77260 100644 --- a/android/app/src/main/java/de/nicolasklier/livebeat/MainActivity.kt +++ b/android/app/src/main/java/de/nicolasklier/livebeat/MainActivity.kt @@ -1,24 +1,202 @@ package de.nicolasklier.livebeat +import android.Manifest +import android.annotation.SuppressLint +import android.content.BroadcastReceiver +import android.content.Context import android.content.Intent +import android.content.IntentFilter +import android.content.pm.PackageManager +import android.graphics.Color +import android.os.Build import android.os.Bundle +import android.os.Handler +import android.os.Looper +import android.provider.Settings +import android.util.Log import android.view.Menu import android.view.MenuItem +import android.view.View +import android.widget.Button +import android.widget.TextView import androidx.appcompat.app.AppCompatActivity +import androidx.core.app.ActivityCompat +import androidx.core.content.ContextCompat import com.google.android.material.floatingactionbutton.FloatingActionButton import com.google.android.material.snackbar.Snackbar +import com.squareup.moshi.Moshi +import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory +import okhttp3.MediaType.Companion.toMediaType +import okhttp3.OkHttpClient +import okhttp3.Request +import okhttp3.RequestBody.Companion.toRequestBody +import java.util.logging.Logger +@Suppress("NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS") class MainActivity : AppCompatActivity() { + companion object { + @JvmStatic val API_URL = "http://192.168.178.26:8040" + var TOKEN = "" + } + + private var broadcastReceiver: BroadcastReceiver? = null + + @SuppressLint("HardwareIds") + fun checkIfPhoneIsRegistered() { + if (TOKEN == "") return; + Thread(Runnable { + val androidId = Settings.Secure.getString(contentResolver, Settings.Secure.ANDROID_ID) + val client = OkHttpClient() + val req = Request.Builder() + .url("$API_URL/phone/$androidId") + .get() + .build() + val response = client.newCall(req).execute() + + if (response.code != 200) { + Snackbar.make(findViewById(R.id.fab), "Device isn't registered yet.", Snackbar.LENGTH_SHORT) + .setBackgroundTint(Color.YELLOW) + .setTextColor(Color.BLACK) + .show() + + // Register device + val phone = Phone( + androidId, + Build.MODEL, + Build.PRODUCT, + Build.VERSION.RELEASE, + System.getProperty("os.arch") + ) + val moshi = Moshi.Builder().add(KotlinJsonAdapterFactory()).build() + val phoneToJson = moshi.adapter(Phone::class.java) + val json = phoneToJson.toJson(phone) + + val createPhone = Request.Builder() + .url("$API_URL/phone") + .post( + (json).toRequestBody() + ) + .header("Content-Type", "application/json") + .header("token", TOKEN) + .build() + client.newCall(createPhone).execute() + } + }).start() + } + override fun onCreate(savedInstanceState: Bundle?) { + checkPerms() + super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) setSupportActionBar(findViewById(R.id.toolbar)) startService(Intent(this, TrackerService::class.java)) + // Check authorization + val backendChecks = Thread(Runnable { + val username = findViewById(R.id.username).text + val password = findViewById(R.id.password).text + val moshi = Moshi.Builder().add(KotlinJsonAdapterFactory()).build() + val jsonToLogin = moshi.adapter(Login::class.java) + + val client = OkHttpClient() + val req = Request.Builder() + .url("$API_URL/user/login") + .post( + ("{ \"username\": \"" + username + "\"," + + "\"password\": \"" + password + "\" }").toRequestBody() + ) + .header("Content-Type", "application/json") + .build() + val loginResponse = client.newCall(req).execute() + val responseBody = loginResponse.body!!.string() + + if (loginResponse.code == 200) { + TOKEN = jsonToLogin.fromJson(responseBody)!!.token + + // Since we are in another thread, we have to get back to the UI thread. + this.runOnUiThread(Runnable { + findViewById(R.id.httpStatus).setTextColor(Color.GREEN) + findViewById(R.id.httpStatus).text = "CONNECTED" + }) + + Snackbar.make(findViewById(R.id.fab), "Login succeeded", Snackbar.LENGTH_SHORT) + .setBackgroundTint(Color.GREEN) + .setActionTextColor(Color.WHITE) + .show() + + checkIfPhoneIsRegistered() + } else { + // Since we are in another thread, we have to get back to the UI thread. + this.runOnUiThread(Runnable { + findViewById(R.id.httpStatus).setTextColor(Color.RED) + findViewById(R.id.httpStatus).text = "LOGIN FAILED" + }) + Snackbar.make(findViewById(R.id.fab), "Login failed", Snackbar.LENGTH_LONG) + .setBackgroundTint(Color.RED) + .setActionTextColor(Color.WHITE) + .show() + } + }) + backendChecks.start() + + /** + * Here we receive updates from our tracker service. + */ + this.broadcastReceiver = object : BroadcastReceiver() { + @SuppressLint("CutPasteId") + override fun onReceive(context: Context, intent: Intent) { + val statusRabbit = intent.getBooleanExtra("statusRabbit", false) + val statusHttp = intent.getIntExtra("statusHttp", 404) + + if (statusRabbit) { + findViewById(R.id.rabbitStatus).text = "connected" + findViewById(R.id.rabbitStatus).setTextColor(Color.GREEN) + } else { + findViewById(R.id.rabbitStatus).text = "disconnected" + findViewById(R.id.rabbitStatus).setTextColor(Color.RED) + } + + if (statusHttp == 200) { + findViewById(R.id.httpStatus).text = "ONLINE (no login)" + findViewById(R.id.httpStatus).setTextColor(Color.CYAN) + findViewById