mirror of
https://github.com/YTVanced/VancedMicroG
synced 2024-11-30 23:23:01 +00:00
EN: Handle confirmation via resolution/pending intent instead of new task
This commit is contained in:
parent
fd6d915f0a
commit
d33391ebce
4 changed files with 82 additions and 50 deletions
|
@ -11,12 +11,14 @@ import android.widget.Button
|
|||
import android.widget.TextView
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import com.google.android.gms.R
|
||||
import com.google.android.gms.nearby.exposurenotification.ExposureNotificationStatusCodes.*
|
||||
import org.microg.gms.nearby.exposurenotification.*
|
||||
|
||||
class ExposureNotificationsConfirmActivity : AppCompatActivity() {
|
||||
private var resultCode: Int = FAILED
|
||||
private val resultData: Bundle = Bundle()
|
||||
private var resultCode: Int = RESULT_CANCELED
|
||||
set(value) {
|
||||
setResult(value)
|
||||
field = value
|
||||
}
|
||||
private val receiver: ResultReceiver?
|
||||
get() = intent.getParcelableExtra(KEY_CONFIRM_RECEIVER)
|
||||
private val action: String?
|
||||
|
@ -47,22 +49,22 @@ class ExposureNotificationsConfirmActivity : AppCompatActivity() {
|
|||
findViewById<Button>(android.R.id.button1).text = getString(R.string.exposure_confirm_keys_button)
|
||||
}
|
||||
else -> {
|
||||
resultCode = INTERNAL_ERROR
|
||||
resultCode = RESULT_CANCELED
|
||||
finish()
|
||||
}
|
||||
}
|
||||
findViewById<Button>(android.R.id.button1).setOnClickListener {
|
||||
resultCode = SUCCESS
|
||||
resultCode = RESULT_OK
|
||||
finish()
|
||||
}
|
||||
findViewById<Button>(android.R.id.button2).setOnClickListener {
|
||||
resultCode = FAILED_REJECTED_OPT_IN
|
||||
resultCode = RESULT_CANCELED
|
||||
finish()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onStop() {
|
||||
super.onStop()
|
||||
receiver?.send(resultCode, resultData)
|
||||
override fun finish() {
|
||||
receiver?.send(resultCode, Bundle())
|
||||
super.finish()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ const val KEY_CONFIRM_PACKAGE = "package"
|
|||
const val CONFIRM_ACTION_START = "start"
|
||||
const val CONFIRM_ACTION_STOP = "stop"
|
||||
const val CONFIRM_ACTION_KEYS = "keys"
|
||||
const val CONFIRM_PERMISSION_VALIDITY = 60 * 60 * 1000L
|
||||
|
||||
const val PERMISSION_EXPOSURE_CALLBACK = "com.google.android.gms.nearby.exposurenotification.EXPOSURE_CALLBACK"
|
||||
|
||||
|
|
|
@ -54,6 +54,9 @@ class ExposureDatabase private constructor(private val context: Context) : SQLit
|
|||
db.execSQL("CREATE TABLE IF NOT EXISTS $TABLE_DIAGNOSIS(package TEXT NOT NULL, token TEXT NOT NULL, tcid INTEGER REFERENCES $TABLE_TEK_CHECK(tcid) ON DELETE CASCADE, transmissionRiskLevel INTEGER NOT NULL);")
|
||||
db.execSQL("CREATE INDEX IF NOT EXISTS index_${TABLE_DIAGNOSIS}_package_token ON $TABLE_DIAGNOSIS(package, token);")
|
||||
}
|
||||
if (oldVersion < 3) {
|
||||
db.execSQL("CREATE TABLE $TABLE_APP_PERMS(package TEXT NOT NULL, sig TEXT NOT NULL, perm TEXT NOT NULL, timestamp INTEGER NOT NULL);")
|
||||
}
|
||||
}
|
||||
|
||||
fun SQLiteDatabase.delete(table: String, whereClause: String, args: LongArray): Int =
|
||||
|
@ -68,7 +71,23 @@ class ExposureDatabase private constructor(private val context: Context) : SQLit
|
|||
val appLogEntries = delete(TABLE_APP_LOG, "timestamp < ?", longArrayOf(rollingStartTime))
|
||||
val temporaryExposureKeys = delete(TABLE_TEK, "(rollingStartNumber + rollingPeriod) < ?", longArrayOf(rollingStartTime / ROLLING_WINDOW_LENGTH_MS))
|
||||
val checkedTemporaryExposureKeys = delete(TABLE_TEK_CHECK, "(rollingStartNumber + rollingPeriod) < ?", longArrayOf(rollingStartTime / ROLLING_WINDOW_LENGTH_MS))
|
||||
Log.d(TAG, "Deleted on daily cleanup: $advertisements adv, $appLogEntries applogs, $temporaryExposureKeys teks, $checkedTemporaryExposureKeys cteks")
|
||||
val appPerms = delete(TABLE_APP_PERMS, "timestamp < ?", longArrayOf(System.currentTimeMillis() - CONFIRM_PERMISSION_VALIDITY))
|
||||
Log.d(TAG, "Deleted on daily cleanup: $advertisements adv, $appLogEntries applogs, $temporaryExposureKeys teks, $checkedTemporaryExposureKeys cteks, $appPerms perms")
|
||||
}
|
||||
|
||||
fun grantPermission(packageName: String, signatureDigest: String, permission: String, timestamp: Long = System.currentTimeMillis()) = writableDatabase.run {
|
||||
insert(TABLE_APP_PERMS, "NULL", ContentValues().apply {
|
||||
put("package", packageName)
|
||||
put("sig", signatureDigest)
|
||||
put("perm", permission)
|
||||
put("timestamp", timestamp)
|
||||
})
|
||||
}
|
||||
|
||||
fun hasPermission(packageName: String, signatureDigest: String, permission: String, maxAge: Long = CONFIRM_PERMISSION_VALIDITY) = readableDatabase.run {
|
||||
query(TABLE_APP_PERMS, arrayOf("MAX(timestamp)"), "package = ? AND sig = ? and perm = ?", arrayOf(packageName, signatureDigest, permission), null, null, null).use { cursor ->
|
||||
cursor.moveToNext() && cursor.getLong(0) + maxAge > System.currentTimeMillis()
|
||||
}
|
||||
}
|
||||
|
||||
fun noteAdvertisement(rpi: ByteArray, aem: ByteArray, rssi: Int, timestamp: Long = Date().time) = writableDatabase.run {
|
||||
|
@ -496,13 +515,14 @@ class ExposureDatabase private constructor(private val context: Context) : SQLit
|
|||
|
||||
companion object {
|
||||
private const val DB_NAME = "exposure.db"
|
||||
private const val DB_VERSION = 2
|
||||
private const val DB_VERSION = 3
|
||||
private const val TABLE_ADVERTISEMENTS = "advertisements"
|
||||
private const val TABLE_APP_LOG = "app_log"
|
||||
private const val TABLE_TEK = "tek"
|
||||
private const val TABLE_TEK_CHECK = "tek_check"
|
||||
private const val TABLE_DIAGNOSIS = "diagnosis"
|
||||
private const val TABLE_CONFIGURATIONS = "configurations"
|
||||
private const val TABLE_APP_PERMS = "app_perms"
|
||||
|
||||
private var instance: ExposureDatabase? = null
|
||||
fun ref(context: Context): ExposureDatabase = synchronized(this) {
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
|
||||
package org.microg.gms.nearby.exposurenotification
|
||||
|
||||
import android.app.Activity
|
||||
import android.app.PendingIntent
|
||||
import android.content.ComponentName
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
|
@ -13,12 +15,14 @@ import android.os.*
|
|||
import android.util.Log
|
||||
import com.google.android.gms.common.api.CommonStatusCodes
|
||||
import com.google.android.gms.common.api.Status
|
||||
import com.google.android.gms.nearby.exposurenotification.ExposureNotificationStatusCodes
|
||||
import com.google.android.gms.nearby.exposurenotification.ExposureNotificationStatusCodes.*
|
||||
import com.google.android.gms.nearby.exposurenotification.ExposureSummary
|
||||
import com.google.android.gms.nearby.exposurenotification.TemporaryExposureKey
|
||||
import com.google.android.gms.nearby.exposurenotification.internal.*
|
||||
import org.json.JSONArray
|
||||
import org.json.JSONObject
|
||||
import org.microg.gms.common.PackageUtils
|
||||
import org.microg.gms.nearby.exposurenotification.Constants.*
|
||||
import org.microg.gms.nearby.exposurenotification.proto.TemporaryExposureKeyExport
|
||||
import org.microg.gms.nearby.exposurenotification.proto.TemporaryExposureKeyProto
|
||||
|
@ -26,48 +30,51 @@ import java.util.*
|
|||
import java.util.zip.ZipInputStream
|
||||
|
||||
class ExposureNotificationServiceImpl(private val context: Context, private val packageName: String) : INearbyExposureNotificationService.Stub() {
|
||||
private fun confirm(action: String, callback: (resultCode: Int, resultData: Bundle?) -> Unit) {
|
||||
private fun pendingConfirm(permission: String): PendingIntent {
|
||||
val intent = Intent(ACTION_CONFIRM)
|
||||
intent.`package` = context.packageName
|
||||
intent.putExtra(KEY_CONFIRM_PACKAGE, packageName)
|
||||
intent.putExtra(KEY_CONFIRM_ACTION, action)
|
||||
intent.putExtra(KEY_CONFIRM_RECEIVER, object : ResultReceiver(Handler(Looper.getMainLooper())) {
|
||||
intent.putExtra(KEY_CONFIRM_ACTION, permission)
|
||||
intent.putExtra(KEY_CONFIRM_RECEIVER, object : ResultReceiver(null) {
|
||||
override fun onReceiveResult(resultCode: Int, resultData: Bundle?) {
|
||||
Log.d(TAG, "Result from action $action: ${getStatusCodeString(resultCode)}")
|
||||
callback(resultCode, resultData)
|
||||
if (resultCode == Activity.RESULT_OK) {
|
||||
ExposureDatabase.with(context) { database -> database.grantPermission(packageName, PackageUtils.firstSignatureDigest(context, packageName)!!, permission) }
|
||||
}
|
||||
}
|
||||
})
|
||||
intent.addFlags(FLAG_ACTIVITY_NEW_TASK)
|
||||
intent.addFlags(FLAG_ACTIVITY_MULTIPLE_TASK)
|
||||
intent.addFlags(FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)
|
||||
try {
|
||||
intent.component = ComponentName(context, context.packageManager.resolveActivity(intent, 0)?.activityInfo?.name!!)
|
||||
context.startActivity(intent)
|
||||
} catch (e: Exception) {
|
||||
Log.w(TAG, e)
|
||||
callback(CommonStatusCodes.INTERNAL_ERROR, null)
|
||||
}
|
||||
Log.d(TAG, "Pending: $intent")
|
||||
val pi = PendingIntent.getActivity(context, permission.hashCode(), intent, PendingIntent.FLAG_ONE_SHOT)
|
||||
Log.d(TAG, "Pending: $pi")
|
||||
return pi
|
||||
}
|
||||
|
||||
private fun confirmPermission(permission: String): Status {
|
||||
if (packageName == context.packageName) return Status.SUCCESS
|
||||
return ExposureDatabase.with(context) { database ->
|
||||
if (!database.hasPermission(packageName, PackageUtils.firstSignatureDigest(context, packageName)!!, permission)) {
|
||||
Status(RESOLUTION_REQUIRED, "Permission EN#$permission required.", pendingConfirm(permission))
|
||||
} else {
|
||||
Status.SUCCESS
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun start(params: StartParams) {
|
||||
if (ExposurePreferences(context).enabled) {
|
||||
params.callback.onResult(Status(FAILED_ALREADY_STARTED))
|
||||
return
|
||||
if (ExposurePreferences(context).enabled) return
|
||||
val status = confirmPermission(CONFIRM_ACTION_START)
|
||||
if (status.isSuccess) {
|
||||
ExposurePreferences(context).enabled = true
|
||||
ExposureDatabase.with(context) { database -> database.noteAppAction(packageName, "start") }
|
||||
}
|
||||
confirm(CONFIRM_ACTION_START) { resultCode, resultData ->
|
||||
if (resultCode == SUCCESS) {
|
||||
ExposurePreferences(context).enabled = true
|
||||
}
|
||||
ExposureDatabase.with(context) { database ->
|
||||
database.noteAppAction(packageName, "start", JSONObject().apply {
|
||||
put("result", resultCode)
|
||||
}.toString())
|
||||
}
|
||||
try {
|
||||
params.callback.onResult(Status(if (resultCode == SUCCESS) SUCCESS else FAILED_REJECTED_OPT_IN, resultData?.getString("message")))
|
||||
} catch (e: Exception) {
|
||||
Log.w(TAG, "Callback failed", e)
|
||||
}
|
||||
try {
|
||||
params.callback.onResult(status)
|
||||
} catch (e: Exception) {
|
||||
Log.w(TAG, "Callback failed", e)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -91,23 +98,25 @@ class ExposureNotificationServiceImpl(private val context: Context, private val
|
|||
}
|
||||
}
|
||||
|
||||
override fun getTemporaryExposureKeyHistory(params: GetTemporaryExposureKeyHistoryParams): Unit = ExposureDatabase.with(context) { database ->
|
||||
confirm(CONFIRM_ACTION_START) { resultCode, resultData ->
|
||||
val (status, response) = if (resultCode == SUCCESS) {
|
||||
SUCCESS to database.allKeys
|
||||
} else {
|
||||
FAILED_REJECTED_OPT_IN to emptyList()
|
||||
override fun getTemporaryExposureKeyHistory(params: GetTemporaryExposureKeyHistoryParams) {
|
||||
val status = confirmPermission(CONFIRM_ACTION_KEYS)
|
||||
val response = when {
|
||||
status.isSuccess -> ExposureDatabase.with(context) { database ->
|
||||
database.allKeys
|
||||
}
|
||||
else -> emptyList()
|
||||
}
|
||||
|
||||
ExposureDatabase.with(context) { database ->
|
||||
database.noteAppAction(packageName, "getTemporaryExposureKeyHistory", JSONObject().apply {
|
||||
put("result", resultCode)
|
||||
put("result", status.statusCode)
|
||||
put("response_keys_size", response.size)
|
||||
}.toString())
|
||||
try {
|
||||
params.callback.onResult(Status(status, resultData?.getString("message")), response)
|
||||
} catch (e: Exception) {
|
||||
Log.w(TAG, "Callback failed", e)
|
||||
}
|
||||
}
|
||||
try {
|
||||
params.callback.onResult(status, response)
|
||||
} catch (e: Exception) {
|
||||
Log.w(TAG, "Callback failed", e)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue