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
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.Test
import org.junit.runner.RunWith
@ -28,6 +30,15 @@ class MessageProcessorTest {
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 {
@JvmStatic
fun decryptMessage(code: String, messageData: String): String {

View File

@ -68,9 +68,8 @@ class RestCryptTest{
val lock = CountDownLatch(1)
fun listTester(resultList: JSONObject) {
fun listTester(messages: JSONArray) {
val message = MessageProcessor(code)
val messages: JSONArray = resultList.get("messages") as JSONArray
var messageEncoded = messages[0] as JSONObject
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.graphics.Insets
import com.example.bump.BumpProcessor
class CameraFragment: Fragment() {
@ -182,6 +180,9 @@ class CameraFragment: Fragment() {
.addOnSuccessListener { barcodes ->
barcodes.forEach {
Log.d(TAG, it.rawValue!!)
val bump = BumpProcessor.getInstance(requireContext())
bump.addSecret(requireContext(), it.rawValue!!)
fragmentManager?.popBackStack()
}
}
.addOnFailureListener {

View File

@ -6,8 +6,13 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.navigation.fragment.findNavController
import com.example.bump.BumpProcessor
import com.example.bump.MessageProcessor
import com.example.bump.RestSingleton
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.
@ -20,6 +25,11 @@ class FirstFragment : Fragment() {
// onDestroyView.
private val binding get() = _binding!!
private lateinit var rest: RestSingleton
private lateinit var log: JSONArray
private val bump = BumpProcessor(requireContext())
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
@ -27,22 +37,21 @@ class FirstFragment : Fragment() {
_binding = FragmentFirstBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
if(bump.hasSecret()){
binding.buttonFirst.visibility = View.GONE
} else {
binding.buttonFirst.setOnClickListener {
findNavController().navigate(R.id.action_FirstFragment_to_SecondFragment)
}
testDecryption()
}
fun testDecryption() {
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null

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.
class MainApplication : Application() {
lateinit var rest : RestSingleton
lateinit var bump : BumpProcessor
init {
instance = this
@ -25,7 +26,10 @@ class MainApplication : Application() {
// Use ApplicationContext.
// example: SharedPreferences etc...
val context: Context = MainApplication.applicationContext()
val context: Context = applicationContext()
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/"
}
fun list(sender: String, callback: (JSONObject) -> Unit){
fun list(sender: String, callback: (JSONArray) -> Unit){
val url = URL + "list/"
val data = JSONObject()
data.put("sender", sender)
@ -38,10 +38,10 @@ class RestSingleton constructor(context: Context){
data,
{ response ->
run {
callback(response)
callback(response.get("messages") as JSONArray)
}
} ,
{callback(JSONObject())})
{callback(JSONArray())})
requestQueue.add(jsonRequest)
}

View File

@ -12,4 +12,6 @@
<string name="current_sender">No Sender Added</string>
<string name="scan_sender">Scan</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>