diff --git a/play-services-nearby-core/src/main/AndroidManifest.xml b/play-services-nearby-core/src/main/AndroidManifest.xml index 83a8bda1..e40ecda8 100644 --- a/play-services-nearby-core/src/main/AndroidManifest.xml +++ b/play-services-nearby-core/src/main/AndroidManifest.xml @@ -14,6 +14,9 @@ + + + @@ -24,6 +27,8 @@ + + diff --git a/play-services-nearby-core/src/main/kotlin/org/microg/gms/nearby/exposurenotification/AdvertiserService.kt b/play-services-nearby-core/src/main/kotlin/org/microg/gms/nearby/exposurenotification/AdvertiserService.kt index 417aaf8e..d3e0b2e8 100644 --- a/play-services-nearby-core/src/main/kotlin/org/microg/gms/nearby/exposurenotification/AdvertiserService.kt +++ b/play-services-nearby-core/src/main/kotlin/org/microg/gms/nearby/exposurenotification/AdvertiserService.kt @@ -76,7 +76,7 @@ class AdvertiserService : LifecycleService() { override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { ForegroundServiceContext.completeForegroundService(this, intent, TAG) super.onStartCommand(intent, flags, startId) - if (ExposurePreferences(this).advertiserEnabled) { + if (ExposurePreferences(this).enabled) { loopAdvertising() } else { stopSelf() @@ -191,7 +191,7 @@ class AdvertiserService : LifecycleService() { companion object { fun isNeeded(context: Context): Boolean { - return ExposurePreferences(context).scannerEnabled + return ExposurePreferences(context).enabled } } } diff --git a/play-services-nearby-core/src/main/kotlin/org/microg/gms/nearby/exposurenotification/CleanupService.kt b/play-services-nearby-core/src/main/kotlin/org/microg/gms/nearby/exposurenotification/CleanupService.kt index f7908f85..0883b803 100644 --- a/play-services-nearby-core/src/main/kotlin/org/microg/gms/nearby/exposurenotification/CleanupService.kt +++ b/play-services-nearby-core/src/main/kotlin/org/microg/gms/nearby/exposurenotification/CleanupService.kt @@ -27,7 +27,7 @@ class CleanupService : LifecycleService() { companion object { fun isNeeded(context: Context): Boolean { return ExposurePreferences(context).let { - it.scannerEnabled && it.lastCleanup < System.currentTimeMillis() - CLEANUP_INTERVAL + it.enabled && it.lastCleanup < System.currentTimeMillis() - CLEANUP_INTERVAL } } } diff --git a/play-services-nearby-core/src/main/kotlin/org/microg/gms/nearby/exposurenotification/ExposureNotificationServiceImpl.kt b/play-services-nearby-core/src/main/kotlin/org/microg/gms/nearby/exposurenotification/ExposureNotificationServiceImpl.kt index efbb7c74..a14bf339 100644 --- a/play-services-nearby-core/src/main/kotlin/org/microg/gms/nearby/exposurenotification/ExposureNotificationServiceImpl.kt +++ b/play-services-nearby-core/src/main/kotlin/org/microg/gms/nearby/exposurenotification/ExposureNotificationServiceImpl.kt @@ -50,13 +50,13 @@ class ExposureNotificationServiceImpl(private val context: Context, private val } override fun start(params: StartParams) { - if (ExposurePreferences(context).scannerEnabled) { + if (ExposurePreferences(context).enabled) { params.callback.onResult(Status(FAILED_ALREADY_STARTED)) return } confirm(CONFIRM_ACTION_START) { resultCode, resultData -> if (resultCode == SUCCESS) { - ExposurePreferences(context).scannerEnabled = true + ExposurePreferences(context).enabled = true } ExposureDatabase.with(context) { database -> database.noteAppAction(packageName, "start", JSONObject().apply { @@ -72,13 +72,13 @@ class ExposureNotificationServiceImpl(private val context: Context, private val } override fun stop(params: StopParams) { - if (!ExposurePreferences(context).scannerEnabled) { + if (!ExposurePreferences(context).enabled) { params.callback.onResult(Status.SUCCESS) return } confirm(CONFIRM_ACTION_STOP) { resultCode, _ -> if (resultCode == SUCCESS) { - ExposurePreferences(context).scannerEnabled = false + ExposurePreferences(context).enabled = false } ExposureDatabase.with(context) { database -> database.noteAppAction(packageName, "stop", JSONObject().apply { @@ -95,7 +95,7 @@ class ExposureNotificationServiceImpl(private val context: Context, private val override fun isEnabled(params: IsEnabledParams) { try { - params.callback.onResult(Status.SUCCESS, ExposurePreferences(context).scannerEnabled) + params.callback.onResult(Status.SUCCESS, ExposurePreferences(context).enabled) } catch (e: Exception) { Log.w(TAG, "Callback failed", e) } diff --git a/play-services-nearby-core/src/main/kotlin/org/microg/gms/nearby/exposurenotification/ExposurePreferences.kt b/play-services-nearby-core/src/main/kotlin/org/microg/gms/nearby/exposurenotification/ExposurePreferences.kt index 1945d519..511e3b02 100644 --- a/play-services-nearby-core/src/main/kotlin/org/microg/gms/nearby/exposurenotification/ExposurePreferences.kt +++ b/play-services-nearby-core/src/main/kotlin/org/microg/gms/nearby/exposurenotification/ExposurePreferences.kt @@ -8,13 +8,21 @@ package org.microg.gms.nearby.exposurenotification import android.content.Context import android.content.Intent import android.content.SharedPreferences +import android.util.Log import androidx.preference.PreferenceManager +import org.microg.gms.common.PackageUtils class ExposurePreferences(private val context: Context) { private var preferences: SharedPreferences = PreferenceManager.getDefaultSharedPreferences(context) - var scannerEnabled + init { + if (context.packageName != PackageUtils.getProcessName()) { + Log.w("Preferences", ExposurePreferences::class.simpleName + " initialized outside main process", RuntimeException()) + } + } + + var enabled get() = preferences.getBoolean(PREF_SCANNER_ENABLED, false) set(newStatus) { preferences.edit().putBoolean(PREF_SCANNER_ENABLED, newStatus).commit() @@ -26,9 +34,6 @@ class ExposurePreferences(private val context: Context) { } } - val advertiserEnabled - get() = scannerEnabled - var lastCleanup get() = preferences.getLong(PREF_LAST_CLEANUP, 0) set(value) = preferences.edit().putLong(PREF_LAST_CLEANUP, value).apply() diff --git a/play-services-nearby-core/src/main/kotlin/org/microg/gms/nearby/exposurenotification/ScannerService.kt b/play-services-nearby-core/src/main/kotlin/org/microg/gms/nearby/exposurenotification/ScannerService.kt index f180e1d6..470beca7 100644 --- a/play-services-nearby-core/src/main/kotlin/org/microg/gms/nearby/exposurenotification/ScannerService.kt +++ b/play-services-nearby-core/src/main/kotlin/org/microg/gms/nearby/exposurenotification/ScannerService.kt @@ -7,7 +7,6 @@ package org.microg.gms.nearby.exposurenotification import android.annotation.TargetApi import android.app.Service -import android.bluetooth.BluetoothAdapter import android.bluetooth.BluetoothAdapter.* import android.bluetooth.le.* import android.content.BroadcastReceiver @@ -76,7 +75,7 @@ class ScannerService : Service() { } fun startScanIfNeeded() { - if (ExposurePreferences(this).scannerEnabled) { + if (ExposurePreferences(this).enabled) { startScan() } else { stopSelf() @@ -138,7 +137,7 @@ class ScannerService : Service() { companion object { fun isNeeded(context: Context): Boolean { - return ExposurePreferences(context).scannerEnabled + return ExposurePreferences(context).enabled } } } diff --git a/play-services-nearby-core/src/main/kotlin/org/microg/gms/nearby/exposurenotification/ServiceInfo.kt b/play-services-nearby-core/src/main/kotlin/org/microg/gms/nearby/exposurenotification/ServiceInfo.kt new file mode 100644 index 00000000..1379e9ce --- /dev/null +++ b/play-services-nearby-core/src/main/kotlin/org/microg/gms/nearby/exposurenotification/ServiceInfo.kt @@ -0,0 +1,89 @@ +/* + * SPDX-FileCopyrightText: 2020, microG Project Team + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.microg.gms.nearby.exposurenotification + +import android.content.BroadcastReceiver +import android.content.Context +import android.content.Intent +import android.content.IntentFilter +import android.util.Log +import java.io.Serializable +import kotlin.coroutines.resume +import kotlin.coroutines.resumeWithException +import kotlin.coroutines.suspendCoroutine + +private const val ACTION_SERVICE_INFO_REQUEST = "org.microg.gms.nearby.exposurenotification.SERVICE_INFO_REQUEST" +private const val ACTION_UPDATE_CONFIGURATION = "org.microg.gms.nearby.exposurenotification.UPDATE_CONFIGURATION" +private const val ACTION_SERVICE_INFO_RESPONSE = "org.microg.gms.nearby.exposurenotification.SERVICE_INFO_RESPONSE" +private const val EXTRA_SERVICE_INFO = "org.microg.gms.nearby.exposurenotification.SERVICE_INFO" +private const val EXTRA_CONFIGURATION = "org.microg.gms.nearby.exposurenotification.CONFIGURATION" + +data class ServiceInfo(val configuration: ServiceConfiguration) : Serializable + +data class ServiceConfiguration(val enabled: Boolean) : Serializable { + fun saveToPrefs(context: Context) { + ExposurePreferences(context).enabled = enabled + } +} + +private fun ExposurePreferences.toConfiguration(): ServiceConfiguration = ServiceConfiguration(enabled) + +class ServiceInfoReceiver : BroadcastReceiver() { + private fun sendInfoResponse(context: Context) { + context.sendOrderedBroadcast(Intent(ACTION_SERVICE_INFO_RESPONSE).apply { + setPackage(context.packageName) + putExtra(EXTRA_SERVICE_INFO, ServiceInfo(ExposurePreferences(context).toConfiguration())) + }, null) + } + + override fun onReceive(context: Context, intent: Intent) { + try { + when (intent.action) { + ACTION_UPDATE_CONFIGURATION -> { + (intent.getSerializableExtra(EXTRA_CONFIGURATION) as? ServiceConfiguration)?.saveToPrefs(context) + } + } + sendInfoResponse(context) + } catch (e: Exception) { + Log.w(TAG, e) + } + } +} + +private suspend fun sendToServiceInfoReceiver(intent: Intent, context: Context): ServiceInfo = suspendCoroutine { + context.registerReceiver(object : BroadcastReceiver() { + override fun onReceive(context: Context, intent: Intent) { + context.unregisterReceiver(this) + val serviceInfo = try { + intent.getSerializableExtra(EXTRA_SERVICE_INFO) as ServiceInfo + } catch (e: Exception) { + it.resumeWithException(e) + return + } + try { + it.resume(serviceInfo) + } catch (e: Exception) { + Log.w(TAG, e) + } + } + }, IntentFilter(ACTION_SERVICE_INFO_RESPONSE)) + try { + context.sendOrderedBroadcast(intent, null) + } catch (e: Exception) { + it.resumeWithException(e) + } +} + +suspend fun getExposureNotificationsServiceInfo(context: Context): ServiceInfo = sendToServiceInfoReceiver( + Intent(context, ServiceInfoReceiver::class.java).apply { + action = ACTION_SERVICE_INFO_REQUEST + }, context) + +suspend fun setExposureNotificationsServiceConfiguration(context: Context, configuration: ServiceConfiguration): ServiceInfo = sendToServiceInfoReceiver( + Intent(context, ServiceInfoReceiver::class.java).apply { + action = ACTION_UPDATE_CONFIGURATION + putExtra(EXTRA_CONFIGURATION, configuration) + }, context)