adds rest list receiver, adds local code storage

- rest class now receives a list as well as single
  messages
- adds support for threaded singleton which takes
  care of continuous checking of the bump server
  to get the most up-to-date list of messages
- adds local data class with tests to get locally saved
  code in preferences
This commit is contained in:
Raphael Maenle 2021-12-29 19:42:43 +01:00
parent 7e4cfceab4
commit 734b64ce3b
10 changed files with 187 additions and 16 deletions

View File

@ -1,6 +1,8 @@
package com.example.bump package com.example.bump
import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.internal.runner.InstrumentationConnection
import androidx.test.platform.app.InstrumentationRegistry
import org.junit.Assert import org.junit.Assert
import org.junit.Test import org.junit.Test
import org.junit.runner.RunWith import org.junit.runner.RunWith
@ -28,6 +30,15 @@ class MessageProcessorTest {
Assert.assertEquals(test, decrypted) Assert.assertEquals(test, decrypted)
} }
@Test
fun setCode() {
val test = getRandomString(512)
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
val local = LocalData(appContext)
local.code = test
Assert.assertEquals(local.code, test)
}
companion object { companion object {
@JvmStatic @JvmStatic
fun decryptMessage(code: String, messageData: String): String { fun decryptMessage(code: String, messageData: String): String {

View File

@ -68,9 +68,8 @@ class RestCryptTest{
val lock = CountDownLatch(1) val lock = CountDownLatch(1)
fun listTester(resultList: JSONObject) { fun listTester(messages: JSONArray) {
val message = MessageProcessor(code) val message = MessageProcessor(code)
val messages: JSONArray = resultList.get("messages") as JSONArray
var messageEncoded = messages[0] as JSONObject var messageEncoded = messages[0] as JSONObject
var messageData = messageEncoded.get("data").toString() var messageData = messageEncoded.get("data").toString()

View File

@ -0,0 +1,116 @@
package com.example.bump
import android.content.Context
import android.os.Handler
import android.os.Looper
import com.android.volley.toolbox.JsonObjectRequest
import com.maenle.bump.MainActivity
import org.json.JSONArray
import org.json.JSONObject
import java.io.File
import java.io.FileOutputStream
import javax.inject.Inject
class BumpProcessor constructor(context: Context) {
private var rest: RestSingleton = RestSingleton.getInstance(context)
private var secret: String? = null
private lateinit var log: JSONArray
private lateinit var messenger: MessageProcessor
init {
secret = getSecret(context)
log = getLog(context)
}
companion object {
@Volatile
private var INSTANCE: BumpProcessor? = null
fun getInstance(context: Context) =
INSTANCE ?: synchronized(this) {
INSTANCE ?: BumpProcessor(context).also {
INSTANCE = it
}
}
}
private fun updateLog(context: Context, list: JSONArray) {
for(i in 0 until list.length()) {
var exists = false
for(j in 0 until log.length()) {
if (list[i] == log[j]) {
exists = true
continue
}
}
exists.let {
log.put(list[i])
addToLog(context, list[i] as JSONObject)
}
}
}
fun hasSecret(): Boolean {
secret?.let {
return true
}
return false
}
private fun getSecret(context: Context):String? {
val secretFile = File(context.filesDir, ".bump_secrets")
!secretFile.exists().let {
secretFile.createNewFile()
}
for(line in secretFile.readLines()) {
return line
}
return null
}
fun startUpdateHandler(context: Context) {
val delay: Long = 30_000 //milliseconds
val handler = Handler(Looper.getMainLooper())
handler.postDelayed(object : Runnable {
override fun run() {
updateFromServer(context)
handler.postDelayed(this, delay)
}
}, delay)
}
private fun updateFromServer(context: Context) {
rest.list(messenger.sender) {list -> updateLog(context, list)}
}
private fun addToLog(context: Context, line: JSONObject) {
val logFile = File(context.filesDir, ".bump_log")
logFile.appendText(line.toString())
}
fun addSecret(context: Context, newSecret: String) {
if(!hasSecret()) {
val secretFile = File(context.filesDir, ".bump_secrets")
!secretFile.exists().let {
secretFile.createNewFile()
}
secretFile.appendText(newSecret)
}
secret = getSecret(context)
}
private fun getLog(context: Context): JSONArray {
val logFile = File(context.filesDir, ".bump_log")
val log = JSONArray()
!logFile.exists().let {
logFile.createNewFile()
}
for(line in logFile.readLines()) {
log.put(JSONObject(line))
}
return log
}
}

View File

@ -31,9 +31,7 @@ import kotlin.math.min
import android.view.WindowInsets import android.view.WindowInsets
import android.graphics.Insets import android.graphics.Insets
import com.example.bump.BumpProcessor
class CameraFragment: Fragment() { class CameraFragment: Fragment() {
@ -182,6 +180,9 @@ class CameraFragment: Fragment() {
.addOnSuccessListener { barcodes -> .addOnSuccessListener { barcodes ->
barcodes.forEach { barcodes.forEach {
Log.d(TAG, it.rawValue!!) Log.d(TAG, it.rawValue!!)
val bump = BumpProcessor.getInstance(requireContext())
bump.addSecret(requireContext(), it.rawValue!!)
fragmentManager?.popBackStack()
} }
} }
.addOnFailureListener { .addOnFailureListener {

View File

@ -6,8 +6,13 @@ import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.findNavController
import com.example.bump.BumpProcessor
import com.example.bump.MessageProcessor import com.example.bump.MessageProcessor
import com.example.bump.RestSingleton
import com.maenle.bump.databinding.FragmentFirstBinding import com.maenle.bump.databinding.FragmentFirstBinding
import org.json.JSONArray
import org.json.JSONObject
import java.io.File
/** /**
* A simple [Fragment] subclass as the default destination in the navigation. * A simple [Fragment] subclass as the default destination in the navigation.
@ -20,6 +25,11 @@ class FirstFragment : Fragment() {
// onDestroyView. // onDestroyView.
private val binding get() = _binding!! private val binding get() = _binding!!
private lateinit var rest: RestSingleton
private lateinit var log: JSONArray
private val bump = BumpProcessor(requireContext())
override fun onCreateView( override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle? savedInstanceState: Bundle?
@ -27,21 +37,20 @@ class FirstFragment : Fragment() {
_binding = FragmentFirstBinding.inflate(inflater, container, false) _binding = FragmentFirstBinding.inflate(inflater, container, false)
return binding.root return binding.root
} }
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
if(bump.hasSecret()){
binding.buttonFirst.setOnClickListener { binding.buttonFirst.visibility = View.GONE
findNavController().navigate(R.id.action_FirstFragment_to_SecondFragment) } else {
binding.buttonFirst.setOnClickListener {
findNavController().navigate(R.id.action_FirstFragment_to_SecondFragment)
}
} }
testDecryption()
} }
fun testDecryption() {
}
override fun onDestroyView() { override fun onDestroyView() {
super.onDestroyView() super.onDestroyView()

View File

@ -0,0 +1,24 @@
package com.example.bump
import android.content.Context
import android.content.Context.MODE_PRIVATE
import android.content.SharedPreferences
import com.maenle.bump.R
class LocalData(context: Context) {
private val codeKey = context.getString(R.string.code_key)
private val preferenceKey = context.getString(R.string.preference_file_key)
private val preferences: SharedPreferences =
context.getSharedPreferences(preferenceKey, MODE_PRIVATE)
var code: String?
get() {
return preferences.getString(codeKey, null)
}
set(codeValue) {
preferences.edit().putString(codeKey, codeValue).apply()
}
// var messages: List<>
}

View File

@ -6,6 +6,7 @@ import android.content.Context
// Not object class. AndroidManifest.xml error happen. // Not object class. AndroidManifest.xml error happen.
class MainApplication : Application() { class MainApplication : Application() {
lateinit var rest : RestSingleton lateinit var rest : RestSingleton
lateinit var bump : BumpProcessor
init { init {
instance = this instance = this
@ -25,7 +26,10 @@ class MainApplication : Application() {
// Use ApplicationContext. // Use ApplicationContext.
// example: SharedPreferences etc... // example: SharedPreferences etc...
val context: Context = MainApplication.applicationContext() val context: Context = applicationContext()
rest = RestSingleton(context) rest = RestSingleton(context)
// bump = BumpProcessor(context)
// bump.startUpdateHandler(context)
} }
} }

View File

@ -0,0 +1,5 @@
package com.example.bump
class Message {
}

View File

@ -29,7 +29,7 @@ class RestSingleton constructor(context: Context){
private const val URL = "http://192.168.68.127:4000/api/" private const val URL = "http://192.168.68.127:4000/api/"
} }
fun list(sender: String, callback: (JSONObject) -> Unit){ fun list(sender: String, callback: (JSONArray) -> Unit){
val url = URL + "list/" val url = URL + "list/"
val data = JSONObject() val data = JSONObject()
data.put("sender", sender) data.put("sender", sender)
@ -38,10 +38,10 @@ class RestSingleton constructor(context: Context){
data, data,
{ response -> { response ->
run { run {
callback(response) callback(response.get("messages") as JSONArray)
} }
} , } ,
{callback(JSONObject())}) {callback(JSONArray())})
requestQueue.add(jsonRequest) requestQueue.add(jsonRequest)
} }

View File

@ -12,4 +12,6 @@
<string name="current_sender">No Sender Added</string> <string name="current_sender">No Sender Added</string>
<string name="scan_sender">Scan</string> <string name="scan_sender">Scan</string>
<string name="camera_fragment_label">Camera Fragment</string> <string name="camera_fragment_label">Camera Fragment</string>
<string name="preference_file_key">code_file_key</string>
<string name="code_key">code_key</string>
</resources> </resources>