mirror of
https://github.com/YTVanced/VancedMicroG
synced 2024-11-30 23:23:01 +00:00
Update EN API
This commit is contained in:
parent
e1bb395ff8
commit
aea55a5c90
6 changed files with 169 additions and 42 deletions
|
@ -45,7 +45,7 @@ class ExposureNotificationsRpisFragment : PreferenceFragmentCompat() {
|
||||||
val (totalRpiCount, rpiHistogram) = withContext(Dispatchers.IO) {
|
val (totalRpiCount, rpiHistogram) = withContext(Dispatchers.IO) {
|
||||||
ExposureDatabase.with(requireContext()) { database ->
|
ExposureDatabase.with(requireContext()) { database ->
|
||||||
val map = linkedMapOf<String, Float>()
|
val map = linkedMapOf<String, Float>()
|
||||||
val lowestDate = Math.round((Date().time / 24 / 60 / 60 / 1000 - 13).toDouble()) * 24 * 60 * 60 * 1000
|
val lowestDate = Math.round((System.currentTimeMillis() / 24 / 60 / 60 / 1000 - 13).toDouble()) * 24 * 60 * 60 * 1000
|
||||||
for (i in 0..13) {
|
for (i in 0..13) {
|
||||||
val date = Calendar.getInstance().apply { this.time = Date(lowestDate + i * 24 * 60 * 60 * 1000) }.get(Calendar.DAY_OF_MONTH)
|
val date = Calendar.getInstance().apply { this.time = Date(lowestDate + i * 24 * 60 * 60 * 1000) }.get(Calendar.DAY_OF_MONTH)
|
||||||
val str = when (i) {
|
val str = when (i) {
|
||||||
|
@ -58,6 +58,7 @@ class ExposureNotificationsRpisFragment : PreferenceFragmentCompat() {
|
||||||
val refDateHigh = Calendar.getInstance().apply { this.time = Date(lowestDate + 13 * 24 * 60 * 60 * 1000) }.get(Calendar.DAY_OF_MONTH)
|
val refDateHigh = Calendar.getInstance().apply { this.time = Date(lowestDate + 13 * 24 * 60 * 60 * 1000) }.get(Calendar.DAY_OF_MONTH)
|
||||||
for (entry in database.rpiHistogram) {
|
for (entry in database.rpiHistogram) {
|
||||||
val time = Date(entry.key * 24 * 60 * 60 * 1000)
|
val time = Date(entry.key * 24 * 60 * 60 * 1000)
|
||||||
|
if (time.time < lowestDate) continue // Ignore old data
|
||||||
val date = Calendar.getInstance().apply { this.time = time }.get(Calendar.DAY_OF_MONTH)
|
val date = Calendar.getInstance().apply { this.time = time }.get(Calendar.DAY_OF_MONTH)
|
||||||
val str = when (date) {
|
val str = when (date) {
|
||||||
refDateLow, refDateHigh -> DateFormat.format(DateFormat.getBestDateTimePattern(Locale.getDefault(), "MMMd"), entry.key * 24 * 60 * 60 * 1000).toString()
|
refDateLow, refDateHigh -> DateFormat.format(DateFormat.getBestDateTimePattern(Locale.getDefault(), "MMMd"), entry.key * 24 * 60 * 60 * 1000).toString()
|
||||||
|
|
|
@ -30,9 +30,6 @@
|
||||||
<receiver android:name="org.microg.gms.nearby.exposurenotification.ServiceTrigger">
|
<receiver android:name="org.microg.gms.nearby.exposurenotification.ServiceTrigger">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
||||||
<action android:name="android.intent.action.AIRPLANE_MODE" />
|
|
||||||
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
|
|
||||||
<action android:name="android.net.conn.BACKGROUND_DATA_SETTING_CHANGED" />
|
|
||||||
|
|
||||||
<action android:name="android.intent.action.MY_PACKAGE_REPLACED" />
|
<action android:name="android.intent.action.MY_PACKAGE_REPLACED" />
|
||||||
<action android:name="android.intent.action.PACKAGE_RESTARTED" />
|
<action android:name="android.intent.action.PACKAGE_RESTARTED" />
|
||||||
|
|
|
@ -9,7 +9,10 @@ import android.annotation.TargetApi
|
||||||
import android.bluetooth.BluetoothAdapter
|
import android.bluetooth.BluetoothAdapter
|
||||||
import android.bluetooth.le.*
|
import android.bluetooth.le.*
|
||||||
import android.bluetooth.le.AdvertiseSettings.*
|
import android.bluetooth.le.AdvertiseSettings.*
|
||||||
|
import android.content.BroadcastReceiver
|
||||||
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
|
import android.content.IntentFilter
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import androidx.lifecycle.LifecycleService
|
import androidx.lifecycle.LifecycleService
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
|
@ -25,10 +28,27 @@ import kotlin.coroutines.suspendCoroutine
|
||||||
@TargetApi(21)
|
@TargetApi(21)
|
||||||
class AdvertiserService : LifecycleService() {
|
class AdvertiserService : LifecycleService() {
|
||||||
private val version = VERSION_1_0
|
private val version = VERSION_1_0
|
||||||
|
private var looping = false
|
||||||
private var callback: AdvertiseCallback? = null
|
private var callback: AdvertiseCallback? = null
|
||||||
private val advertiser: BluetoothLeAdvertiser
|
private val advertiser: BluetoothLeAdvertiser?
|
||||||
get() = BluetoothAdapter.getDefaultAdapter().bluetoothLeAdvertiser
|
get() = BluetoothAdapter.getDefaultAdapter().bluetoothLeAdvertiser
|
||||||
private lateinit var database: ExposureDatabase
|
private lateinit var database: ExposureDatabase
|
||||||
|
private val trigger = object : BroadcastReceiver() {
|
||||||
|
override fun onReceive(context: Context?, intent: Intent?) {
|
||||||
|
if (intent?.action == "android.bluetooth.adapter.action.STATE_CHANGED") {
|
||||||
|
when (intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1)) {
|
||||||
|
BluetoothAdapter.STATE_TURNING_OFF, BluetoothAdapter.STATE_OFF -> stopAdvertising()
|
||||||
|
BluetoothAdapter.STATE_ON -> {
|
||||||
|
if (looping) {
|
||||||
|
lifecycleScope.launchWhenStarted { restartAdvertising() }
|
||||||
|
} else {
|
||||||
|
loopAdvertising()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private suspend fun BluetoothLeAdvertiser.startAdvertising(settings: AdvertiseSettings, advertiseData: AdvertiseData): AdvertiseCallback = suspendCoroutine {
|
private suspend fun BluetoothLeAdvertiser.startAdvertising(settings: AdvertiseSettings, advertiseData: AdvertiseData): AdvertiseCallback = suspendCoroutine {
|
||||||
startAdvertising(settings, advertiseData, object : AdvertiseCallback() {
|
startAdvertising(settings, advertiseData, object : AdvertiseCallback() {
|
||||||
|
@ -45,12 +65,13 @@ class AdvertiserService : LifecycleService() {
|
||||||
override fun onCreate() {
|
override fun onCreate() {
|
||||||
super.onCreate()
|
super.onCreate()
|
||||||
database = ExposureDatabase.ref(this)
|
database = ExposureDatabase.ref(this)
|
||||||
|
registerReceiver(trigger, IntentFilter().also { it.addAction("android.bluetooth.adapter.action.STATE_CHANGED") })
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||||
super.onStartCommand(intent, flags, startId)
|
super.onStartCommand(intent, flags, startId)
|
||||||
if (ExposurePreferences(this).advertiserEnabled) {
|
if (ExposurePreferences(this).advertiserEnabled) {
|
||||||
startAdvertising()
|
loopAdvertising()
|
||||||
} else {
|
} else {
|
||||||
stopSelf()
|
stopSelf()
|
||||||
}
|
}
|
||||||
|
@ -59,40 +80,63 @@ class AdvertiserService : LifecycleService() {
|
||||||
|
|
||||||
override fun onDestroy() {
|
override fun onDestroy() {
|
||||||
super.onDestroy()
|
super.onDestroy()
|
||||||
|
unregisterReceiver(trigger)
|
||||||
stopAdvertising()
|
stopAdvertising()
|
||||||
database.unref()
|
database.unref()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun startAdvertising() {
|
@Synchronized
|
||||||
|
fun loopAdvertising() {
|
||||||
|
if (looping) return
|
||||||
|
looping = true
|
||||||
lifecycleScope.launchWhenStarted {
|
lifecycleScope.launchWhenStarted {
|
||||||
do {
|
Log.d(TAG, "Looping advertising")
|
||||||
val aem = when (version) {
|
try {
|
||||||
VERSION_1_0 -> byteArrayOf(
|
do {
|
||||||
version, // Version and flags
|
val aem = when (version) {
|
||||||
(currentDeviceInfo.txPowerCorrection + TX_POWER_LOW).toByte(), // TX power
|
VERSION_1_0 -> byteArrayOf(
|
||||||
0x00, // Reserved
|
version, // Version and flags
|
||||||
0x00 // Reserved
|
(currentDeviceInfo.txPowerCorrection + TX_POWER_LOW).toByte(), // TX power
|
||||||
)
|
0x00, // Reserved
|
||||||
VERSION_1_1 -> byteArrayOf(
|
0x00 // Reserved
|
||||||
(version + currentDeviceInfo.confidence * 4).toByte(), // Version and flags
|
)
|
||||||
(currentDeviceInfo.txPowerCorrection + TX_POWER_LOW).toByte(), // TX power
|
VERSION_1_1 -> byteArrayOf(
|
||||||
0x00, // Reserved
|
(version + currentDeviceInfo.confidence * 4).toByte(), // Version and flags
|
||||||
0x00 // Reserved
|
(currentDeviceInfo.txPowerCorrection + TX_POWER_LOW).toByte(), // TX power
|
||||||
)
|
0x00, // Reserved
|
||||||
else -> return@launchWhenStarted
|
0x00 // Reserved
|
||||||
}
|
)
|
||||||
val payload = database.generateCurrentPayload(aem)
|
else -> return@launchWhenStarted
|
||||||
var nextSend = nextKeyMillis.coerceAtMost(180000)
|
}
|
||||||
startAdvertising(payload, nextSend.toInt())
|
val payload = database.generateCurrentPayload(aem)
|
||||||
delay(nextSend)
|
var nextSend = nextKeyMillis.coerceAtMost(180000)
|
||||||
} while (callback != null)
|
startAdvertising(payload, nextSend.toInt())
|
||||||
|
if (callback != null) delay(nextSend)
|
||||||
|
} while (callback != null)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.w(TAG, "Error during advertising loop", e)
|
||||||
|
}
|
||||||
|
Log.d(TAG, "No longer advertising")
|
||||||
|
synchronized(this@AdvertiserService) {
|
||||||
|
looping = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var startTime = System.currentTimeMillis()
|
||||||
|
var sendingBytes = ByteArray(0)
|
||||||
|
var sendingNext = 0
|
||||||
suspend fun startAdvertising(bytes: ByteArray, nextSend: Int) {
|
suspend fun startAdvertising(bytes: ByteArray, nextSend: Int) {
|
||||||
|
startTime = System.currentTimeMillis()
|
||||||
|
sendingBytes = bytes
|
||||||
|
sendingNext = nextSend
|
||||||
|
continueAdvertising(bytes, nextSend)
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun continueAdvertising(bytes: ByteArray, nextSend: Int) {
|
||||||
stopAdvertising()
|
stopAdvertising()
|
||||||
val data = AdvertiseData.Builder().addServiceUuid(SERVICE_UUID).addServiceData(SERVICE_UUID, bytes).build()
|
val data = AdvertiseData.Builder().addServiceUuid(SERVICE_UUID).addServiceData(SERVICE_UUID, bytes).build()
|
||||||
val settings = AdvertiseSettings.Builder()
|
val settings = Builder()
|
||||||
.setTimeout(nextSend)
|
.setTimeout(nextSend)
|
||||||
.setAdvertiseMode(ADVERTISE_MODE_LOW_POWER)
|
.setAdvertiseMode(ADVERTISE_MODE_LOW_POWER)
|
||||||
.setTxPowerLevel(ADVERTISE_TX_POWER_MEDIUM)
|
.setTxPowerLevel(ADVERTISE_TX_POWER_MEDIUM)
|
||||||
|
@ -100,18 +144,42 @@ class AdvertiserService : LifecycleService() {
|
||||||
.build()
|
.build()
|
||||||
val (uuid, aem) = ByteBuffer.wrap(bytes).let { UUID(it.long, it.long) to it.int }
|
val (uuid, aem) = ByteBuffer.wrap(bytes).let { UUID(it.long, it.long) to it.int }
|
||||||
Log.d(TAG, "RPI: $uuid, Version: 0x${version.toString(16)}, TX Power: ${currentDeviceInfo.txPowerCorrection + TX_POWER_LOW}, AEM: 0x${aem.toLong().let { if (it < 0) 0x100000000L + it else it }.toString(16)}, Timeout: ${nextSend}ms")
|
Log.d(TAG, "RPI: $uuid, Version: 0x${version.toString(16)}, TX Power: ${currentDeviceInfo.txPowerCorrection + TX_POWER_LOW}, AEM: 0x${aem.toLong().let { if (it < 0) 0x100000000L + it else it }.toString(16)}, Timeout: ${nextSend}ms")
|
||||||
callback = advertiser.startAdvertising(settings, data)
|
callback = advertiser?.startAdvertising(settings, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun restartAdvertising() {
|
||||||
|
val startTime = startTime
|
||||||
|
val bytes = sendingBytes
|
||||||
|
val next = sendingNext
|
||||||
|
if (next == 0 || bytes.isEmpty()) return
|
||||||
|
val nextSend = (startTime - System.currentTimeMillis() + next).toInt()
|
||||||
|
if (nextSend < 5000) return
|
||||||
|
continueAdvertising(bytes, nextSend)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun dump(fd: FileDescriptor?, writer: PrintWriter?, args: Array<out String>?) {
|
override fun dump(fd: FileDescriptor?, writer: PrintWriter?, args: Array<out String>?) {
|
||||||
|
writer?.println("Looping: $looping")
|
||||||
writer?.println("Active: ${callback != null}")
|
writer?.println("Active: ${callback != null}")
|
||||||
writer?.println("Currently advertising: ${database.currentRpiId}")
|
try {
|
||||||
writer?.println("Next key change in ${nextKeyMillis}ms")
|
val startTime = startTime
|
||||||
|
val bytes = sendingBytes
|
||||||
|
val (uuid, aem) = ByteBuffer.wrap(bytes).let { UUID(it.long, it.long) to it.int }
|
||||||
|
writer?.println("""
|
||||||
|
Last advertising:
|
||||||
|
Since: ${Date(startTime)}
|
||||||
|
RPI: $uuid
|
||||||
|
Version: 0x${version.toString(16)}
|
||||||
|
TX Power: ${currentDeviceInfo.txPowerCorrection + TX_POWER_LOW}
|
||||||
|
AEM: 0x${aem.toLong().let { if (it < 0) 0x100000000L + it else it }.toString(16)}
|
||||||
|
""".trimIndent())
|
||||||
|
} catch (e: Exception) {
|
||||||
|
writer?.println("Last advertising: ${e.message ?: e.toString()}")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Synchronized
|
@Synchronized
|
||||||
fun stopAdvertising() {
|
fun stopAdvertising() {
|
||||||
callback?.let { advertiser.stopAdvertising(it) }
|
callback?.let { advertiser?.stopAdvertising(it) }
|
||||||
callback = null
|
callback = null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,8 +23,8 @@ val currentDeviceInfo: DeviceInfo
|
||||||
get() {
|
get() {
|
||||||
var deviceInfo = knownDeviceInfo
|
var deviceInfo = knownDeviceInfo
|
||||||
if (deviceInfo == null) {
|
if (deviceInfo == null) {
|
||||||
val byOem = allDeviceInfos.filter { it.oem == Build.MANUFACTURER }
|
val byOem = allDeviceInfos.filter { it.oem.equalsIgnoreCase(Build.MANUFACTURER) }
|
||||||
val exactMatch = byOem.find { it.model == Build.MODEL }
|
val exactMatch = byOem.find { it.model.equalsIgnoreCase(Build.MODEL) }
|
||||||
deviceInfo = when {
|
deviceInfo = when {
|
||||||
exactMatch != null -> {
|
exactMatch != null -> {
|
||||||
// Exact match
|
// Exact match
|
||||||
|
@ -45,6 +45,9 @@ val currentDeviceInfo: DeviceInfo
|
||||||
return deviceInfo
|
return deviceInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN")
|
||||||
|
private fun String.equalsIgnoreCase(other: String): Boolean = (this as java.lang.String).equalsIgnoreCase(other)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Derived from en-calibration-2020-06-13.csv published via
|
* Derived from en-calibration-2020-06-13.csv published via
|
||||||
* https://developers.google.com/android/exposure-notifications/ble-attenuation-computation#device-list
|
* https://developers.google.com/android/exposure-notifications/ble-attenuation-computation#device-list
|
||||||
|
|
|
@ -8,42 +8,86 @@ package org.microg.gms.nearby.exposurenotification
|
||||||
import android.annotation.TargetApi
|
import android.annotation.TargetApi
|
||||||
import android.app.Service
|
import android.app.Service
|
||||||
import android.bluetooth.BluetoothAdapter
|
import android.bluetooth.BluetoothAdapter
|
||||||
|
import android.bluetooth.BluetoothAdapter.*
|
||||||
import android.bluetooth.le.*
|
import android.bluetooth.le.*
|
||||||
|
import android.content.BroadcastReceiver
|
||||||
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
|
import android.content.IntentFilter
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.IBinder
|
import android.os.IBinder
|
||||||
|
import android.util.Log
|
||||||
|
import java.io.FileDescriptor
|
||||||
|
import java.io.PrintWriter
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
@TargetApi(21)
|
@TargetApi(21)
|
||||||
class ScannerService : Service() {
|
class ScannerService : Service() {
|
||||||
private var started = false
|
private var started = false
|
||||||
|
private var startTime = 0L
|
||||||
|
private var seenAdvertisements = 0L
|
||||||
private lateinit var database: ExposureDatabase
|
private lateinit var database: ExposureDatabase
|
||||||
private val callback = object : ScanCallback() {
|
private val callback = object : ScanCallback() {
|
||||||
override fun onScanResult(callbackType: Int, result: ScanResult?) {
|
override fun onScanResult(callbackType: Int, result: ScanResult?) {
|
||||||
val data = result?.scanRecord?.serviceData?.get(SERVICE_UUID) ?: return
|
result?.let { onScanResult(it) }
|
||||||
if (data.size < 16) return // Ignore invalid advertisements
|
}
|
||||||
database.noteAdvertisement(data.sliceArray(0..15), data.drop(16).toByteArray(), result.rssi)
|
|
||||||
|
override fun onBatchScanResults(results: MutableList<ScanResult>) {
|
||||||
|
Log.d(TAG, "onBatchScanResults: ${results.size}")
|
||||||
|
for (result in results) {
|
||||||
|
onScanResult(result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onScanFailed(errorCode: Int) {
|
||||||
|
Log.w(TAG, "onScanFailed: $errorCode")
|
||||||
|
stopScan()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private val scanner: BluetoothLeScanner
|
private val trigger = object : BroadcastReceiver() {
|
||||||
get() = BluetoothAdapter.getDefaultAdapter().bluetoothLeScanner
|
override fun onReceive(context: Context?, intent: Intent?) {
|
||||||
|
if (intent?.action == "android.bluetooth.adapter.action.STATE_CHANGED") {
|
||||||
|
when (intent.getIntExtra(EXTRA_STATE, -1)) {
|
||||||
|
STATE_TURNING_OFF, STATE_OFF -> stopScan()
|
||||||
|
STATE_ON -> startScanIfNeeded()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val scanner: BluetoothLeScanner?
|
||||||
|
get() = getDefaultAdapter().bluetoothLeScanner
|
||||||
|
|
||||||
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||||
super.onStartCommand(intent, flags, startId)
|
super.onStartCommand(intent, flags, startId)
|
||||||
|
startScanIfNeeded()
|
||||||
|
return START_STICKY
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onScanResult(result: ScanResult) {
|
||||||
|
val data = result.scanRecord?.serviceData?.get(SERVICE_UUID) ?: return
|
||||||
|
if (data.size < 16) return // Ignore invalid advertisements
|
||||||
|
database.noteAdvertisement(data.sliceArray(0..15), data.drop(16).toByteArray(), result.rssi)
|
||||||
|
seenAdvertisements++
|
||||||
|
}
|
||||||
|
|
||||||
|
fun startScanIfNeeded() {
|
||||||
if (ExposurePreferences(this).scannerEnabled) {
|
if (ExposurePreferences(this).scannerEnabled) {
|
||||||
startScan()
|
startScan()
|
||||||
} else {
|
} else {
|
||||||
stopSelf()
|
stopSelf()
|
||||||
}
|
}
|
||||||
return START_STICKY
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreate() {
|
override fun onCreate() {
|
||||||
super.onCreate()
|
super.onCreate()
|
||||||
database = ExposureDatabase.ref(this)
|
database = ExposureDatabase.ref(this)
|
||||||
|
registerReceiver(trigger, IntentFilter().also { it.addAction("android.bluetooth.adapter.action.STATE_CHANGED") })
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroy() {
|
override fun onDestroy() {
|
||||||
super.onDestroy()
|
super.onDestroy()
|
||||||
|
unregisterReceiver(trigger)
|
||||||
stopScan()
|
stopScan()
|
||||||
database.unref()
|
database.unref()
|
||||||
}
|
}
|
||||||
|
@ -55,6 +99,8 @@ class ScannerService : Service() {
|
||||||
@Synchronized
|
@Synchronized
|
||||||
private fun startScan() {
|
private fun startScan() {
|
||||||
if (started) return
|
if (started) return
|
||||||
|
val scanner = scanner ?: return
|
||||||
|
Log.d(TAG, "Starting scanner for service $SERVICE_UUID")
|
||||||
scanner.startScan(
|
scanner.startScan(
|
||||||
listOf(ScanFilter.Builder()
|
listOf(ScanFilter.Builder()
|
||||||
.setServiceUuid(SERVICE_UUID)
|
.setServiceUuid(SERVICE_UUID)
|
||||||
|
@ -66,12 +112,22 @@ class ScannerService : Service() {
|
||||||
callback
|
callback
|
||||||
)
|
)
|
||||||
started = true
|
started = true
|
||||||
|
startTime = System.currentTimeMillis()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Synchronized
|
@Synchronized
|
||||||
private fun stopScan() {
|
private fun stopScan() {
|
||||||
if (!started) return
|
if (!started) return
|
||||||
scanner.stopScan(callback)
|
Log.d(TAG, "Stopping scanner for service $SERVICE_UUID")
|
||||||
started = false
|
started = false
|
||||||
|
scanner?.stopScan(callback)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun dump(fd: FileDescriptor?, writer: PrintWriter?, args: Array<out String>?) {
|
||||||
|
writer?.println("Started: $started")
|
||||||
|
if (started) {
|
||||||
|
writer?.println("Since ${Date(startTime)}")
|
||||||
|
writer?.println("Seen advertisements: $seenAdvertisements")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,11 +9,13 @@ import android.annotation.SuppressLint
|
||||||
import android.content.BroadcastReceiver
|
import android.content.BroadcastReceiver
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
|
import android.util.Log
|
||||||
import org.microg.gms.common.ForegroundServiceContext
|
import org.microg.gms.common.ForegroundServiceContext
|
||||||
|
|
||||||
class ServiceTrigger : BroadcastReceiver() {
|
class ServiceTrigger : BroadcastReceiver() {
|
||||||
@SuppressLint("UnsafeProtectedBroadcastReceiver")
|
@SuppressLint("UnsafeProtectedBroadcastReceiver")
|
||||||
override fun onReceive(context: Context, intent: Intent?) {
|
override fun onReceive(context: Context, intent: Intent?) {
|
||||||
|
Log.d(TAG, "ServiceTrigger: $intent")
|
||||||
if (ExposurePreferences(context).scannerEnabled) {
|
if (ExposurePreferences(context).scannerEnabled) {
|
||||||
ForegroundServiceContext(context).startService(Intent(context, ScannerService::class.java))
|
ForegroundServiceContext(context).startService(Intent(context, ScannerService::class.java))
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue