Repo Created
This commit is contained in:
parent
eb305e2886
commit
a8c22c65db
4784 changed files with 329907 additions and 2 deletions
43
play-services-nearby/build.gradle
Normal file
43
play-services-nearby/build.gradle
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2020 microG Project Team
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
apply plugin: 'com.android.library'
|
||||
apply plugin: 'maven-publish'
|
||||
apply plugin: 'signing'
|
||||
|
||||
android {
|
||||
namespace "com.google.android.gms.nearby"
|
||||
|
||||
compileSdkVersion androidCompileSdk
|
||||
buildToolsVersion "$androidBuildVersionTools"
|
||||
|
||||
buildFeatures {
|
||||
aidl = true
|
||||
}
|
||||
|
||||
defaultConfig {
|
||||
versionName version
|
||||
minSdkVersion androidMinSdk
|
||||
targetSdkVersion androidTargetSdk
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility = 1.8
|
||||
targetCompatibility = 1.8
|
||||
}
|
||||
}
|
||||
|
||||
apply from: '../gradle/publish-android.gradle'
|
||||
|
||||
description = 'microG implementation of play-services-nearby'
|
||||
|
||||
dependencies {
|
||||
// Dependencies from play-services-nearby:18.0.2
|
||||
api "androidx.collection:collection:1.0.0"
|
||||
api "androidx.core:core:1.0.0"
|
||||
api project(':play-services-base')
|
||||
api project(':play-services-basement')
|
||||
api project(':play-services-tasks')
|
||||
}
|
||||
75
play-services-nearby/core/build.gradle
Normal file
75
play-services-nearby/core/build.gradle
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2020, microG Project Team
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
apply plugin: 'com.android.library'
|
||||
apply plugin: 'com.squareup.wire'
|
||||
apply plugin: 'kotlin-android'
|
||||
apply plugin: 'maven-publish'
|
||||
apply plugin: 'signing'
|
||||
|
||||
dependencies {
|
||||
api project(':play-services-nearby')
|
||||
|
||||
implementation project(':play-services-base-core')
|
||||
|
||||
implementation "androidx.annotation:annotation:$annotationVersion"
|
||||
implementation "androidx.lifecycle:lifecycle-service:$lifecycleVersion"
|
||||
implementation "androidx.lifecycle:lifecycle-runtime-ktx:$lifecycleVersion"
|
||||
implementation "androidx.navigation:navigation-fragment-ktx:$navigationVersion"
|
||||
implementation "androidx.navigation:navigation-ui-ktx:$navigationVersion"
|
||||
implementation "androidx.preference:preference:$preferenceVersion"
|
||||
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlinVersion"
|
||||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutineVersion"
|
||||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutineVersion"
|
||||
|
||||
implementation "com.squareup.wire:wire-runtime:$wireVersion"
|
||||
|
||||
testImplementation 'junit:junit:4.13.2'
|
||||
}
|
||||
|
||||
android {
|
||||
namespace "org.microg.gms.nearby.core"
|
||||
|
||||
compileSdkVersion androidCompileSdk
|
||||
buildToolsVersion "$androidBuildVersionTools"
|
||||
|
||||
defaultConfig {
|
||||
versionName version
|
||||
minSdkVersion androidMinSdk
|
||||
targetSdkVersion androidTargetSdk
|
||||
}
|
||||
|
||||
buildFeatures {
|
||||
dataBinding = true
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
main {
|
||||
java.srcDirs = ['src/main/kotlin']
|
||||
}
|
||||
}
|
||||
|
||||
lintOptions {
|
||||
disable 'MissingTranslation', 'GetLocales'
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility = 1.8
|
||||
targetCompatibility = 1.8
|
||||
}
|
||||
|
||||
kotlinOptions {
|
||||
jvmTarget = 1.8
|
||||
}
|
||||
}
|
||||
|
||||
wire {
|
||||
kotlin {}
|
||||
}
|
||||
|
||||
apply from: '../../gradle/publish-android.gradle'
|
||||
|
||||
description = 'microG service implementation for play-services-nearby'
|
||||
47
play-services-nearby/core/package/build.gradle
Normal file
47
play-services-nearby/core/package/build.gradle
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2023 microG Project Team
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
apply plugin: 'com.android.library'
|
||||
apply plugin: 'kotlin-android'
|
||||
|
||||
dependencies {
|
||||
implementation project(':play-services-base-core')
|
||||
implementation project(':play-services-nearby-core')
|
||||
implementation "androidx.navigation:navigation-fragment-ktx:$navigationVersion"
|
||||
implementation "androidx.navigation:navigation-ui-ktx:$navigationVersion"
|
||||
implementation "androidx.preference:preference:$preferenceVersion"
|
||||
}
|
||||
|
||||
android {
|
||||
namespace "org.microg.gms.nearby.core.pkg"
|
||||
|
||||
compileSdkVersion androidCompileSdk
|
||||
buildToolsVersion "$androidBuildVersionTools"
|
||||
|
||||
defaultConfig {
|
||||
versionName version
|
||||
minSdkVersion androidMinSdk
|
||||
targetSdkVersion androidTargetSdk
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
main {
|
||||
java.srcDirs = ['src/main/kotlin']
|
||||
}
|
||||
}
|
||||
|
||||
lintOptions {
|
||||
disable 'MissingTranslation'
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility = 1.8
|
||||
targetCompatibility = 1.8
|
||||
}
|
||||
|
||||
kotlinOptions {
|
||||
jvmTarget = 1.8
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
~ SPDX-FileCopyrightText: 2023 microG Project Team
|
||||
~ SPDX-License-Identifier: Apache-2.0
|
||||
-->
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<uses-permission android:name="android.permission.BLUETOOTH" />
|
||||
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
|
||||
<uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />
|
||||
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
|
||||
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
|
||||
|
||||
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
|
||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
||||
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
|
||||
|
||||
<permission
|
||||
android:name="com.google.android.gms.nearby.exposurenotification.EXPOSURE_CALLBACK"
|
||||
android:protectionLevel="normal" />
|
||||
|
||||
<application>
|
||||
<meta-data
|
||||
android:name="org.microg.gms.ui.settings.entry:nearby-exposurenotifications"
|
||||
android:value="org.microg.gms.nearby.exposurenotification.ui.ExposureNotificationsSettingsProvider" />
|
||||
</application>
|
||||
</manifest>
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2023 microG Project Team
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package org.microg.gms.nearby.exposurenotification.ui
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Build.VERSION.SDK_INT
|
||||
import androidx.annotation.Keep
|
||||
import androidx.appcompat.content.res.AppCompatResources
|
||||
import androidx.navigation.NavController
|
||||
import com.google.android.gms.nearby.exposurenotification.ExposureNotificationClient
|
||||
import org.microg.gms.ui.settings.SettingsProvider
|
||||
import org.microg.gms.nearby.core.R
|
||||
import org.microg.gms.nearby.exposurenotification.ExposureDatabase
|
||||
import org.microg.gms.nearby.exposurenotification.ExposurePreferences
|
||||
import org.microg.gms.ui.settings.SettingsProvider.Companion.Entry
|
||||
import org.microg.gms.ui.settings.SettingsProvider.Companion.Group.OTHER
|
||||
|
||||
@Keep
|
||||
object ExposureNotificationsSettingsProvider : SettingsProvider {
|
||||
override fun getEntriesStatic(context: Context): List<Entry> {
|
||||
if (SDK_INT < 21) return emptyList()
|
||||
if (!ExposurePreferences(context).enabled) return emptyList()
|
||||
return getEntries(context)
|
||||
}
|
||||
|
||||
override suspend fun getEntriesDynamic(context: Context): List<Entry> {
|
||||
if (SDK_INT < 21) return emptyList()
|
||||
if (!ExposurePreferences(context).enabled) {
|
||||
if (ExposureDatabase.with(context) { it.isEmpty }) {
|
||||
return emptyList()
|
||||
}
|
||||
}
|
||||
return getEntries(context)
|
||||
}
|
||||
|
||||
private fun getEntries(context: Context) = listOf(
|
||||
Entry(
|
||||
key = "pref_exposure",
|
||||
group = OTHER,
|
||||
navigationId = R.id.exposureNotificationsFragment,
|
||||
title = context.getString(R.string.service_name_exposure),
|
||||
summary = if (ExposurePreferences(context).enabled) {
|
||||
context.getString(org.microg.gms.base.core.R.string.service_status_enabled_short)
|
||||
} else {
|
||||
context.getString(org.microg.gms.base.core.R.string.service_status_disabled_short)
|
||||
},
|
||||
icon = AppCompatResources.getDrawable(context, R.drawable.ic_virus_outline)
|
||||
)
|
||||
)
|
||||
|
||||
override fun preProcessSettingsIntent(intent: Intent) {
|
||||
if (ExposureNotificationClient.ACTION_EXPOSURE_NOTIFICATION_SETTINGS == intent.action && intent.data == null) {
|
||||
intent.data = Uri.parse("x-gms-settings://exposure-notifications")
|
||||
}
|
||||
}
|
||||
|
||||
override fun extendNavigation(navController: NavController) {
|
||||
navController.graph.addAll(navController.navInflater.inflate(R.navigation.nav_nearby))
|
||||
}
|
||||
}
|
||||
79
play-services-nearby/core/src/main/AndroidManifest.xml
Normal file
79
play-services-nearby/core/src/main/AndroidManifest.xml
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
~ SPDX-FileCopyrightText: 2020 microG Project Team
|
||||
~ SPDX-License-Identifier: Apache-2.0
|
||||
-->
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
||||
<uses-permission android:name="com.google.android.gms.nearby.exposurenotification.EXPOSURE_CALLBACK" />
|
||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
||||
|
||||
<application>
|
||||
|
||||
<!-- Exposure Notifications -->
|
||||
|
||||
<service
|
||||
android:name="org.microg.gms.nearby.exposurenotification.ScannerService"
|
||||
android:process=":persistent" />
|
||||
<service
|
||||
android:name="org.microg.gms.nearby.exposurenotification.AdvertiserService"
|
||||
android:process=":persistent" />
|
||||
<service
|
||||
android:name="org.microg.gms.nearby.exposurenotification.CleanupService"
|
||||
android:process=":persistent" />
|
||||
<service
|
||||
android:name="org.microg.gms.nearby.exposurenotification.NotifyService"
|
||||
android:process=":persistent" />
|
||||
|
||||
<service
|
||||
android:name="org.microg.gms.nearby.exposurenotification.ExposureNotificationService"
|
||||
android:process=":persistent"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="com.google.android.gms.nearby.exposurenotification.START" />
|
||||
</intent-filter>
|
||||
</service>
|
||||
|
||||
<receiver
|
||||
android:name="org.microg.gms.nearby.exposurenotification.ServiceTrigger"
|
||||
android:process=":persistent"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
||||
|
||||
<action android:name="android.intent.action.MY_PACKAGE_REPLACED" />
|
||||
<action android:name="android.intent.action.PACKAGE_RESTARTED" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<provider
|
||||
android:name="org.microg.gms.nearby.exposurenotification.ExposureFileProvider"
|
||||
android:authorities="${applicationId}.microg.exposure.export"
|
||||
android:exported="false"
|
||||
android:grantUriPermissions="true">
|
||||
<meta-data
|
||||
android:name="android.support.FILE_PROVIDER_PATHS"
|
||||
android:resource="@xml/preferences_exposure_notifications_exportedfiles" />
|
||||
</provider>
|
||||
|
||||
<activity
|
||||
android:name="org.microg.gms.nearby.exposurenotification.ui.ExposureNotificationsConfirmActivity"
|
||||
android:exported="false"
|
||||
android:process=":ui"
|
||||
android:theme="@style/Theme.AppCompat.DayNight.Dialog.Alert.NoActionBar">
|
||||
<intent-filter>
|
||||
<action android:name="org.microg.gms.nearby.exposurenotification.CONFIRM" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity
|
||||
android:name="org.microg.gms.nearby.exposurenotification.ui.ExposureNotificationsSettingsActivity"
|
||||
android:exported="false"
|
||||
android:process=":ui"
|
||||
android:theme="@style/Theme.AppCompat.DayNight">
|
||||
<intent-filter android:priority="-100">
|
||||
<action android:name="com.google.android.gms.settings.EXPOSURE_NOTIFICATION_SETTINGS" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
</manifest>
|
||||
|
|
@ -0,0 +1,268 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2020, microG Project Team
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package org.microg.gms.nearby.exposurenotification
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.annotation.TargetApi
|
||||
import android.app.AlarmManager
|
||||
import android.app.PendingIntent.FLAG_ONE_SHOT
|
||||
import android.app.PendingIntent.FLAG_UPDATE_CURRENT
|
||||
import android.bluetooth.BluetoothAdapter.*
|
||||
import android.bluetooth.le.*
|
||||
import android.bluetooth.le.AdvertiseSettings.*
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.os.Build.VERSION.SDK_INT
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.os.SystemClock
|
||||
import android.util.Log
|
||||
import androidx.core.app.PendingIntentCompat
|
||||
import androidx.lifecycle.LifecycleService
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.microg.gms.common.ForegroundServiceContext
|
||||
import org.microg.gms.common.ForegroundServiceInfo
|
||||
import java.io.FileDescriptor
|
||||
import java.io.PrintWriter
|
||||
import java.nio.ByteBuffer
|
||||
import java.util.*
|
||||
|
||||
@TargetApi(21)
|
||||
@ForegroundServiceInfo("Exposure Notification")
|
||||
class AdvertiserService : LifecycleService() {
|
||||
private val version = VERSION_1_1
|
||||
private var advertising = false
|
||||
private var wantStartAdvertising = false
|
||||
private val advertiser: BluetoothLeAdvertiser?
|
||||
get() = getDefaultAdapter()?.bluetoothLeAdvertiser
|
||||
private val alarmManager: AlarmManager
|
||||
get() = getSystemService(Context.ALARM_SERVICE) as AlarmManager
|
||||
private val callback: AdvertiseCallback = object : AdvertiseCallback() {
|
||||
override fun onStartSuccess(settingsInEffect: AdvertiseSettings?) {
|
||||
Log.d(TAG, "Advertising active for ${settingsInEffect?.timeout}ms")
|
||||
}
|
||||
|
||||
override fun onStartFailure(errorCode: Int) {
|
||||
Log.w(TAG, "Advertising failed: $errorCode")
|
||||
stopOrRestartAdvertising()
|
||||
}
|
||||
}
|
||||
|
||||
@TargetApi(23)
|
||||
private var setCallback: Any? = null
|
||||
private val trigger = object : BroadcastReceiver() {
|
||||
override fun onReceive(context: Context?, intent: Intent?) {
|
||||
if (intent?.action == ACTION_STATE_CHANGED) {
|
||||
when (intent.getIntExtra(EXTRA_STATE, -1)) {
|
||||
STATE_TURNING_OFF, STATE_OFF -> stopOrRestartAdvertising()
|
||||
STATE_ON -> startAdvertisingIfNeeded()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
private val handler = Handler(Looper.getMainLooper())
|
||||
private val startLaterRunnable = Runnable { startAdvertisingIfNeeded() }
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
registerReceiver(trigger, IntentFilter().apply { addAction(ACTION_STATE_CHANGED) })
|
||||
}
|
||||
|
||||
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||
ForegroundServiceContext.completeForegroundService(this, intent, TAG)
|
||||
Log.d(TAG, "AdvertisingService.start: $intent")
|
||||
super.onStartCommand(intent, flags, startId)
|
||||
if (intent?.action == ACTION_RESTART_ADVERTISING && advertising) {
|
||||
stopOrRestartAdvertising()
|
||||
} else {
|
||||
startAdvertisingIfNeeded()
|
||||
}
|
||||
return START_STICKY
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
unregisterReceiver(trigger)
|
||||
stopOrRestartAdvertising()
|
||||
handler.removeCallbacks(startLaterRunnable)
|
||||
}
|
||||
|
||||
private fun startAdvertisingIfNeeded() {
|
||||
if (ExposurePreferences(this).enabled) {
|
||||
lifecycleScope.launchWhenStarted {
|
||||
withContext(Dispatchers.IO) {
|
||||
startAdvertising()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
stopSelf()
|
||||
}
|
||||
}
|
||||
|
||||
private var lastStartTime = System.currentTimeMillis()
|
||||
private var sendingBytes = ByteArray(0)
|
||||
private var starting = false
|
||||
|
||||
@SuppressLint("MissingPermission")
|
||||
private suspend fun startAdvertising() {
|
||||
val advertiser = synchronized(this) {
|
||||
if (advertising || starting) return
|
||||
val advertiser = advertiser ?: return
|
||||
wantStartAdvertising = false
|
||||
starting = true
|
||||
advertiser
|
||||
}
|
||||
try {
|
||||
val aemBytes = when (version) {
|
||||
VERSION_1_0 -> byteArrayOf(
|
||||
version, // Version and flags
|
||||
currentDeviceInfo.txPowerCorrection, // TX power
|
||||
0x00, // Reserved
|
||||
0x00 // Reserved
|
||||
)
|
||||
VERSION_1_1 -> byteArrayOf(
|
||||
(version + currentDeviceInfo.confidence.toByte() * 4).toByte(), // Version and flags
|
||||
currentDeviceInfo.txPowerCorrection, // TX power
|
||||
0x00, // Reserved
|
||||
0x00 // Reserved
|
||||
)
|
||||
else -> return
|
||||
}
|
||||
var nextSend = nextKeyMillis.coerceAtLeast(10000)
|
||||
val payload = ExposureDatabase.with(this@AdvertiserService) { database ->
|
||||
database.generateCurrentPayload(aemBytes)
|
||||
}
|
||||
val data = AdvertiseData.Builder().addServiceUuid(SERVICE_UUID).addServiceData(SERVICE_UUID, payload).build()
|
||||
Log.i(TAG, "Starting advertiser")
|
||||
if (SDK_INT >= 26) {
|
||||
setCallback = SetCallback()
|
||||
val params = AdvertisingSetParameters.Builder()
|
||||
.setInterval(AdvertisingSetParameters.INTERVAL_MEDIUM)
|
||||
.setLegacyMode(true)
|
||||
.setTxPowerLevel(AdvertisingSetParameters.TX_POWER_LOW)
|
||||
.setConnectable(false)
|
||||
.build()
|
||||
try {
|
||||
advertiser.startAdvertisingSet(params, data, null, null, null, setCallback as AdvertisingSetCallback)
|
||||
} catch (e: SecurityException) {
|
||||
Log.e(TAG, "Couldn't start advertising: Need android.permission.BLUETOOTH_ADVERTISE permission.", )
|
||||
}
|
||||
} else {
|
||||
nextSend = nextSend.coerceAtMost(180000)
|
||||
val settings = Builder()
|
||||
.setTimeout(nextSend.toInt())
|
||||
.setAdvertiseMode(ADVERTISE_MODE_BALANCED)
|
||||
.setTxPowerLevel(ADVERTISE_TX_POWER_LOW)
|
||||
.setConnectable(false)
|
||||
.build()
|
||||
try {
|
||||
advertiser.startAdvertising(settings, data, callback)
|
||||
} catch (e: SecurityException) {
|
||||
Log.e(TAG, "Couldn't start advertising.", )
|
||||
}
|
||||
}
|
||||
synchronized(this) { advertising = true }
|
||||
sendingBytes = payload
|
||||
lastStartTime = System.currentTimeMillis()
|
||||
scheduleRestartAdvertising(nextSend)
|
||||
} finally {
|
||||
synchronized(this) { starting = false }
|
||||
}
|
||||
}
|
||||
|
||||
override fun dump(fd: FileDescriptor?, writer: PrintWriter?, args: Array<out String>?) {
|
||||
writer?.println("Advertising: $advertising")
|
||||
try {
|
||||
val startTime = lastStartTime
|
||||
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}
|
||||
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()}")
|
||||
}
|
||||
}
|
||||
|
||||
private fun scheduleRestartAdvertising(nextSend: Long) {
|
||||
val intent = Intent(this, AdvertiserService::class.java).apply { action = ACTION_RESTART_ADVERTISING }
|
||||
val pendingIntent = PendingIntentCompat.getService(this, ACTION_RESTART_ADVERTISING.hashCode(), intent, FLAG_ONE_SHOT or FLAG_UPDATE_CURRENT, false)!!
|
||||
when {
|
||||
SDK_INT >= 23 ->
|
||||
alarmManager.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + nextSend, pendingIntent)
|
||||
else ->
|
||||
alarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + nextSend, pendingIntent)
|
||||
}
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
@SuppressLint("MissingPermission")
|
||||
private fun stopOrRestartAdvertising() {
|
||||
if (!advertising) return
|
||||
Log.i(TAG, "Stopping advertiser")
|
||||
advertising = false
|
||||
if (SDK_INT >= 26) {
|
||||
wantStartAdvertising = true
|
||||
try {
|
||||
advertiser?.stopAdvertisingSet(setCallback as AdvertisingSetCallback)
|
||||
} catch (e: SecurityException) {
|
||||
Log.i(TAG, "Tried calling stopAdvertisingSet without android.permission.BLUETOOTH_ADVERTISE permission.", )
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
advertiser?.stopAdvertising(callback)
|
||||
} catch (e: SecurityException) {
|
||||
Log.i(TAG, "stopAdvertising() failed with a SecurityException. Maybe some permissions are missing?", )
|
||||
}
|
||||
}
|
||||
handler.postDelayed(startLaterRunnable, 1000)
|
||||
}
|
||||
|
||||
@TargetApi(26)
|
||||
inner class SetCallback : AdvertisingSetCallback() {
|
||||
override fun onAdvertisingSetStarted(advertisingSet: AdvertisingSet?, txPower: Int, status: Int) {
|
||||
Log.d(TAG, "Advertising active, status=$status")
|
||||
}
|
||||
|
||||
override fun onAdvertisingSetStopped(advertisingSet: AdvertisingSet?) {
|
||||
Log.d(TAG, "Advertising stopped")
|
||||
if (wantStartAdvertising) {
|
||||
startAdvertisingIfNeeded()
|
||||
} else {
|
||||
stopOrRestartAdvertising()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
companion object {
|
||||
private const val ACTION_RESTART_ADVERTISING = "org.microg.gms.nearby.exposurenotification.RESTART_ADVERTISING"
|
||||
|
||||
fun isNeeded(context: Context): Boolean {
|
||||
return ExposurePreferences(context).enabled
|
||||
}
|
||||
|
||||
fun isSupported(context: Context): Boolean? {
|
||||
val adapter = getDefaultAdapter()
|
||||
return when {
|
||||
adapter == null -> false
|
||||
SDK_INT >= 26 && (adapter.isLeExtendedAdvertisingSupported || adapter.isLePeriodicAdvertisingSupported) -> true
|
||||
adapter.state != STATE_ON -> null
|
||||
adapter.bluetoothLeAdvertiser != null -> true
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2020, microG Project Team
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package org.microg.gms.nearby.exposurenotification
|
||||
|
||||
import android.app.AlarmManager
|
||||
import android.app.PendingIntent.FLAG_ONE_SHOT
|
||||
import android.app.PendingIntent.FLAG_UPDATE_CURRENT
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.util.Log
|
||||
import androidx.core.app.PendingIntentCompat
|
||||
import androidx.lifecycle.LifecycleService
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.microg.gms.common.ForegroundServiceContext
|
||||
import org.microg.gms.common.ForegroundServiceInfo
|
||||
|
||||
@ForegroundServiceInfo("Exposure Notification")
|
||||
class CleanupService : LifecycleService() {
|
||||
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||
ForegroundServiceContext.completeForegroundService(this, intent, TAG)
|
||||
Log.d(TAG, "CleanupService.start: $intent")
|
||||
super.onStartCommand(intent, flags, startId)
|
||||
if (isNeeded(this, true)) {
|
||||
lifecycleScope.launchWhenStarted {
|
||||
withContext(Dispatchers.IO) {
|
||||
var workPending = true
|
||||
while (workPending) {
|
||||
ExposureDatabase.with(this@CleanupService) {
|
||||
workPending = !it.dailyCleanup()
|
||||
}
|
||||
if (workPending) delay(5000L)
|
||||
}
|
||||
ExposurePreferences(this@CleanupService).lastCleanup = System.currentTimeMillis()
|
||||
}
|
||||
stop()
|
||||
}
|
||||
} else {
|
||||
stop()
|
||||
}
|
||||
return START_NOT_STICKY
|
||||
}
|
||||
|
||||
fun stop() {
|
||||
val alarmManager = getSystemService(Context.ALARM_SERVICE) as AlarmManager
|
||||
val pendingIntent = PendingIntentCompat.getService(applicationContext, CleanupService::class.java.name.hashCode(), Intent(applicationContext, CleanupService::class.java), FLAG_ONE_SHOT or FLAG_UPDATE_CURRENT, false)!!
|
||||
alarmManager.set(AlarmManager.RTC, ExposurePreferences(this).lastCleanup + CLEANUP_INTERVAL, pendingIntent)
|
||||
stopSelf()
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun isNeeded(context: Context, now: Boolean = false): Boolean {
|
||||
return ExposurePreferences(context).let {
|
||||
(it.enabled && !now) || it.lastCleanup < System.currentTimeMillis() - CLEANUP_INTERVAL
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2020, microG Project Team
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package org.microg.gms.nearby.exposurenotification
|
||||
|
||||
import android.os.ParcelUuid
|
||||
import com.google.android.gms.nearby.exposurenotification.CalibrationConfidence
|
||||
import java.util.*
|
||||
|
||||
const val TAG = "ExposureNotification"
|
||||
val SERVICE_UUID = ParcelUuid(UUID.fromString("0000FD6F-0000-1000-8000-00805F9B34FB"))
|
||||
|
||||
const val SCANNING_INTERVAL = 3 * 60 // Google uses 5m, but we use a slightly different scanning and reporting system
|
||||
const val SCANNING_INTERVAL_MS = SCANNING_INTERVAL * 1000L
|
||||
const val SCANNING_TIME = 20 // Google uses 4s + 13s (if Bluetooth is used by something else)
|
||||
const val SCANNING_TIME_MS = SCANNING_TIME * 1000L
|
||||
|
||||
const val ROLLING_WINDOW_LENGTH = 10 * 60
|
||||
const val ROLLING_WINDOW_LENGTH_MS = ROLLING_WINDOW_LENGTH * 1000L
|
||||
const val ROLLING_PERIOD = 144
|
||||
const val ALLOWED_KEY_OFFSET_MS = 60 * 60 * 1000L
|
||||
const val MINIMUM_EXPOSURE_DURATION_MS = 0L
|
||||
const val KEEP_DAYS = 14
|
||||
|
||||
const val ACTION_CONFIRM = "org.microg.gms.nearby.exposurenotification.CONFIRM"
|
||||
const val KEY_CONFIRM_ACTION = "action"
|
||||
const val KEY_CONFIRM_RECEIVER = "receiver"
|
||||
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"
|
||||
|
||||
const val TX_POWER_LOW = -15
|
||||
|
||||
const val ADVERTISER_OFFSET = 60 * 1000
|
||||
const val CLEANUP_INTERVAL = 24 * 60 * 60 * 1000L
|
||||
|
||||
const val VERSION_1_0: Byte = 0x40
|
||||
const val VERSION_1_1: Byte = 0x50
|
||||
|
||||
const val NOTIFICATION_UPDATE_ACTION = "org.microg.gms.nearby.UPDATE_NOTIFICATION"
|
||||
|
|
@ -0,0 +1,122 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2020, microG Project Team
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package org.microg.gms.nearby.exposurenotification
|
||||
|
||||
import android.annotation.TargetApi
|
||||
import android.util.Log
|
||||
import com.google.android.gms.nearby.exposurenotification.TemporaryExposureKey
|
||||
import java.nio.ByteBuffer
|
||||
import java.nio.ByteOrder
|
||||
import java.nio.charset.StandardCharsets
|
||||
import java.security.SecureRandom
|
||||
import java.util.*
|
||||
import javax.crypto.Cipher
|
||||
import javax.crypto.Mac
|
||||
import javax.crypto.spec.IvParameterSpec
|
||||
import javax.crypto.spec.SecretKeySpec
|
||||
import kotlin.math.floor
|
||||
|
||||
private const val RPIK_HKDF_INFO = "EN-RPIK"
|
||||
private const val RPIK_ALGORITHM = "AES"
|
||||
|
||||
private const val AEMK_HKDF_INFO = "EN-AEMK"
|
||||
private const val AEMK_ALGORITHM = "AES"
|
||||
|
||||
private const val HKDF_ALGORITHM = "HmacSHA256"
|
||||
private const val HKDF_LENGTH = 16
|
||||
private const val HASH_LENGTH = 32
|
||||
|
||||
private const val RPID_ALGORITHM = "AES/ECB/NoPadding"
|
||||
private const val RPID_PREFIX = "EN-RPI"
|
||||
private const val AES_BLOCK_SIZE = 16
|
||||
|
||||
private const val AEM_ALGORITHM = "AES/CTR/NoPadding"
|
||||
|
||||
val currentIntervalNumber: Int
|
||||
get() = floor(System.currentTimeMillis() / 1000.0 / ROLLING_WINDOW_LENGTH).toInt()
|
||||
|
||||
val currentDayRollingStartNumber: Int
|
||||
get() = getDayRollingStartNumber(currentIntervalNumber)
|
||||
|
||||
fun getDayRollingStartNumber(intervalNumber: Int) = (floor(intervalNumber.toDouble() / ROLLING_PERIOD).toLong() * ROLLING_PERIOD).toInt()
|
||||
fun getPeriodInDay(intervalNumber: Int) = intervalNumber - getDayRollingStartNumber(intervalNumber)
|
||||
|
||||
val nextKeyMillis: Long
|
||||
get() {
|
||||
val currentWindowStart = currentIntervalNumber.toLong() * ROLLING_WINDOW_LENGTH_MS
|
||||
val currentWindowEnd = currentWindowStart + ROLLING_WINDOW_LENGTH_MS
|
||||
return (currentWindowEnd - System.currentTimeMillis()).coerceAtLeast(0)
|
||||
}
|
||||
|
||||
fun generateTemporaryExposureKey(intervalNumber: Int): TemporaryExposureKey.TemporaryExposureKeyBuilder = TemporaryExposureKey.TemporaryExposureKeyBuilder().apply {
|
||||
var keyData = ByteArray(16)
|
||||
SecureRandom().nextBytes(keyData)
|
||||
setKeyData(keyData)
|
||||
setRollingStartIntervalNumber(intervalNumber)
|
||||
setRollingPeriod((ROLLING_PERIOD - getPeriodInDay(intervalNumber)))
|
||||
}
|
||||
|
||||
fun generateCurrentDayTemporaryExposureKey(): TemporaryExposureKey = generateTemporaryExposureKey(currentDayRollingStartNumber).build()
|
||||
fun generateIntraDayTemporaryExposureKey(intervalNumber: Int = currentIntervalNumber): TemporaryExposureKey = generateTemporaryExposureKey(intervalNumber).build()
|
||||
|
||||
@TargetApi(21)
|
||||
fun TemporaryExposureKey.generateRpiKey(): SecretKeySpec {
|
||||
return SecretKeySpec(hkdf(keyData, null, RPIK_HKDF_INFO.toByteArray(StandardCharsets.UTF_8)), RPIK_ALGORITHM)
|
||||
}
|
||||
|
||||
@TargetApi(21)
|
||||
fun TemporaryExposureKey.generateAemKey(): SecretKeySpec {
|
||||
return SecretKeySpec(hkdf(keyData, null, AEMK_HKDF_INFO.toByteArray(StandardCharsets.UTF_8)), AEMK_ALGORITHM)
|
||||
}
|
||||
|
||||
@TargetApi(21)
|
||||
fun TemporaryExposureKey.generateRpiId(intervalNumber: Int): ByteArray {
|
||||
val cipher = Cipher.getInstance(RPID_ALGORITHM)
|
||||
cipher.init(Cipher.ENCRYPT_MODE, generateRpiKey())
|
||||
val data = ByteBuffer.allocate(AES_BLOCK_SIZE).order(ByteOrder.LITTLE_ENDIAN).apply {
|
||||
put(RPID_PREFIX.toByteArray(StandardCharsets.UTF_8))
|
||||
position(12)
|
||||
putInt(intervalNumber)
|
||||
}.array()
|
||||
return cipher.doFinal(data)
|
||||
}
|
||||
|
||||
@TargetApi(21)
|
||||
fun TemporaryExposureKey.generateAllRpiIds(): ByteArray {
|
||||
val cipher = Cipher.getInstance(RPID_ALGORITHM)
|
||||
cipher.init(Cipher.ENCRYPT_MODE, generateRpiKey())
|
||||
val data = ByteBuffer.allocate(AES_BLOCK_SIZE * rollingPeriod).order(ByteOrder.LITTLE_ENDIAN).apply {
|
||||
val prefix = RPID_PREFIX.toByteArray(StandardCharsets.UTF_8)
|
||||
for (i in 0 until rollingPeriod) {
|
||||
put(prefix)
|
||||
position(i * 16 + 12)
|
||||
putInt(rollingStartIntervalNumber + i)
|
||||
}
|
||||
}.array()
|
||||
return cipher.doFinal(data)
|
||||
}
|
||||
|
||||
fun TemporaryExposureKey.cryptAem(rpi: ByteArray, metadata: ByteArray): ByteArray {
|
||||
val cipher = Cipher.getInstance(AEM_ALGORITHM)
|
||||
cipher.init(Cipher.ENCRYPT_MODE, generateAemKey(), IvParameterSpec(rpi))
|
||||
return cipher.doFinal(metadata)
|
||||
}
|
||||
|
||||
fun TemporaryExposureKey.generatePayload(intervalNumber: Int, metadata: ByteArray): ByteArray {
|
||||
val rpi = generateRpiId(intervalNumber)
|
||||
val aem = cryptAem(rpi, metadata)
|
||||
return rpi + aem
|
||||
}
|
||||
|
||||
private fun hkdf(inputKeyingMaterial: ByteArray, inputSalt: ByteArray?, info: ByteArray): ByteArray {
|
||||
val mac = Mac.getInstance(HKDF_ALGORITHM)
|
||||
val salt = if (inputSalt == null || inputSalt.isEmpty()) ByteArray(HASH_LENGTH) else inputSalt
|
||||
mac.init(SecretKeySpec(salt, HKDF_ALGORITHM))
|
||||
val pseudoRandomKey = mac.doFinal(inputKeyingMaterial)
|
||||
mac.init(SecretKeySpec(pseudoRandomKey, HKDF_ALGORITHM))
|
||||
mac.update(info)
|
||||
return Arrays.copyOf(mac.doFinal(byteArrayOf(0x01)), HKDF_LENGTH)
|
||||
}
|
||||
|
|
@ -0,0 +1,620 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2020, microG Project Team
|
||||
* SPDX-License-Identifier: Apache-2.0 AND CC-BY-4.0
|
||||
* Notice: Portions of this file are reproduced from work created and shared by Google and used
|
||||
* according to terms described in the Creative Commons 4.0 Attribution License.
|
||||
* See https://developers.google.com/readme/policies for details.
|
||||
*/
|
||||
|
||||
package org.microg.gms.nearby.exposurenotification
|
||||
|
||||
import android.os.Build.DEVICE
|
||||
import android.os.Build.MANUFACTURER
|
||||
import android.os.Build.MODEL
|
||||
import android.util.Log
|
||||
import com.google.android.gms.nearby.exposurenotification.CalibrationConfidence
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
data class DeviceInfo(val oem: String, val device: String, val model: String, val rssiCorrection: Byte, val txPowerCorrection: Byte, @CalibrationConfidence val confidence: Int = CalibrationConfidence.MEDIUM)
|
||||
|
||||
private var knownDeviceInfo: DeviceInfo? = null
|
||||
|
||||
fun averageCurrentDeviceInfo(oem: String, device: String, model: String, deviceInfos: List<DeviceInfo>, @CalibrationConfidence confidence: Int = CalibrationConfidence.LOW): DeviceInfo =
|
||||
DeviceInfo(oem, device, model, deviceInfos.map { it.rssiCorrection }.average().roundToInt().toByte(), deviceInfos.map { it.txPowerCorrection }.average().roundToInt().toByte(), confidence)
|
||||
|
||||
val currentDeviceInfo: DeviceInfo
|
||||
get() {
|
||||
var deviceInfo = knownDeviceInfo
|
||||
if (deviceInfo == null) {
|
||||
// Note: Custom ROMs sometimes have slightly different model information, so we have some flexibility for those
|
||||
val byOem = allDeviceInfos.filter { it.oem.equalsIgnoreCase(MANUFACTURER) }
|
||||
val byDevice = allDeviceInfos.filter { it.device.equalsIgnoreCase(DEVICE) }
|
||||
val byModel = allDeviceInfos.filter { it.model.equalsIgnoreCase(MODEL) }
|
||||
val exactMatch = byOem.find { it.device.equalsIgnoreCase(DEVICE) && it.model.equalsIgnoreCase(MODEL) }
|
||||
deviceInfo = when {
|
||||
exactMatch != null -> {
|
||||
// Exact match, use provided confidence
|
||||
exactMatch
|
||||
}
|
||||
byModel.isNotEmpty() || byDevice.isNotEmpty() -> {
|
||||
// We have data from "sister devices", that's way better than taking the OEM average
|
||||
averageCurrentDeviceInfo(MANUFACTURER, DEVICE, MODEL, (byDevice + byModel).distinct(), CalibrationConfidence.MEDIUM)
|
||||
}
|
||||
byOem.isNotEmpty() -> {
|
||||
// Fallback to OEM average
|
||||
averageCurrentDeviceInfo(MANUFACTURER, DEVICE, MODEL, byOem, CalibrationConfidence.LOW)
|
||||
}
|
||||
else -> {
|
||||
// Fallback to all device average
|
||||
averageCurrentDeviceInfo(MANUFACTURER, DEVICE, MODEL, allDeviceInfos, CalibrationConfidence.LOWEST)
|
||||
}
|
||||
}
|
||||
Log.i(TAG, "Selected $deviceInfo")
|
||||
knownDeviceInfo = deviceInfo
|
||||
}
|
||||
return deviceInfo
|
||||
}
|
||||
|
||||
val averageDeviceInfo: DeviceInfo
|
||||
get() = averageCurrentDeviceInfo(MANUFACTURER, DEVICE, MODEL, allDeviceInfos, CalibrationConfidence.LOWEST)
|
||||
|
||||
@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-12-14.csv published via
|
||||
* https://developers.google.com/android/exposure-notifications/ble-attenuation-computation#device-list
|
||||
*/
|
||||
val allDeviceInfos = listOf(
|
||||
DeviceInfo("asus", "ASUS_A001", "ASUS_A001", 9, -25, 3),
|
||||
DeviceInfo("asus", "ASUS_I001_1", "ASUS_I001D", 4, -28, 3),
|
||||
DeviceInfo("asus", "ASUS_I002D", "ASUS_I002D", 7, -37, 3),
|
||||
DeviceInfo("asus", "ASUS_I003_1", "ASUS_I003DD", 1, -32, 3),
|
||||
DeviceInfo("asus", "ASUS_I01WD", "ASUS_I01WD", 5, -27, 3),
|
||||
DeviceInfo("asus", "ASUS_X008_1", "ASUS_X008DC", 0, -21, 3),
|
||||
DeviceInfo("asus", "ASUS_X00T_3", "ASUS_X00TD", 2, -26, 3),
|
||||
DeviceInfo("asus", "ASUS_X018_4", "ASUS_X018D", 2, -22, 3),
|
||||
DeviceInfo("asus", "ASUS_X01BD_1", "ASUS_X01BDA", 2, -25, 3),
|
||||
DeviceInfo("asus", "ASUS_Z010_CD", "ASUS_Z010D", 2, -18, 3),
|
||||
DeviceInfo("asus", "ASUS_Z01F_1", "ASUS_Z01FD", 5, -20, 3),
|
||||
DeviceInfo("asus", "ASUS_Z01QD_1", "ASUS_Z01QD", 3, -25, 3),
|
||||
DeviceInfo("asus", "ASUS_Z01R_1", "ASUS_Z01RD", 4, -26, 3),
|
||||
DeviceInfo("asus", "P027", "P027", 4, -20, 3),
|
||||
DeviceInfo("blackberry", "bbe100", "BBE100-4", 6, -27, 3),
|
||||
DeviceInfo("blu", "Grand_M", "Grand M", -1, -21, 3),
|
||||
DeviceInfo("blu", "Studio_Mega", "Studio Mega", 6, -28, 3),
|
||||
DeviceInfo("blu", "Tank_Xtreme_4_0", "Tank Xtreme 4.0", 1, -24, 3),
|
||||
DeviceInfo("blu", "BLU_VIVO_5", "VIVO 5", 5, -24, 3),
|
||||
DeviceInfo("blu", "V0270WW", "Vivo ONE", 4, -25, 3),
|
||||
DeviceInfo("coolpad", "CP8722", "Coolpad 8722V", 0, -20, 3),
|
||||
DeviceInfo("docomo", "SO-41A", "SO-41A", 2, -31, 3),
|
||||
DeviceInfo("essential products", "mata", "PH-1", 7, -24, 3),
|
||||
DeviceInfo("google", "sailfish", "Pixel", -3, -26, 3),
|
||||
DeviceInfo("google", "blueline", "Pixel 3", 5, -33, 3),
|
||||
DeviceInfo("google", "sargo", "Pixel 3a", 2, -29, 3),
|
||||
DeviceInfo("google", "bonito", "Pixel 3a XL", 2, -28, 3),
|
||||
DeviceInfo("google", "flame", "Pixel 4", 8, -30, 3),
|
||||
DeviceInfo("google", "coral", "Pixel 4 XL", 7, -26, 3),
|
||||
DeviceInfo("google", "sunfish", "Pixel 4a", 1, -30, 3),
|
||||
DeviceInfo("google", "redfin", "Pixel 5", 5, -25, 3),
|
||||
DeviceInfo("google", "marlin", "Pixel XL", -2, -26, 3),
|
||||
DeviceInfo("google", "gobo", "gobo_512", 2, -22, 3),
|
||||
DeviceInfo("htc", "htc_pmewhl", "2PS64", -1, -31, 3),
|
||||
DeviceInfo("htc", "htc_pmewl", "HTC 10", 1, -31, 3),
|
||||
DeviceInfo("htc", "htc_pmeuhl", "HTC 10", 2, -33, 3),
|
||||
DeviceInfo("htc", "htc_a16ul", "HTC Desire 530", 5, -28, 3),
|
||||
DeviceInfo("htc", "htc_ocnwhl", "HTC U11", 2, -21, 3),
|
||||
DeviceInfo("htc", "htc_ocndugl", "HTC U11", 2, -27, 3),
|
||||
DeviceInfo("htc", "htc_ocmdugl", "HTC U11 plus", 3, -28, 3),
|
||||
DeviceInfo("htc", "htc_imldugl", "HTC U12 life", 2, -23, 3),
|
||||
DeviceInfo("htc", "htc_imedugl", "HTC U12+", 7, -33, 3),
|
||||
DeviceInfo("htc", "htc_ocedugl", "HTC_U-1u", -5, -29, 3),
|
||||
DeviceInfo("htc", "htc_ocndugl", "HTC_U-3u", 5, -23, 3),
|
||||
DeviceInfo("huawei", "HWANE", "ANE-LX3", 3, -3, 3),
|
||||
DeviceInfo("huawei", "HWCLT", "CLT-L09", -1, -30, 3),
|
||||
DeviceInfo("huawei", "HWCOR", "COR-L29", 2, -5, 3),
|
||||
DeviceInfo("huawei", "HWDRA-MG", "DRA-LX3", 4, -24, 3),
|
||||
DeviceInfo("huawei", "HWTIT-L6735", "HUAWEI TIT-AL00", 4, -10, 3),
|
||||
DeviceInfo("huawei", "HW-01K", "HW-01K", -1, -32, 3),
|
||||
DeviceInfo("huawei", "hwfdra04l", "HWT31", 3, -24, 3),
|
||||
DeviceInfo("huawei", "HNKIW-Q", "KIW-L24", 7, -25, 3),
|
||||
DeviceInfo("huawei", "HWMHA", "MHA-L29", 2, -27, 3),
|
||||
DeviceInfo("huawei", "HWNEO", "NEO-L29", -3, -28, 3),
|
||||
DeviceInfo("huawei", "angler", "Nexus 6P", 6, -27, 3),
|
||||
DeviceInfo("huawei", "HWPIC", "PIC-AL00", -1, -3, 3),
|
||||
DeviceInfo("huawei", "HWPRA-H", "PRA-LX1", 1, -3, 3),
|
||||
DeviceInfo("huawei", "HWWAS-H", "WAS-LX3", 2, -4, 3),
|
||||
DeviceInfo("infinix", "Infinix-X627STU", "Infinix X627", 3, -27, 3),
|
||||
DeviceInfo("infinix", "Infinix-X650", "Infinix X650", 1, -26, 3),
|
||||
DeviceInfo("infinix", "Infinix-X650C", "Infinix X650C", 3, -30, 3),
|
||||
DeviceInfo("infinix", "Infinix-X653", "Infinix X653", 4, -24, 3),
|
||||
DeviceInfo("infinix", "Infinix-X653C", "Infinix X653C", -1, -23, 3),
|
||||
DeviceInfo("itel", "itel-A32F", "itel A32F", 3, -26, 3),
|
||||
DeviceInfo("itel", "itel-L5503", "itel L5503", -3, -6, 3),
|
||||
DeviceInfo("itel", "itel-L6005", "itel L6005", -4, -1, 3),
|
||||
DeviceInfo("itel", "itel-W5504", "itel W5504", -1, -11, 3),
|
||||
DeviceInfo("lava", "Z50", "Z50", 6, -26, 3),
|
||||
DeviceInfo("leagoo", "T5c", "T5c", -29, -23, 3),
|
||||
DeviceInfo("lenovo", "A1010a20", "Lenovo A1010a20", 2, -25, 3),
|
||||
DeviceInfo("lenovo", "A6600d40", "Lenovo A6600d40", 3, -26, 3),
|
||||
DeviceInfo("lenovo", "guamp", "Lenovo K12 Note", 1, -18, 3),
|
||||
DeviceInfo("lenovo", "K33a42", "Lenovo K33a42", 3, -29, 3),
|
||||
DeviceInfo("lenovo", "K33a48", "Lenovo K33a48", 3, -27, 3),
|
||||
DeviceInfo("lenovo", "seoul", "Lenovo K520", 4, -20, 3),
|
||||
DeviceInfo("lenovo", "k52_e78", "Lenovo K52e78", 0, -18, 3),
|
||||
DeviceInfo("lenovo", "K53a48", "Lenovo K53a48", 5, -29, 3),
|
||||
DeviceInfo("lenovo", "brady_f", "Lenovo K8", 4, -22, 3),
|
||||
DeviceInfo("lenovo", "manning", "Lenovo K8 Note", 4, -26, 3),
|
||||
DeviceInfo("lenovo", "jd2018", "Lenovo L78011", 1, -21, 3),
|
||||
DeviceInfo("lenovo", "P2a42", "Lenovo P2a42", 3, -19, 3),
|
||||
DeviceInfo("lenovo", "TB3-710I", "Lenovo TB3-710I", 3, -26, 3),
|
||||
DeviceInfo("lenovo", "zoom_tdd", "Lenovo Z90-3", 5, -22, 3),
|
||||
DeviceInfo("letv", "le_s2_ww", "Le X527", 4, -21, 3),
|
||||
DeviceInfo("lge", "lv0", "LG-AS110", 6, -24, 3),
|
||||
DeviceInfo("lge", "p1", "LG-F500L", -3, -24, 3),
|
||||
DeviceInfo("lge", "h1", "LG-F700L", 9, -28, 3),
|
||||
DeviceInfo("lge", "c50", "LG-H345", 3, -21, 3),
|
||||
DeviceInfo("lge", "g4stylus", "LG-H634", 3, -21, 3),
|
||||
DeviceInfo("lge", "p1", "LG-H815", -3, -25, 3),
|
||||
DeviceInfo("lge", "mme0n", "LG-K100", 2, -23, 3),
|
||||
DeviceInfo("lge", "mm1v", "LG-K350", 1, -21, 3),
|
||||
DeviceInfo("lge", "m253", "LG-K430", 2, -22, 3),
|
||||
DeviceInfo("lge", "k5", "LG-K500", 6, -22, 3),
|
||||
DeviceInfo("lge", "ph1", "LG-K540", 6, -22, 3),
|
||||
DeviceInfo("lge", "mlv5", "LG-M250", 3, -22, 3),
|
||||
DeviceInfo("lge", "mlv1", "LG-X230", 2, -23, 3),
|
||||
DeviceInfo("lge", "mlv3", "LG-X240", 1, -22, 3),
|
||||
DeviceInfo("lge", "e7iilte", "LGLK430", 2, -18, 3),
|
||||
DeviceInfo("lge", "me0", "LGLS450", 5, -24, 3),
|
||||
DeviceInfo("lge", "joan", "LGM-V300L", 4, -21, 3),
|
||||
DeviceInfo("lge", "anna", "LGM-X800L", 6, -13, 3),
|
||||
DeviceInfo("lge", "p1", "LGUS991", -4, -25, 3),
|
||||
DeviceInfo("lge", "mdh30xlm", "LM-K500", 6, -30, 3),
|
||||
DeviceInfo("lge", "mh3", "LM-Q620", 7, -33, 3),
|
||||
DeviceInfo("lge", "mdh50lm", "LM-Q730", 4, -30, 3),
|
||||
DeviceInfo("lge", "phoenix_sprout", "LM-Q910", 4, -24, 3),
|
||||
DeviceInfo("lge", "timelm", "LM-V600", -1, -33, 3),
|
||||
DeviceInfo("lge", "cv1", "LM-X210", 4, -18, 3),
|
||||
DeviceInfo("lge", "bullhead", "Nexus 5X", -6, -25, 3),
|
||||
DeviceInfo("lge", "h1", "RS988", 8, -3, 3),
|
||||
DeviceInfo("lge", "lucye", "VS988", -3, -8, 3),
|
||||
DeviceInfo("lge", "elsa", "VS995", 6, -3, 3),
|
||||
DeviceInfo("meizu", "mx4", "MX4", 5, -5, 3),
|
||||
DeviceInfo("motorola", "athene_f", "Moto G (4)", 0, -17, 3),
|
||||
DeviceInfo("motorola", "cedric", "Moto G (5)", 3, -19, 3),
|
||||
DeviceInfo("motorola", "potter_n", "Moto G (5) Plus", 6, -20, 3),
|
||||
DeviceInfo("motorola", "potter", "Moto G (5) Plus", 3, -19, 3),
|
||||
DeviceInfo("motorola", "sanders", "Moto G (5S) Plus", 4, -19, 3),
|
||||
DeviceInfo("motorola", "harpia", "Moto G Play", 5, -23, 3),
|
||||
DeviceInfo("motorola", "albus", "Moto Z2 Play", 3, -18, 3),
|
||||
DeviceInfo("motorola", "osprey_uds", "MotoG3", 5, -21, 3),
|
||||
DeviceInfo("motorola", "shamu", "Nexus 6", 10, -29, 3),
|
||||
DeviceInfo("motorola", "clark", "XT1575", 0, -30, 3),
|
||||
DeviceInfo("motorola", "harpia", "XT1609", 5, -22, 3),
|
||||
DeviceInfo("motorola", "addison", "XT1635-01", 5, -19, 3),
|
||||
DeviceInfo("motorola", "griffin", "XT1650", -3, -26, 3),
|
||||
DeviceInfo("motorola", "taido_row", "XT1706", 8, -27, 3),
|
||||
DeviceInfo("motorola", "pettyl", "moto e5 play", 1, -27, 3),
|
||||
DeviceInfo("motorola", "rjames_f", "moto e5 play", 3, -18, 3),
|
||||
DeviceInfo("motorola", "kiev", "moto g 5G", 4, -26, 3),
|
||||
DeviceInfo("motorola", "nairo", "moto g 5G plus", -3, -26, 3),
|
||||
DeviceInfo("motorola", "sofiap_sprout", "moto g pro", 4, -34, 3),
|
||||
DeviceInfo("motorola", "jeter", "moto g(6) play", 3, -20, 3),
|
||||
DeviceInfo("motorola", "river", "moto g(7)", 4, -23, 3),
|
||||
DeviceInfo("motorola", "channel", "moto g(7) play", 6, -32, 3),
|
||||
DeviceInfo("motorola", "lake_n", "moto g(7) plus", 3, -23, 3),
|
||||
DeviceInfo("motorola", "doha_n", "moto g(8) plus", 3, -23, 3),
|
||||
DeviceInfo("motorola", "odessa", "moto g(9) plus", 5, -33, 3),
|
||||
DeviceInfo("motorola", "cebu", "moto g(9) power", -2, -16, 3),
|
||||
DeviceInfo("motorola", "payton", "moto x4", 2, -23, 3),
|
||||
DeviceInfo("motorola", "messi", "moto z3", 4, -26, 3),
|
||||
DeviceInfo("motorola", "foles", "moto z4", 8, -30, 3),
|
||||
DeviceInfo("motorola", "racer", "motorola edge", -2, -27, 3),
|
||||
DeviceInfo("motorola", "burton", "motorola edge plus", 8, -35, 3),
|
||||
DeviceInfo("motorola", "deen_sprout", "motorola one", 4, -21, 3),
|
||||
DeviceInfo("motorola", "def", "motorola one hyper", 4, -23, 3),
|
||||
DeviceInfo("motorola", "chef_sprout", "motorola one power", 2, -22, 3),
|
||||
DeviceInfo("nokia", "FRT", "Nokia 1", 2, -24, 3),
|
||||
DeviceInfo("nokia", "ANT", "Nokia 1 Plus", 1, -20, 3),
|
||||
DeviceInfo("nokia", "E2M", "Nokia 2.1", 0, -28, 3),
|
||||
DeviceInfo("nokia", "IRM_sprout", "Nokia 2.3", -3, -21, 3),
|
||||
DeviceInfo("nokia", "ES2_sprout", "Nokia 3.1", 6, -23, 3),
|
||||
DeviceInfo("nokia", "ROON_sprout", "Nokia 3.1 Plus", 0, -24, 3),
|
||||
DeviceInfo("nokia", "DPL_sprout", "Nokia 3.2", 4, -32, 3),
|
||||
DeviceInfo("nokia", "PAN_sprout", "Nokia 4.2", 7, -36, 3),
|
||||
DeviceInfo("nokia", "CO2_sprout", "Nokia 5.1", 6, -25, 3),
|
||||
DeviceInfo("nokia", "PL2_sprout", "Nokia 6.1", 8, -28, 3),
|
||||
DeviceInfo("nokia", "DRG_sprout", "Nokia 6.1 Plus", 6, -27, 3),
|
||||
DeviceInfo("nokia", "B2N_sprout", "Nokia 7 plus", 2, -20, 3),
|
||||
DeviceInfo("nokia", "CTL_sprout", "Nokia 7.1", 6, -24, 3),
|
||||
DeviceInfo("nokia", "DDV_sprout", "Nokia 7.2", 3, -7, 3),
|
||||
DeviceInfo("nokia", "A1N_sprout", "Nokia 8 Sirocco", 12, -30, 3),
|
||||
DeviceInfo("nokia", "PNX_sprout", "Nokia 8.1", 5, -24, 3),
|
||||
DeviceInfo("nokia", "BGT_sprout", "Nokia 8.3 5G", 5, -23, 3),
|
||||
DeviceInfo("nokia", "AOP_sprout", "Nokia 9", 7, -25, 3),
|
||||
DeviceInfo("nokia", "RKU", "Nokia C1", -7, -3, 3),
|
||||
DeviceInfo("nokia", "NB1", "TA-1012", 5, -22, 3),
|
||||
DeviceInfo("nokia", "PLE", "TA-1025", 2, -17, 3),
|
||||
DeviceInfo("nokia", "PL2", "TA-1054", 7, -26, 3),
|
||||
DeviceInfo("nokia 5.1 plus", "Panda_00WW", "PDA_sprout", 5, -28, 3),
|
||||
DeviceInfo("oneplus", "OnePlus7", "GM1900", 3, -17, 3),
|
||||
DeviceInfo("oneplus", "OnePlus7Pro", "GM1910", 3, -18, 3),
|
||||
DeviceInfo("oneplus", "OnePlus7T", "HD1905", 1, -16, 3),
|
||||
DeviceInfo("oneplus", "OnePlus7TPro", "HD1911", 0, -17, 3),
|
||||
DeviceInfo("oneplus", "OnePlus8", "IN2011", 4, -27, 3),
|
||||
DeviceInfo("oneplus", "OnePlus8Pro", "IN2025", 6, -29, 3),
|
||||
DeviceInfo("oneplus", "OnePlus8T", "KB2003", 5, -31, 3),
|
||||
DeviceInfo("oneplus", "OnePlus5", "ONEPLUS A5000", 6, -25, 3),
|
||||
DeviceInfo("oneplus", "OnePlus5T", "ONEPLUS A5010", 3, -22, 3),
|
||||
DeviceInfo("oneplus", "OnePlus6", "ONEPLUS A6000", 3, -23, 3),
|
||||
DeviceInfo("oneplus", "OnePlus6", "ONEPLUS A6003", 4, -29, 3),
|
||||
DeviceInfo("oneplus", "OnePlus6T", "ONEPLUS A6010", 2, -19, 3),
|
||||
DeviceInfo("oneplus", "OnePlus6T", "ONEPLUS A6013", 1, -21, 3),
|
||||
DeviceInfo("oppo", "CPH1715", "CPH1715", 2, -25, 3),
|
||||
DeviceInfo("oppo", "CPH1717", "CPH1717", -4, -18, 3),
|
||||
DeviceInfo("oppo", "CPH1721", "CPH1721", -1, -20, 3),
|
||||
DeviceInfo("oppo", "CPH1723", "CPH1723", 3, -24, 3),
|
||||
DeviceInfo("oppo", "CPH1803", "CPH1803", -1, -17, 3),
|
||||
DeviceInfo("oppo", "CPH1823", "CPH1823", -2, -21, 3),
|
||||
DeviceInfo("oppo", "OP4845", "CPH1919", 3, -24, 3),
|
||||
DeviceInfo("oppo", "CPH1920", "CPH1920", -2, -24, 3),
|
||||
DeviceInfo("oppo", "OP4B79L1", "CPH1931", 4, -32, 3),
|
||||
DeviceInfo("oppo", "OP4B65L1", "CPH1945", -1, -26, 3),
|
||||
DeviceInfo("oppo", "OP4863", "CPH1969", 2, -27, 3),
|
||||
DeviceInfo("oppo", "OP48A1L1", "CPH1979", 0, -36, 3),
|
||||
DeviceInfo("oppo", "OP4C4BL1", "CPH1989", -4, -21, 3),
|
||||
DeviceInfo("oppo", "OP4C2DL1", "CPH2009", 4, -26, 3),
|
||||
DeviceInfo("oppo", "OP4BA1L1", "CPH2023", 9, -37, 3),
|
||||
DeviceInfo("orange", "Neva_play", "Orange Neva play", -1, -12, 3),
|
||||
DeviceInfo("orange", "Neva_zen", "Orange Neva zen", -5, -3, 3),
|
||||
DeviceInfo("orbic", "RC555L", "RC555L", 5, -26, 3),
|
||||
DeviceInfo("razer", "cheryl", "Phone", 7, -26, 3),
|
||||
DeviceInfo("razer", "aura", "Phone 2", 3, -24, 3),
|
||||
DeviceInfo("redmi", "olivelite", "Redmi 8A", 5, -30, 3),
|
||||
DeviceInfo("redmi", "lavender", "Redmi Note 7", 5, -29, 3),
|
||||
DeviceInfo("redmi", "ginkgo", "Redmi Note 8", 4, -19, 3),
|
||||
DeviceInfo("samsung", "poseidonlteatt", "SAMSUNG-SM-G891A", 4, -27, 3),
|
||||
DeviceInfo("samsung", "klteatt", "SAMSUNG-SM-G900A", 9, -23, 3),
|
||||
DeviceInfo("samsung", "heroqlteaio", "SAMSUNG-SM-G930AZ", 11, -33, 3),
|
||||
DeviceInfo("samsung", "hero2qlteatt", "SAMSUNG-SM-G935A", 10, -33, 3),
|
||||
DeviceInfo("samsung", "SC-02J", "SC-02J", 11, -31, 3),
|
||||
DeviceInfo("samsung", "SC-02K", "SC-02K", 11, -29, 3),
|
||||
DeviceInfo("samsung", "SC-02L", "SC-02L", 5, -23, 3),
|
||||
DeviceInfo("samsung", "SC-03K", "SC-03K", 15, -34, 3),
|
||||
DeviceInfo("samsung", "SCV33", "SCV33", 7, -29, 3),
|
||||
DeviceInfo("samsung", "SCV36", "SCV36", 9, -24, 3),
|
||||
DeviceInfo("samsung", "a10e", "SM-A102U", 6, -25, 3),
|
||||
DeviceInfo("samsung", "a10", "SM-A105F", 3, -23, 3),
|
||||
DeviceInfo("samsung", "a10", "SM-A105FN", 4, -25, 3),
|
||||
DeviceInfo("samsung", "a10", "SM-A105G", 2, -23, 3),
|
||||
DeviceInfo("samsung", "a10", "SM-A105M", 1, -23, 3),
|
||||
DeviceInfo("samsung", "a10s", "SM-A107F", 5, -30, 3),
|
||||
DeviceInfo("samsung", "a20e", "SM-A202F", 2, -26, 3),
|
||||
DeviceInfo("samsung", "a20", "SM-A205F", 3, -26, 3),
|
||||
DeviceInfo("samsung", "a20", "SM-A205G", 2, -24, 3),
|
||||
DeviceInfo("samsung", "a20p", "SM-A205U", 23, -47, 3),
|
||||
DeviceInfo("samsung", "a20s", "SM-A207F", 8, -32, 3),
|
||||
DeviceInfo("samsung", "a3ulte", "SM-A300FU", 6, -23, 3),
|
||||
DeviceInfo("samsung", "a30", "SM-A305F", 4, -23, 3),
|
||||
DeviceInfo("samsung", "a30s", "SM-A307FN", 2, -26, 3),
|
||||
DeviceInfo("samsung", "a3y17lte", "SM-A320FL", -10, -23, 3),
|
||||
DeviceInfo("samsung", "a40", "SM-A405FN", 2, -23, 3),
|
||||
DeviceInfo("samsung", "a50", "SM-A505F", 0, -20, 3),
|
||||
DeviceInfo("samsung", "a50", "SM-A505FM", 3, -20, 3),
|
||||
DeviceInfo("samsung", "a50", "SM-A505FN", -2, -20, 3),
|
||||
DeviceInfo("samsung", "a5xelte", "SM-A510F", 6, -2, 3),
|
||||
DeviceInfo("samsung", "a5xelte", "SM-A510M", 3, -1, 3),
|
||||
DeviceInfo("samsung", "a51", "SM-A515F", 2, -28, 3),
|
||||
DeviceInfo("samsung", "a5y17lte", "SM-A520F", -6, -25, 3),
|
||||
DeviceInfo("samsung", "jackpotlte", "SM-A530F", 2, -23, 3),
|
||||
DeviceInfo("samsung", "a6lte", "SM-A600FN", 8, -35, 3),
|
||||
DeviceInfo("samsung", "a70q", "SM-A705FN", 5, -33, 3),
|
||||
DeviceInfo("samsung", "a7xelte", "SM-A710F", 5, -5, 3),
|
||||
DeviceInfo("samsung", "a7y18lte", "SM-A750F", 4, -24, 3),
|
||||
DeviceInfo("samsung", "a7y18lte", "SM-A750FN", 5, -26, 3),
|
||||
DeviceInfo("samsung", "a7y18lte", "SM-A750GN", 6, -23, 3),
|
||||
DeviceInfo("samsung", "a9y18qltechn", "SM-A9200", 5, -24, 3),
|
||||
DeviceInfo("samsung", "a9y18qlte", "SM-A920F", 4, -21, 3),
|
||||
DeviceInfo("samsung", "c5proltechn", "SM-C5010", 9, -26, 3),
|
||||
DeviceInfo("samsung", "jadeltechn", "SM-C7100", 8, -26, 3),
|
||||
DeviceInfo("samsung", "elitexlte", "SM-G1650", 6, -30, 3),
|
||||
DeviceInfo("samsung", "grandpplte", "SM-G532M", 4, -24, 3),
|
||||
DeviceInfo("samsung", "on5xelte", "SM-G570F", 7, -24, 3),
|
||||
DeviceInfo("samsung", "on5xelte", "SM-G570M", 2, -24, 3),
|
||||
DeviceInfo("samsung", "o7ltechn", "SM-G6000", 3, -22, 3),
|
||||
DeviceInfo("samsung", "on7xelte", "SM-G610F", 7, 2, 3),
|
||||
DeviceInfo("samsung", "on7xreflte", "SM-G611F", 6, -2, 3),
|
||||
DeviceInfo("samsung", "slte", "SM-G850F", 17, -33, 3),
|
||||
DeviceInfo("samsung", "astarqltechn", "SM-G8850", 3, -24, 3),
|
||||
DeviceInfo("samsung", "astarqlteskt", "SM-G885S", 1, -24, 3),
|
||||
DeviceInfo("samsung", "cruiserlteatt", "SM-G892A", 8, -24, 3),
|
||||
DeviceInfo("samsung", "klte", "SM-G900F", 12, -24, 3),
|
||||
DeviceInfo("samsung", "zeroflte", "SM-G920F", 9, -25, 3),
|
||||
DeviceInfo("samsung", "zeroflte", "SM-G920I", 7, -24, 3),
|
||||
DeviceInfo("samsung", "zerofltetmo", "SM-G920T", 8, -24, 3),
|
||||
DeviceInfo("samsung", "zerolte", "SM-G925F", 8, -25, 3),
|
||||
DeviceInfo("samsung", "zerolte", "SM-G925I", 4, -23, 3),
|
||||
DeviceInfo("samsung", "herolte", "SM-G930F", 9, -33, 3),
|
||||
DeviceInfo("samsung", "heroqltespr", "SM-G930P", 7, -32, 3),
|
||||
DeviceInfo("samsung", "heroqlteusc", "SM-G930R4", 12, -35, 3),
|
||||
DeviceInfo("samsung", "heroqltevzw", "SM-G930V", 9, -32, 3),
|
||||
DeviceInfo("samsung", "hero2qltechn", "SM-G9350", 8, -31, 3),
|
||||
DeviceInfo("samsung", "hero2lte", "SM-G935F", 11, -33, 3),
|
||||
DeviceInfo("samsung", "hero2qltespr", "SM-G935P", 8, -31, 3),
|
||||
DeviceInfo("samsung", "hero2qlteusc", "SM-G935R4", 9, -29, 3),
|
||||
DeviceInfo("samsung", "hero2qltetmo", "SM-G935T", 4, -28, 3),
|
||||
DeviceInfo("samsung", "hero2qltevzw", "SM-G935V", 14, -34, 3),
|
||||
DeviceInfo("samsung", "dreamlte", "SM-G950F", 12, -29, 3),
|
||||
DeviceInfo("samsung", "dreamlteks", "SM-G950N", 11, -27, 3),
|
||||
DeviceInfo("samsung", "dreamqlteue", "SM-G950U1", 10, -27, 3),
|
||||
DeviceInfo("samsung", "dreamqltecan", "SM-G950W", 9, -24, 3),
|
||||
DeviceInfo("samsung", "dream2lte", "SM-G955F", 9, -26, 3),
|
||||
DeviceInfo("samsung", "dream2lteks", "SM-G955N", 10, -26, 3),
|
||||
DeviceInfo("samsung", "dream2qlteue", "SM-G955U1", 10, -26, 3),
|
||||
DeviceInfo("samsung", "dream2qltecan", "SM-G955W", 8, -23, 3),
|
||||
DeviceInfo("samsung", "starqltechn", "SM-G9600", 4, -22, 3),
|
||||
DeviceInfo("samsung", "starlte", "SM-G960F", 8, -28, 3),
|
||||
DeviceInfo("samsung", "starlteks", "SM-G960N", 7, -28, 3),
|
||||
DeviceInfo("samsung", "starqltesq", "SM-G960U", 5, -21, 3),
|
||||
DeviceInfo("samsung", "starqlteue", "SM-G960U1", 4, -19, 3),
|
||||
DeviceInfo("samsung", "star2qltechn", "SM-G9650", 7, -26, 3),
|
||||
DeviceInfo("samsung", "star2lte", "SM-G965F", 8, -27, 3),
|
||||
DeviceInfo("samsung", "star2lteks", "SM-G965N", 9, -25, 3),
|
||||
DeviceInfo("samsung", "star2qltesq", "SM-G965U", 8, -25, 3),
|
||||
DeviceInfo("samsung", "star2qlteue", "SM-G965U1", 6, -24, 3),
|
||||
DeviceInfo("samsung", "beyond1", "SM-G973F", 2, -29, 3),
|
||||
DeviceInfo("samsung", "beyond1q", "SM-G973U", -1, -26, 3),
|
||||
DeviceInfo("samsung", "beyond2", "SM-G975F", 1, -26, 3),
|
||||
DeviceInfo("samsung", "beyond2q", "SM-G975U", 0, -24, 3),
|
||||
DeviceInfo("samsung", "beyondx", "SM-G977N", 0, -26, 3),
|
||||
DeviceInfo("samsung", "beyondxq", "SM-G977P", -3, -34, 3),
|
||||
DeviceInfo("samsung", "j1qltevzw", "SM-J100VPP", 6, -22, 3),
|
||||
DeviceInfo("samsung", "j2y18lte", "SM-J250F", 3, -27, 3),
|
||||
DeviceInfo("samsung", "j2corelte", "SM-J260F", 5, -25, 3),
|
||||
DeviceInfo("samsung", "j2corelte", "SM-J260G", 7, -27, 3),
|
||||
DeviceInfo("samsung", "j2corelte", "SM-J260M", 6, -25, 3),
|
||||
DeviceInfo("samsung", "j3ltevzw", "SM-J320V", 1, -17, 3),
|
||||
DeviceInfo("samsung", "j3popelteue", "SM-J327U", 6, -24, 3),
|
||||
DeviceInfo("samsung", "j3y17ltelgt", "SM-J330F", 3, -24, 3),
|
||||
DeviceInfo("samsung", "j3y17lte", "SM-J330FN", 4, -28, 3),
|
||||
DeviceInfo("samsung", "j3y17ltelgt", "SM-J330L", 2, -22, 3),
|
||||
DeviceInfo("samsung", "j3topeltevzw", "SM-J337V", 0, -19, 3),
|
||||
DeviceInfo("samsung", "j4lte", "SM-J400F", 6, -27, 3),
|
||||
DeviceInfo("samsung", "j4lte", "SM-J400M", 8, -27, 3),
|
||||
DeviceInfo("samsung", "j4primelte", "SM-J415F", 3, -29, 3),
|
||||
DeviceInfo("samsung", "j4primelte", "SM-J415G", 4, -28, 3),
|
||||
DeviceInfo("samsung", "j5lte", "SM-J500F", 4, -19, 3),
|
||||
DeviceInfo("samsung", "j53g", "SM-J500H", -1, -18, 3),
|
||||
DeviceInfo("samsung", "j5lte", "SM-J500M", 2, -18, 3),
|
||||
DeviceInfo("samsung", "j5xnlte", "SM-J510FN", 1, -18, 3),
|
||||
DeviceInfo("samsung", "j5xnlte", "SM-J510GN", 3, -19, 3),
|
||||
DeviceInfo("samsung", "j5xnlte", "SM-J510MN", 3, -20, 3),
|
||||
DeviceInfo("samsung", "j5y17lte", "SM-J530F", 8, -33, 3),
|
||||
DeviceInfo("samsung", "j6lte", "SM-J600FN", 7, -24, 3),
|
||||
DeviceInfo("samsung", "j6primelte", "SM-J610F", 3, -27, 3),
|
||||
DeviceInfo("samsung", "j6primelte", "SM-J610G", 3, -28, 3),
|
||||
DeviceInfo("samsung", "j7velte", "SM-J701F", 8, -3, 3),
|
||||
DeviceInfo("samsung", "j7popltevzw", "SM-J727V", 4, -20, 3),
|
||||
DeviceInfo("samsung", "j7y17lte", "SM-J730F", 6, -33, 3),
|
||||
DeviceInfo("samsung", "j7y17lte", "SM-J730FM", 7, -34, 3),
|
||||
DeviceInfo("samsung", "j7y17ltektt", "SM-J730K", 4, -30, 3),
|
||||
DeviceInfo("samsung", "j8y18lte", "SM-J810F", 5, -29, 3),
|
||||
DeviceInfo("samsung", "j8y18lte", "SM-J810M", 5, -32, 3),
|
||||
DeviceInfo("samsung", "m20lte", "SM-M205F", 3, -22, 3),
|
||||
DeviceInfo("samsung", "trelte", "SM-N910C", 11, -31, 3),
|
||||
DeviceInfo("samsung", "tblte", "SM-N915G", 7, -24, 3),
|
||||
DeviceInfo("samsung", "noblelte", "SM-N9208", 4, -29, 3),
|
||||
DeviceInfo("samsung", "noblelte", "SM-N920C", 5, -30, 3),
|
||||
DeviceInfo("samsung", "greatlte", "SM-N950F", 8, -24, 3),
|
||||
DeviceInfo("samsung", "greatlteks", "SM-N950N", 6, -24, 3),
|
||||
DeviceInfo("samsung", "greatqlte", "SM-N950U", 9, -25, 3),
|
||||
DeviceInfo("samsung", "greatqlteue", "SM-N950U1", 9, -26, 3),
|
||||
DeviceInfo("samsung", "crownlte", "SM-N960F", 7, -28, 3),
|
||||
DeviceInfo("samsung", "crownlteks", "SM-N960N", 9, -27, 3),
|
||||
DeviceInfo("samsung", "crownqltesq", "SM-N960U", 5, -24, 3),
|
||||
DeviceInfo("samsung", "crownqlteue", "SM-N960U1", 5, -24, 3),
|
||||
DeviceInfo("samsung", "j3topeltetfnvzw", "SM-S367VL", 3, -21, 3),
|
||||
DeviceInfo("samsung", "j7popqltetfnvzw", "SM-S727VL", 4, -18, 3),
|
||||
DeviceInfo("samsung", "gt58wifi", "SM-T350", 2, -18, 3),
|
||||
DeviceInfo("samsung", "gtesveltevzw", "SM-T378V", 1, -20, 3),
|
||||
DeviceInfo("samsung", "gta2swifi", "SM-T380", 4, -19, 3),
|
||||
DeviceInfo("samsung", "gta2swifichn", "SM-T380C", 4, -20, 3),
|
||||
DeviceInfo("samsung", "gta2sltechn", "SM-T385C", 4, -20, 3),
|
||||
DeviceInfo("samsung", "gta2sltektt", "SM-T385K", 3, -18, 3),
|
||||
DeviceInfo("samsung", "gta2sltelgt", "SM-T385L", 2, -19, 3),
|
||||
DeviceInfo("samsung", "gtactive2wifi", "SM-T390", -11, -23, 3),
|
||||
DeviceInfo("samsung", "gtactive2lte", "SM-T395", -8, -26, 3),
|
||||
DeviceInfo("samsung", "gtaxlwifi", "SM-T580", -12, -22, 3),
|
||||
DeviceInfo("samsung", "gts3lwifi", "SM-T820", -10, -23, 3),
|
||||
DeviceInfo("samsung", "gts3lltevzw", "SM-T827V", 0, -22, 3),
|
||||
DeviceInfo("samsung", "gts4lltevzw", "SM-T837V", 1, -20, 3),
|
||||
DeviceInfo("sg", "OI6", "A001SH", 9, -32, 3),
|
||||
DeviceInfo("sharp", "eve_sprout", "507SH", 6, -29, 3),
|
||||
DeviceInfo("sharp", "SG509SH", "509SH", 3, -34, 3),
|
||||
DeviceInfo("sharp", "SG704SH", "704SH", 5, -32, 3),
|
||||
DeviceInfo("sharp", "kaleido_sprout", "S1", 3, -22, 3),
|
||||
DeviceInfo("sharp", "rome_sprout", "S3-SH", 5, -39, 3),
|
||||
DeviceInfo("sharp", "zeon_sprout", "S5-SH", 2, -25, 3),
|
||||
DeviceInfo("sharp", "SH-01K", "SH-01K", 4, -34, 3),
|
||||
DeviceInfo("sharp", "SH-01L", "SH-01L", 3, -25, 3),
|
||||
DeviceInfo("sharp", "SH-01M", "SH-01M", 7, -27, 3),
|
||||
DeviceInfo("sharp", "SH-02J", "SH-02J", 5, -34, 3),
|
||||
DeviceInfo("sharp", "SH-02M", "SH-02M", 5, -29, 3),
|
||||
DeviceInfo("sharp", "SH-03J", "SH-03J", 6, -24, 3),
|
||||
DeviceInfo("sharp", "SH-03K", "SH-03K", 4, -28, 3),
|
||||
DeviceInfo("sharp", "SH-04H", "SH-04H", 1, -36, 3),
|
||||
DeviceInfo("sharp", "SH-04L", "SH-04L", 5, -27, 3),
|
||||
DeviceInfo("sharp", "SH-51A", "SH-51A", 4, -41, 3),
|
||||
DeviceInfo("sharp", "SHV36", "SHV36", 6, -36, 3),
|
||||
DeviceInfo("sharp", "HUR", "SHV39", 5, -22, 3),
|
||||
DeviceInfo("sm-j415f", "j4primeltedx", "j4primelte", 4, -26, 3),
|
||||
DeviceInfo("softbank", "Z8851S", "902ZT", 6, -34, 3),
|
||||
DeviceInfo("sony", "601SO", "601SO", 1, -36, 3),
|
||||
DeviceInfo("sony", "602SO", "602SO", -3, -30, 3),
|
||||
DeviceInfo("sony", "701SO", "701SO", 6, -26, 3),
|
||||
DeviceInfo("sony", "E6603", "E6603", 10, -26, 3),
|
||||
DeviceInfo("sony", "E6633", "E6633", 13, -26, 3),
|
||||
DeviceInfo("sony", "F5121", "F5121", 8, -34, 3),
|
||||
DeviceInfo("sony", "F8131", "F8131", 1, -32, 3),
|
||||
DeviceInfo("sony", "F8331", "F8331", -2, -29, 3),
|
||||
DeviceInfo("sony", "F8332", "F8332", -2, -31, 3),
|
||||
DeviceInfo("sony", "G3123", "G3123", 4, -24, 3),
|
||||
DeviceInfo("sony", "G3223", "G3223", 8, -27, 3),
|
||||
DeviceInfo("sony", "G8141", "G8141", 11, -34, 3),
|
||||
DeviceInfo("sony", "G8142", "G8142", 10, -27, 3),
|
||||
DeviceInfo("sony", "G8232", "G8232", 0, -34, 3),
|
||||
DeviceInfo("sony", "G8341", "G8341", 10, -31, 3),
|
||||
DeviceInfo("sony", "G8342", "G8342", 9, -28, 3),
|
||||
DeviceInfo("sony", "G8441", "G8441", 5, -24, 3),
|
||||
DeviceInfo("sony", "H4113", "H4113", 9, -31, 3),
|
||||
DeviceInfo("sony", "H8216", "H8216", 5, -31, 3),
|
||||
DeviceInfo("sony", "H8266", "H8266", 6, -30, 3),
|
||||
DeviceInfo("sony", "H8296", "H8296", 8, -32, 3),
|
||||
DeviceInfo("sony", "H8314", "H8314", 9, -33, 3),
|
||||
DeviceInfo("sony", "H8324", "H8324", 9, -33, 3),
|
||||
DeviceInfo("sony", "H8416", "H8416", 6, -30, 3),
|
||||
DeviceInfo("sony", "I3113", "I3113", 4, -28, 3),
|
||||
DeviceInfo("sony", "I4213", "I4213", 8, -29, 3),
|
||||
DeviceInfo("sony", "I4312", "I4312", 4, -31, 3),
|
||||
DeviceInfo("sony", "SO-01J", "SO-01J", 0, -32, 3),
|
||||
DeviceInfo("sony", "SO-01K", "SO-01K", 7, -29, 3),
|
||||
DeviceInfo("sony", "SO-01L", "SO-01L", 5, -32, 3),
|
||||
DeviceInfo("sony", "SO-02L", "SO-02L", 3, -26, 3),
|
||||
DeviceInfo("sony", "SO-03J", "SO-03J", 0, -34, 3),
|
||||
DeviceInfo("sony", "SO-03K", "SO-03K", 5, -29, 3),
|
||||
DeviceInfo("sony", "SO-03L", "SO-03L", 7, -28, 3),
|
||||
DeviceInfo("sony", "SO-04J", "SO-04J", 10, -31, 3),
|
||||
DeviceInfo("sony", "SO-05K", "SO-05K", 8, -31, 3),
|
||||
DeviceInfo("sony", "SO-51A", "SO-51A", 4, -45, 3),
|
||||
DeviceInfo("sony", "SOV33", "SOV33", -3, -33, 3),
|
||||
DeviceInfo("sony", "SOV34", "SOV34", -2, -32, 3),
|
||||
DeviceInfo("sony", "SOV36", "SOV36", 8, -27, 3),
|
||||
DeviceInfo("sony", "SOV41", "SOV41", 3, -25, 3),
|
||||
DeviceInfo("sony", "SOV42", "SOV42", 4, -29, 3),
|
||||
DeviceInfo("sony", "XQ-AD51", "XQ-AD51", 6, -31, 3),
|
||||
DeviceInfo("sprint", "htc_acawhl", "2PYB2", 10, -27, 3),
|
||||
DeviceInfo("tcl", "A5A_INFINI", "5086D", 3, -26, 3),
|
||||
DeviceInfo("tcl", "T1_LITE", "T770B", 4, -34, 3),
|
||||
DeviceInfo("tcl", "T1", "T780H", 5, -33, 3),
|
||||
DeviceInfo("tcl", "Seattle", "T790Y", 2, -32, 3),
|
||||
DeviceInfo("tcl", "T1_PRO", "T799H", 1, -31, 3),
|
||||
DeviceInfo("tct (alcatel)", "Pixi4-4", "4034D", 13, -40, 3),
|
||||
DeviceInfo("tct (alcatel)", "Seoul", "5002D_EEA", 2, -33, 3),
|
||||
DeviceInfo("tct (alcatel)", "PIXI3_45_4G", "5017O", 5, -29, 3),
|
||||
DeviceInfo("tct (alcatel)", "Faraday", "5024A", -6, -6, 3),
|
||||
DeviceInfo("tct (alcatel)", "A3A_XL_3G", "5026A", 0, -26, 3),
|
||||
DeviceInfo("tct (alcatel)", "TokyoPro", "5029E", -2, -24, 3),
|
||||
DeviceInfo("tct (alcatel)", "Jakarta", "5030D_EEA", -8, -6, 3),
|
||||
DeviceInfo("tct (alcatel)", "Morgan_4G", "5032W", 2, -29, 3),
|
||||
DeviceInfo("tct (alcatel)", "U3A_PLUS_4G", "5033M", 3, -26, 3),
|
||||
DeviceInfo("tct (alcatel)", "U50A_ATT", "5041C", 2, -24, 3),
|
||||
DeviceInfo("tct (alcatel)", "BUZZ6T4G", "5044P", 9, -33, 3),
|
||||
DeviceInfo("tct (alcatel)", "PIXI4_5_4G", "5045F", 19, -43, 3),
|
||||
DeviceInfo("tct (alcatel)", "mickey6t", "5049G", 2, -26, 3),
|
||||
DeviceInfo("tct (alcatel)", "Mickey6TVZW", "5049S", 3, -26, 3),
|
||||
DeviceInfo("tct (alcatel)", "Mickey6TTMO", "5049Z", 5, -29, 3),
|
||||
DeviceInfo("tct (alcatel)", "A3A_PLUS", "5058A", 4, -27, 3),
|
||||
DeviceInfo("tct (alcatel)", "U5A_PLUS_4G", "5059A", 1, -20, 3),
|
||||
DeviceInfo("tct (alcatel)", "Milan", "5061K", 2, -30, 3),
|
||||
DeviceInfo("tct (alcatel)", "shine_lite", "5080X", 4, -27, 3),
|
||||
DeviceInfo("tct (alcatel)", "A3A_XL_4G", "5099U", 2, -27, 3),
|
||||
DeviceInfo("tct (alcatel)", "FERMI_TF", "A501DL", 1, -24, 3),
|
||||
DeviceInfo("tct (alcatel)", "U50A_PLUS_TF", "A502DL", 5, -27, 3),
|
||||
DeviceInfo("tct (alcatel)", "BUZZ6T4GTFUMTS", "A574BL", 3, -28, 3),
|
||||
DeviceInfo("tct (alcatel)", "FERMI_ATT", "Alcatel_5005R", 2, -25, 3),
|
||||
DeviceInfo("tct (alcatel)", "BUZZ6T4GGOPHONE", "Alcatel_5044R", 4, -28, 3),
|
||||
DeviceInfo("tct (alcatel)", "U50A_PLUS_ATT", "Alcatel_5059R", 3, -27, 3),
|
||||
DeviceInfo("tecno", "TECNO-BA2", "TECNO BA2", 3, -27, 3),
|
||||
DeviceInfo("tecno", "TECNO-BB4k", "TECNO BB4k", 6, -28, 3),
|
||||
DeviceInfo("tecno", "TECNO-CC6", "TECNO CC6", 0, -28, 3),
|
||||
DeviceInfo("tecno", "TECNO-CC7", "TECNO CC7", 1, -25, 3),
|
||||
DeviceInfo("tecno", "TECNO-CE9", "TECNO CE9", 3, -27, 3),
|
||||
DeviceInfo("tecno", "TECNO-CF7", "TECNO CF7", 3, -11, 3),
|
||||
DeviceInfo("tecno", "TECNO-KB7j", "TECNO KB7j", 5, -29, 3),
|
||||
DeviceInfo("tecno", "TECNO-KC1", "TECNO KC1", 7, -28, 3),
|
||||
DeviceInfo("tecno", "TECNO-KC2", "TECNO KC2", 9, -33, 3),
|
||||
DeviceInfo("tecno", "TECNO-KC6", "TECNO KC6", 4, -28, 3),
|
||||
DeviceInfo("tecno", "TECNO-KC8", "TECNO KC8", 4, -28, 3),
|
||||
DeviceInfo("tecno", "TECNO-LC6", "TECNO LC6", 2, -31, 3),
|
||||
DeviceInfo("tesla", "SS0801", "AC2003", 1, -29, 3),
|
||||
DeviceInfo("vivo", "1723", "vivo 1723", 4, -20, 3),
|
||||
DeviceInfo("vivo", "1804", "vivo 1804", 5, -26, 3),
|
||||
DeviceInfo("vodafone", "VFD610", "VFD 610", 7, -29, 3),
|
||||
DeviceInfo("xiaomi", "cancro", "MI 4W", 4, -21, 3),
|
||||
DeviceInfo("xiaomi", "gemini", "MI 5", -2, -27, 3),
|
||||
DeviceInfo("xiaomi", "capricorn", "MI 5s", -4, -26, 3),
|
||||
DeviceInfo("xiaomi", "natrium", "MI 5s Plus", -3, -23, 3),
|
||||
DeviceInfo("xiaomi", "sagit", "MI 6", 2, -22, 3),
|
||||
DeviceInfo("xiaomi", "dipper", "MI 8", 1, -22, 3),
|
||||
DeviceInfo("xiaomi", "platina", "MI 8 Lite", 1, -21, 3),
|
||||
DeviceInfo("xiaomi", "equuleus", "MI 8 Pro", 1, -30, 3),
|
||||
DeviceInfo("xiaomi", "nitrogen", "MI MAX 3", 3, -24, 3),
|
||||
DeviceInfo("xiaomi", "virgo", "MI NOTE LTE", 9, -23, 3),
|
||||
DeviceInfo("xiaomi", "lithium", "MIX", -2, -27, 3),
|
||||
DeviceInfo("xiaomi", "davinci", "Mi 9T", 3, -31, 3),
|
||||
DeviceInfo("xiaomi", "tissot_sprout", "Mi A1", 1, -18, 3),
|
||||
DeviceInfo("xiaomi", "jasmine_sprout", "Mi A2", 2, -23, 3),
|
||||
DeviceInfo("xiaomi", "daisy_sprout", "Mi A2 Lite", 4, -21, 3),
|
||||
DeviceInfo("xiaomi", "laurel_sprout", "Mi A3", 1, -19, 3),
|
||||
DeviceInfo("xiaomi", "chiron", "Mi MIX 2", 6, -24, 3),
|
||||
DeviceInfo("xiaomi", "polaris", "Mi MIX 2S", 1, -19, 3),
|
||||
DeviceInfo("xiaomi", "scorpio", "Mi Note 2", -2, -25, 3),
|
||||
DeviceInfo("xiaomi", "ido", "Redmi 3", 3, -21, 3),
|
||||
DeviceInfo("xiaomi", "land", "Redmi 3S", -1, -25, 3),
|
||||
DeviceInfo("xiaomi", "santoni", "Redmi 4X", -1, -23, 3),
|
||||
DeviceInfo("xiaomi", "rosy", "Redmi 5", 4, -31, 3),
|
||||
DeviceInfo("xiaomi", "riva", "Redmi 5A", 3, -29, 3),
|
||||
DeviceInfo("xiaomi", "cereus", "Redmi 6", 1, -25, 3),
|
||||
DeviceInfo("xiaomi", "sakura_india", "Redmi 6 Pro", 5, -21, 3),
|
||||
DeviceInfo("xiaomi", "cactus", "Redmi 6A", 2, -27, 3),
|
||||
DeviceInfo("xiaomi", "onc", "Redmi 7", 4, -30, 3),
|
||||
DeviceInfo("xiaomi", "pine", "Redmi 7A", 4, -34, 3),
|
||||
DeviceInfo("xiaomi", "olive", "Redmi 8", 10, -31, 3),
|
||||
DeviceInfo("xiaomi", "tiare", "Redmi Go", 5, -31, 3),
|
||||
DeviceInfo("xiaomi", "kenzo", "Redmi Note 3", 5, -22, 3),
|
||||
DeviceInfo("xiaomi", "whyred", "Redmi Note 5", 1, -20, 3),
|
||||
DeviceInfo("xiaomi", "tulip", "Redmi Note 6 Pro", 4, -29, 3),
|
||||
DeviceInfo("xiaomi", "violet", "Redmi Note 7 Pro", 4, -30, 3),
|
||||
DeviceInfo("xiaomi", "ysl", "Redmi S2", 4, -29, 3),
|
||||
DeviceInfo("zte", "P809F15", "BLADE A6 MAX", 4, -28, 3),
|
||||
DeviceInfo("zte", "P450L10", "BLADE V9", 7, -31, 3),
|
||||
DeviceInfo("zte", "P963F50", "Blade A5 2020-T", -3, -11, 3),
|
||||
DeviceInfo("zte", "Z6350T", "Blade A7S 2020-T", -4, 1, 3),
|
||||
DeviceInfo("zte", "Z6351O", "P650 Pro", -4, 0, 3),
|
||||
DeviceInfo("zte", "T86", "T86", 3, -29, 3),
|
||||
DeviceInfo("zte", "Z3351", "Z3351S", 3, -25, 3),
|
||||
DeviceInfo("zte", "Z5151", "Z5151V", 6, -33, 3),
|
||||
DeviceInfo("zte", "Z5156", "Z5156CC", 0, -25, 3),
|
||||
DeviceInfo("zte", "Z5157", "Z5157V", -1, -24, 3),
|
||||
DeviceInfo("zte", "Z6201", "Z6201V", 12, -36, 3),
|
||||
DeviceInfo("zte", "Z6250", "Z6250CC", 0, -25, 3),
|
||||
DeviceInfo("zte", "Z6530", "Z6530V", 15, -39, 3),
|
||||
DeviceInfo("zte", "camellia", "Z833", 3, -25, 3),
|
||||
DeviceInfo("zte", "Z7750R", "ZR01", 16, -36, 3),
|
||||
DeviceInfo("zte", "P963F05", "ZTE 8010", -3, -2, 3),
|
||||
DeviceInfo("zte", "P963F05", "ZTE 8010RU", -3, -2, 3),
|
||||
DeviceInfo("zte", "P671F60", "ZTE 9000", 4, -28, 3),
|
||||
DeviceInfo("zte", "P683S10", "ZTE 9000N", 9, -31, 3),
|
||||
DeviceInfo("zte", "P845A01", "ZTE A2019G Pro", 8, -26, 3),
|
||||
DeviceInfo("zte", "P855A02", "ZTE A2020 Pro", 6, -25, 3),
|
||||
DeviceInfo("zte", "P855A01", "ZTE A2020G Pro", 8, -28, 3),
|
||||
DeviceInfo("zte", "P855A21", "ZTE A2020N3 Pro", 6, -26, 3),
|
||||
DeviceInfo("zte", "P855A03_NA", "ZTE A2020U Pro", 6, -26, 3),
|
||||
DeviceInfo("zte", "P725A12", "ZTE A2021", 9, -29, 3),
|
||||
DeviceInfo("zte", "P725A11", "ZTE A2021G", -1, -29, 3),
|
||||
DeviceInfo("zte", "P725A12", "ZTE A2021H", 0, -28, 3),
|
||||
DeviceInfo("zte", "P725A02", "ZTE A2121", 9, -31, 3),
|
||||
DeviceInfo("zte", "P618A01", "ZTE A2121E", 1, -26, 3),
|
||||
DeviceInfo("zte", "P963F03", "ZTE A7020", -3, -4, 3),
|
||||
DeviceInfo("zte", "P963F03", "ZTE A7020RU", -3, -4, 3),
|
||||
DeviceInfo("zte", "P932F20", "ZTE Blade A3 2019", -4, -4, 3),
|
||||
DeviceInfo("zte", "P932F50", "ZTE Blade A3 2020", -4, -7, 3),
|
||||
DeviceInfo("zte", "P932K30", "ZTE Blade A3 2020", -5, -4, 3),
|
||||
DeviceInfo("zte", "P963F50", "ZTE Blade A5 2020", -3, -10, 3),
|
||||
DeviceInfo("zte", "P662F02", "ZTE Blade A7s", 2, -27, 3),
|
||||
DeviceInfo("zte", "P731K30", "ZTE Blade L130", -5, -5, 3),
|
||||
DeviceInfo("zte", "P731F50", "ZTE Blade L210", -4, -2, 3),
|
||||
DeviceInfo("zte", "P731F50", "ZTE Blade L210RU", -4, -5, 3),
|
||||
DeviceInfo("zte", "P671F20", "ZTE Blade V10", 7, -31, 3),
|
||||
DeviceInfo("zte", "P963F01", "ZTE Blade V10 Vita", -3, -10, 3)
|
||||
)
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,10 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2020, microG Project Team
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package org.microg.gms.nearby.exposurenotification
|
||||
|
||||
import androidx.core.content.FileProvider
|
||||
|
||||
class ExposureFileProvider : FileProvider()
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2020, microG Project Team
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package org.microg.gms.nearby.exposurenotification
|
||||
|
||||
import android.content.pm.PackageManager
|
||||
import android.os.Build.VERSION.SDK_INT
|
||||
import android.util.Log
|
||||
import com.google.android.gms.common.Feature
|
||||
import com.google.android.gms.common.internal.ConnectionInfo
|
||||
import com.google.android.gms.common.internal.GetServiceRequest
|
||||
import com.google.android.gms.common.internal.IGmsCallbacks
|
||||
import com.google.android.gms.nearby.exposurenotification.ExposureNotificationStatusCodes.*
|
||||
import org.microg.gms.BaseService
|
||||
import org.microg.gms.common.GmsService
|
||||
import org.microg.gms.common.PackageUtils
|
||||
|
||||
class ExposureNotificationService : BaseService(TAG, GmsService.NEARBY_EXPOSURE) {
|
||||
override fun handleServiceRequest(callback: IGmsCallbacks, request: GetServiceRequest, service: GmsService) {
|
||||
PackageUtils.getAndCheckCallingPackage(this, request.packageName)
|
||||
|
||||
fun checkPermission(permission: String): String? {
|
||||
if (checkCallingPermission(permission) != PackageManager.PERMISSION_GRANTED) {
|
||||
callback.onPostInitComplete(FAILED_UNAUTHORIZED, null, null)
|
||||
return null
|
||||
}
|
||||
return permission
|
||||
}
|
||||
|
||||
if (request.packageName != packageName) {
|
||||
checkPermission("android.permission.BLUETOOTH") ?: return
|
||||
}
|
||||
|
||||
if (SDK_INT < 21) {
|
||||
callback.onPostInitComplete(FAILED_NOT_SUPPORTED, null, null)
|
||||
return
|
||||
}
|
||||
|
||||
Log.d(TAG, "handleServiceRequest: " + request.packageName)
|
||||
callback.onPostInitCompleteWithConnectionInfo(SUCCESS, ExposureNotificationServiceImpl(this, lifecycle, request.packageName), ConnectionInfo().apply {
|
||||
// Note: this is just a list of all possible features as of 1.7.1-eap
|
||||
features = arrayOf(
|
||||
Feature("nearby_exposure_notification", 3),
|
||||
Feature("nearby_exposure_notification_1p", 1),
|
||||
Feature("nearby_exposure_notification_get_version", 1),
|
||||
Feature("nearby_exposure_notification_get_calibration_confidence", 1),
|
||||
Feature("nearby_exposure_notification_get_day_summaries", 1),
|
||||
Feature("nearby_exposure_notification_get_status", 1),
|
||||
Feature("nearby_exposure_notification_diagnosis_keys_data_mapping", 1),
|
||||
Feature("nearby_exposure_notification_diagnosis_key_file_supplier", 1),
|
||||
Feature("nearby_exposure_notification_package_configuration", 1),
|
||||
Feature("nearby_exposure_notification_preauthorize_key_release", 1)
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,802 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2020, microG Project Team
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package org.microg.gms.nearby.exposurenotification
|
||||
|
||||
import android.annotation.TargetApi
|
||||
import android.app.Activity
|
||||
import android.app.PendingIntent
|
||||
import android.bluetooth.BluetoothAdapter
|
||||
import android.content.ComponentName
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.location.LocationManager
|
||||
import android.os.*
|
||||
import android.util.Base64
|
||||
import android.util.Log
|
||||
import androidx.core.app.PendingIntentCompat
|
||||
import androidx.core.location.LocationManagerCompat
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.LifecycleCoroutineScope
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.google.android.gms.common.api.Status
|
||||
import com.google.android.gms.nearby.exposurenotification.*
|
||||
import com.google.android.gms.nearby.exposurenotification.ExposureNotificationClient.*
|
||||
import com.google.android.gms.nearby.exposurenotification.ExposureNotificationStatusCodes.*
|
||||
import com.google.android.gms.nearby.exposurenotification.TemporaryExposureKey.DAYS_SINCE_ONSET_OF_SYMPTOMS_UNKNOWN
|
||||
import com.google.android.gms.nearby.exposurenotification.internal.*
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.json.JSONArray
|
||||
import org.json.JSONObject
|
||||
import org.microg.gms.common.Constants
|
||||
import org.microg.gms.common.PackageUtils
|
||||
import org.microg.gms.nearby.exposurenotification.proto.TEKSignatureList
|
||||
import org.microg.gms.nearby.exposurenotification.proto.TemporaryExposureKeyExport
|
||||
import org.microg.gms.nearby.exposurenotification.proto.TemporaryExposureKeyProto
|
||||
import org.microg.gms.utils.warnOnTransactionIssues
|
||||
import java.io.File
|
||||
import java.io.InputStream
|
||||
import java.security.KeyFactory
|
||||
import java.security.MessageDigest
|
||||
import java.security.Signature
|
||||
import java.security.spec.X509EncodedKeySpec
|
||||
import java.util.zip.ZipEntry
|
||||
import java.util.zip.ZipFile
|
||||
import kotlin.math.max
|
||||
import kotlin.math.roundToInt
|
||||
import kotlin.random.Random
|
||||
|
||||
@TargetApi(21)
|
||||
class ExposureNotificationServiceImpl(private val context: Context, override val lifecycle: Lifecycle, private val packageName: String) : INearbyExposureNotificationService.Stub(), LifecycleOwner {
|
||||
|
||||
// Table of back-end public keys, used to verify the signature of the diagnosed TEKs.
|
||||
// The table is indexed by package names.
|
||||
private val backendPubKeyForPackage = mapOf<String, String>(
|
||||
"ch.admin.bag.dp3t.dev" to
|
||||
"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEsFcEnOPY4AOAKkpv9HSdW2BrhUCWwL15Hpqu5zHaWy1Wno2KR8G6dYJ8QO0uZu1M6j8z6NGXFVZcpw7tYeXAqQ==",
|
||||
"ch.admin.bag.dp3t.test" to
|
||||
"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEsFcEnOPY4AOAKkpv9HSdW2BrhUCWwL15Hpqu5zHaWy1Wno2KR8G6dYJ8QO0uZu1M6j8z6NGXFVZcpw7tYeXAqQ==",
|
||||
"ch.admin.bag.dp3t.abnahme" to
|
||||
"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEsFcEnOPY4AOAKkpv9HSdW2BrhUCWwL15Hpqu5zHaWy1Wno2KR8G6dYJ8QO0uZu1M6j8z6NGXFVZcpw7tYeXAqQ==",
|
||||
"ch.admin.bag.dp3t" to
|
||||
"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEK2k9nZ8guo7JP2ELPQXnUkqDyjjJmYmpt9Zy0HPsiGXCdI3SFmLr204KNzkuITppNV5P7+bXRxiiY04NMrEITg==",
|
||||
// CWA, see https://github.com/corona-warn-app/cwa-documentation/issues/740#issuecomment-963223074
|
||||
"de.rki.coronawarnapp" to
|
||||
"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEc7DEstcUIRcyk35OYDJ95/hTg3UVhsaDXKT0zK7NhHPXoyzipEnOp3GyNXDVpaPi3cAfQmxeuFMZAIX2+6A5Xg==",
|
||||
// CCTG uses CWA infrastucture
|
||||
"de.corona.tracing" to
|
||||
"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEc7DEstcUIRcyk35OYDJ95/hTg3UVhsaDXKT0zK7NhHPXoyzipEnOp3GyNXDVpaPi3cAfQmxeuFMZAIX2+6A5Xg==",
|
||||
// CCTG-Test builds don't have access any staging infrastructure, so again CWA key
|
||||
"de.corona.tracing.test" to
|
||||
"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEc7DEstcUIRcyk35OYDJ95/hTg3UVhsaDXKT0zK7NhHPXoyzipEnOp3GyNXDVpaPi3cAfQmxeuFMZAIX2+6A5Xg==",
|
||||
)
|
||||
|
||||
// Back-end public key for this package
|
||||
private val backendPublicKey = backendPubKeyForPackage[packageName]?.let {
|
||||
try {
|
||||
KeyFactory.getInstance("EC").generatePublic(X509EncodedKeySpec(Base64.decode(it, Base64.DEFAULT)))
|
||||
} catch (e: Exception) {
|
||||
Log.w(TAG, "Failed to retrieve back-end public key for ${packageName}: " + e.message)
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
// Table of supported signature algorithms for the diagnosed TEKs.
|
||||
// The table is indexed by ASN.1 OIDs as specified in https://tools.ietf.org/html/rfc5758#section-3.2
|
||||
private val sigAlgoForOid = mapOf<String, Function0<Signature>>(
|
||||
"1.2.840.10045.4.3.2" to { Signature.getInstance("SHA256withECDSA") },
|
||||
"1.2.840.10045.4.3.4" to { Signature.getInstance("SHA512withECDSA") },
|
||||
)
|
||||
|
||||
private fun LifecycleCoroutineScope.launchSafely(block: suspend CoroutineScope.() -> Unit): Job = launchWhenStarted { try { block() } catch (e: Exception) { Log.w(TAG, "Error in coroutine", e) } }
|
||||
|
||||
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, permission)
|
||||
intent.putExtra(KEY_CONFIRM_RECEIVER, object : ResultReceiver(null) {
|
||||
override fun onReceiveResult(resultCode: Int, resultData: Bundle?) {
|
||||
if (resultCode == Activity.RESULT_OK) {
|
||||
tempGrantedPermissions.add(packageName to permission)
|
||||
}
|
||||
}
|
||||
})
|
||||
try {
|
||||
intent.component = ComponentName(context, context.packageManager.resolveActivity(intent, 0)?.activityInfo?.name!!)
|
||||
} catch (e: Exception) {
|
||||
Log.w(TAG, e)
|
||||
}
|
||||
Log.d(TAG, "Pending: $intent")
|
||||
val pi = PendingIntentCompat.getActivity(context, permission.hashCode(), intent, PendingIntent.FLAG_ONE_SHOT, false)!!
|
||||
Log.d(TAG, "Pending: $pi")
|
||||
return pi
|
||||
}
|
||||
|
||||
private fun hasConfirmActivity(): Boolean {
|
||||
val intent = Intent(ACTION_CONFIRM)
|
||||
intent.`package` = context.packageName
|
||||
return try {
|
||||
context.packageManager.resolveActivity(intent, 0) != null
|
||||
} catch (e: Exception) {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun confirmPermission(permission: String, force: Boolean = false): Status {
|
||||
return ExposureDatabase.with(context) { database ->
|
||||
when {
|
||||
tempGrantedPermissions.contains(packageName to permission) -> {
|
||||
database.grantPermission(packageName, PackageUtils.firstSignatureDigest(context, packageName)!!, permission)
|
||||
tempGrantedPermissions.remove(packageName to permission)
|
||||
Status.SUCCESS
|
||||
}
|
||||
!force && database.hasPermission(packageName, PackageUtils.firstSignatureDigest(context, packageName)!!, permission) -> {
|
||||
Status.SUCCESS
|
||||
}
|
||||
!hasConfirmActivity() -> {
|
||||
Status.SUCCESS
|
||||
}
|
||||
else -> {
|
||||
Status(RESOLUTION_REQUIRED, "Permission EN#$permission required.", pendingConfirm(permission))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getVersion(params: GetVersionParams) {
|
||||
params.callback.onResult(Status.SUCCESS, VERSION_FULL)
|
||||
}
|
||||
|
||||
override fun getCalibrationConfidence(params: GetCalibrationConfidenceParams) {
|
||||
params.callback.onResult(Status.SUCCESS, currentDeviceInfo.confidence)
|
||||
}
|
||||
|
||||
override fun start(params: StartParams) {
|
||||
lifecycleScope.launchSafely {
|
||||
val isAuthorized = ExposureDatabase.with(context) { it.isAppAuthorized(packageName) }
|
||||
val adapter = BluetoothAdapter.getDefaultAdapter()
|
||||
val status = if (isAuthorized && ExposurePreferences(context).enabled) {
|
||||
Status.SUCCESS
|
||||
} else if (adapter == null) {
|
||||
Status(FAILED_NOT_SUPPORTED, "No Bluetooth Adapter available.")
|
||||
} else {
|
||||
val status = confirmPermission(CONFIRM_ACTION_START, !adapter.isEnabled)
|
||||
if (status.isSuccess) {
|
||||
val context = context
|
||||
adapter.enableAsync(context)
|
||||
ExposurePreferences(context).enabled = true
|
||||
ExposureDatabase.with(context) { database ->
|
||||
database.authorizeApp(packageName)
|
||||
database.noteAppAction(packageName, "start")
|
||||
}
|
||||
}
|
||||
status
|
||||
}
|
||||
try {
|
||||
params.callback.onResult(status)
|
||||
} catch (e: Exception) {
|
||||
Log.w(TAG, "Callback failed", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun stop(params: StopParams) {
|
||||
lifecycleScope.launchSafely {
|
||||
val isAuthorized = ExposureDatabase.with(context) { database ->
|
||||
database.isAppAuthorized(packageName).also {
|
||||
if (it) database.noteAppAction(packageName, "stop")
|
||||
}
|
||||
}
|
||||
if (isAuthorized) {
|
||||
ExposurePreferences(context).enabled = false
|
||||
}
|
||||
try {
|
||||
params.callback.onResult(Status.SUCCESS)
|
||||
} catch (e: Exception) {
|
||||
Log.w(TAG, "Callback failed", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun isEnabled(params: IsEnabledParams) {
|
||||
lifecycleScope.launchSafely {
|
||||
val isAuthorized = ExposureDatabase.with(context) { database ->
|
||||
database.isAppAuthorized(packageName)
|
||||
}
|
||||
try {
|
||||
params.callback.onResult(Status.SUCCESS, isAuthorized && ExposurePreferences(context).enabled)
|
||||
} catch (e: Exception) {
|
||||
Log.w(TAG, "Callback failed", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getTemporaryExposureKeyHistory(params: GetTemporaryExposureKeyHistoryParams) {
|
||||
lifecycleScope.launchSafely {
|
||||
val status = confirmPermission(CONFIRM_ACTION_KEYS)
|
||||
val response = when {
|
||||
status.isSuccess -> ExposureDatabase.with(context) { database ->
|
||||
database.authorizeApp(packageName)
|
||||
database.exportKeys()
|
||||
}
|
||||
else -> emptyList()
|
||||
}
|
||||
|
||||
ExposureDatabase.with(context) { database ->
|
||||
database.noteAppAction(packageName, "getTemporaryExposureKeyHistory", JSONObject().apply {
|
||||
put("result", status.statusCode)
|
||||
put("response_keys_size", response.size)
|
||||
}.toString())
|
||||
}
|
||||
try {
|
||||
params.callback.onResult(status, response)
|
||||
} catch (e: Exception) {
|
||||
Log.w(TAG, "Callback failed", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun TemporaryExposureKeyProto.toKey(): TemporaryExposureKey = TemporaryExposureKey.TemporaryExposureKeyBuilder()
|
||||
.setKeyData(key_data?.toByteArray() ?: throw IllegalArgumentException("key data missing"))
|
||||
.setRollingStartIntervalNumber(rolling_start_interval_number
|
||||
?: throw IllegalArgumentException("rolling start interval number missing"))
|
||||
.setRollingPeriod(rolling_period ?: throw IllegalArgumentException("rolling period missing"))
|
||||
.setTransmissionRiskLevel(transmission_risk_level ?: 0)
|
||||
.build()
|
||||
|
||||
private fun InputStream.copyToFile(outputFile: File) {
|
||||
outputFile.outputStream().use { output ->
|
||||
copyTo(output)
|
||||
output.flush()
|
||||
}
|
||||
}
|
||||
|
||||
private fun MessageDigest.digest(file: File): ByteArray = file.inputStream().use { input ->
|
||||
val buf = ByteArray(4096)
|
||||
var bytes = input.read(buf)
|
||||
while (bytes != -1) {
|
||||
update(buf, 0, bytes)
|
||||
bytes = input.read(buf)
|
||||
}
|
||||
digest()
|
||||
}
|
||||
|
||||
private fun ExposureConfiguration?.orDefault() = this
|
||||
?: ExposureConfiguration.ExposureConfigurationBuilder().build()
|
||||
|
||||
private suspend fun buildExposureSummary(token: String): ExposureSummary = ExposureDatabase.with(context) { database ->
|
||||
if (!database.isAppAuthorized(packageName)) {
|
||||
// Not providing summary if app not authorized
|
||||
Log.d(TAG, "$packageName not yet authorized")
|
||||
return@with ExposureSummary.ExposureSummaryBuilder().build()
|
||||
}
|
||||
val pair = database.loadConfiguration(packageName, token)
|
||||
val (configuration, exposures) = if (pair != null) {
|
||||
pair.second.orDefault() to database.findAllMeasuredExposures(pair.first).merge()
|
||||
} else {
|
||||
ExposureConfiguration.ExposureConfigurationBuilder().build() to emptyList()
|
||||
}
|
||||
|
||||
ExposureSummary.ExposureSummaryBuilder()
|
||||
.setDaysSinceLastExposure(exposures.map { it.daysSinceExposure }.minOrNull()?.toInt() ?: 0)
|
||||
.setMatchedKeyCount(exposures.map { it.key }.distinct().size)
|
||||
.setMaximumRiskScore(exposures.map { it.getRiskScore(configuration) }.maxOrNull()?.toInt() ?: 0)
|
||||
.setAttenuationDurations(intArrayOf(
|
||||
exposures.map { it.getAttenuationDurations(configuration)[0] }.sum(),
|
||||
exposures.map { it.getAttenuationDurations(configuration)[1] }.sum(),
|
||||
exposures.map { it.getAttenuationDurations(configuration)[2] }.sum()
|
||||
))
|
||||
.setSummationRiskScore(exposures.map { it.getRiskScore(configuration) }.sum())
|
||||
.build()
|
||||
}
|
||||
|
||||
override fun provideDiagnosisKeys(params: ProvideDiagnosisKeysParams) {
|
||||
val token = params.token ?: TOKEN_A
|
||||
Log.w(TAG, "provideDiagnosisKeys() with $packageName/$token")
|
||||
lifecycleScope.launchSafely {
|
||||
val tid = ExposureDatabase.with(context) { database ->
|
||||
val configuration = params.configuration
|
||||
if (configuration != null) {
|
||||
database.storeConfiguration(packageName, token, configuration)
|
||||
} else {
|
||||
database.getOrCreateTokenId(packageName, token)
|
||||
}
|
||||
}
|
||||
if (tid == null) {
|
||||
Log.w(TAG, "Unknown token without configuration: $packageName/$token")
|
||||
try {
|
||||
params.callback.onResult(Status.INTERNAL_ERROR)
|
||||
} catch (e: Exception) {
|
||||
Log.w(TAG, "Callback failed", e)
|
||||
}
|
||||
return@launchSafely
|
||||
}
|
||||
ExposureDatabase.with(context) { database ->
|
||||
val start = System.currentTimeMillis()
|
||||
|
||||
// keys
|
||||
params.keys?.let { database.batchStoreSingleDiagnosisKey(tid, it) }
|
||||
|
||||
var keys = params.keys?.size ?: 0
|
||||
|
||||
// Key files
|
||||
val todoKeyFiles = arrayListOf<Pair<File, ByteArray>>()
|
||||
for (file in params.keyFiles.orEmpty()) {
|
||||
try {
|
||||
val cacheFile = File(context.cacheDir, "en-keyfile-${System.currentTimeMillis()}-${Random.nextInt()}.zip")
|
||||
ParcelFileDescriptor.AutoCloseInputStream(file).use { it.copyToFile(cacheFile) }
|
||||
val hash = MessageDigest.getInstance("SHA-256").digest(cacheFile)
|
||||
val storedKeys = database.storeDiagnosisFileUsed(tid, hash)
|
||||
if (storedKeys != null) {
|
||||
keys += storedKeys.toInt()
|
||||
cacheFile.delete()
|
||||
} else {
|
||||
todoKeyFiles.add(cacheFile to hash)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.w(TAG, "Failed parsing file", e)
|
||||
}
|
||||
}
|
||||
params.keyFileSupplier?.let { keyFileSupplier ->
|
||||
Log.d(TAG, "Using key file supplier")
|
||||
try {
|
||||
while (keyFileSupplier.isAvailable && keyFileSupplier.hasNext()) {
|
||||
withContext(Dispatchers.IO) {
|
||||
try {
|
||||
val cacheFile = File(context.cacheDir, "en-keyfile-${System.currentTimeMillis()}-${Random.nextLong()}.zip")
|
||||
ParcelFileDescriptor.AutoCloseInputStream(keyFileSupplier.next()).use { it.copyToFile(cacheFile) }
|
||||
val hash = MessageDigest.getInstance("SHA-256").digest(cacheFile)
|
||||
val storedKeys = database.storeDiagnosisFileUsed(tid, hash)
|
||||
if (storedKeys != null) {
|
||||
keys += storedKeys.toInt()
|
||||
cacheFile.delete()
|
||||
} else {
|
||||
todoKeyFiles.add(cacheFile to hash)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.w(TAG, "Failed parsing file", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.w(TAG, "Disconnected from key file supplier", e)
|
||||
}
|
||||
}
|
||||
|
||||
if (todoKeyFiles.size > 0) {
|
||||
val time = (System.currentTimeMillis() - start).coerceAtLeast(1).toDouble() / 1000.0
|
||||
Log.d(TAG, "$packageName/$token processed $keys keys (${todoKeyFiles.size} files pending) in ${time}s -> ${(keys.toDouble() / time * 1000).roundToInt().toDouble() / 1000.0} keys/s")
|
||||
}
|
||||
|
||||
Handler(Looper.getMainLooper()).post {
|
||||
try {
|
||||
params.callback.onResult(Status.SUCCESS)
|
||||
} catch (e: Exception) {
|
||||
Log.w(TAG, "Callback failed", e)
|
||||
}
|
||||
}
|
||||
|
||||
var newKeys = if (params.keys != null) database.finishSingleMatching(tid) else 0
|
||||
for ((cacheFile, hash) in todoKeyFiles) {
|
||||
withContext(Dispatchers.IO) {
|
||||
if (backendPublicKey != null && !verifyKeyFile(cacheFile)) {
|
||||
Log.w(TAG, "Skipping non-verified key file")
|
||||
return@withContext
|
||||
}
|
||||
try {
|
||||
ZipFile(cacheFile).use { zip ->
|
||||
for (entry in zip.entries()) {
|
||||
if (entry.name == "export.bin") {
|
||||
val stream = zip.getInputStream(entry)
|
||||
val prefix = ByteArray(16)
|
||||
var totalBytesRead = 0
|
||||
var bytesRead = 0
|
||||
while (bytesRead != -1 && totalBytesRead < prefix.size) {
|
||||
bytesRead = stream.read(prefix, totalBytesRead, prefix.size - totalBytesRead)
|
||||
if (bytesRead > 0) {
|
||||
totalBytesRead += bytesRead
|
||||
}
|
||||
}
|
||||
if (totalBytesRead == prefix.size && String(prefix).trim() == "EK Export v1") {
|
||||
val export = TemporaryExposureKeyExport.ADAPTER.decode(stream)
|
||||
database.finishFileMatching(tid, hash, export.end_timestamp?.let { it * 1000 }
|
||||
?: System.currentTimeMillis(), export.keys.map { it.toKey() }, export.revised_keys.map { it.toKey() })
|
||||
keys += export.keys.size + export.revised_keys.size
|
||||
newKeys += export.keys.size
|
||||
} else {
|
||||
Log.d(TAG, "export.bin had invalid prefix")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
cacheFile.delete()
|
||||
} catch (e: Exception) {
|
||||
Log.w(TAG, "Failed parsing file", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val time = (System.currentTimeMillis() - start).coerceAtLeast(1).toDouble() / 1000.0
|
||||
Log.d(TAG, "$packageName/$token processed $keys keys ($newKeys new) in ${time}s -> ${(keys.toDouble() / time * 1000).roundToInt().toDouble() / 1000.0} keys/s")
|
||||
|
||||
database.noteAppAction(packageName, "provideDiagnosisKeys", JSONObject().apply {
|
||||
put("request_token", token)
|
||||
put("request_keys_size", params.keys?.size)
|
||||
put("request_keyFiles_size", params.keyFiles?.size)
|
||||
put("request_keys_count", keys)
|
||||
}.toString())
|
||||
|
||||
if (!database.isAppAuthorized(packageName)) {
|
||||
// Not sending results via broadcast if app not authorized
|
||||
Log.d(TAG, "$packageName not yet authorized")
|
||||
return@with
|
||||
}
|
||||
|
||||
val exposureSummary = buildExposureSummary(token)
|
||||
|
||||
try {
|
||||
val intent = if (exposureSummary.matchedKeyCount > 0) {
|
||||
Intent(ACTION_EXPOSURE_STATE_UPDATED)
|
||||
} else {
|
||||
Intent(ACTION_EXPOSURE_NOT_FOUND)
|
||||
}
|
||||
if (token != TOKEN_A) {
|
||||
intent.putExtra(EXTRA_EXPOSURE_SUMMARY, exposureSummary)
|
||||
}
|
||||
intent.putExtra(EXTRA_TOKEN, token)
|
||||
intent.`package` = packageName
|
||||
Log.d(TAG, "Sending $intent")
|
||||
context.sendOrderedBroadcast(intent, null)
|
||||
} catch (e: Exception) {
|
||||
Log.w(TAG, "Callback failed", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun verifyKeyFile(file: File): Boolean {
|
||||
try {
|
||||
ZipFile(file).use { zip ->
|
||||
var dataEntry: ZipEntry? = null
|
||||
var sigEntry: ZipEntry? = null
|
||||
|
||||
for (entry in zip.entries()) {
|
||||
when (entry.name) {
|
||||
"export.bin" ->
|
||||
if (dataEntry != null) {
|
||||
throw Exception("Zip archive contains more than one 'export.bin' entry")
|
||||
} else {
|
||||
dataEntry = entry
|
||||
}
|
||||
"export.sig" ->
|
||||
if (sigEntry != null) {
|
||||
throw Exception("Zip archive contains more than one 'export.sig' entry")
|
||||
} else {
|
||||
sigEntry = entry
|
||||
}
|
||||
else -> throw Exception("Unexpected entry in zip archive: ${entry.name}")
|
||||
}
|
||||
}
|
||||
when {
|
||||
dataEntry == null -> throw Exception("Zip archive does not contain 'export.bin'")
|
||||
sigEntry == null -> throw Exception("Zip archive does not contain 'export.sin'")
|
||||
}
|
||||
|
||||
val sigStream = zip.getInputStream(sigEntry)
|
||||
val sigList = TEKSignatureList.ADAPTER.decode(sigStream)
|
||||
|
||||
for (sig in sigList.signatures) {
|
||||
Log.d(TAG, "Verifying signature ${sig.batch_num}/${sig.batch_size}")
|
||||
val sigInfo = sig.signature_info ?: throw Exception("Signature information is missing")
|
||||
Log.d(TAG, "Signature info: algo=${sigInfo.signature_algorithm} key={id=${sigInfo.verification_key_id}, version=${sigInfo.verification_key_version}}")
|
||||
|
||||
val signature = sig.signature?.toByteArray() ?: throw Exception("Signature contents is missing")
|
||||
val sigVerifier = (sigAlgoForOid.get(sigInfo.signature_algorithm) ?: throw Exception("Signature algorithm not supported: ${sigInfo.signature_algorithm}"))()
|
||||
sigVerifier.initVerify(backendPublicKey)
|
||||
|
||||
val stream = zip.getInputStream(dataEntry)
|
||||
val buf = ByteArray(1024)
|
||||
var nbRead = 0
|
||||
while (nbRead != -1) {
|
||||
nbRead = stream.read(buf)
|
||||
if (nbRead > 0) {
|
||||
sigVerifier.update(buf, 0, nbRead)
|
||||
}
|
||||
}
|
||||
|
||||
if (!sigVerifier.verify(signature)) {
|
||||
throw Exception("Signature does not verify")
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.w(TAG, "Key file verification failed: " + e.message)
|
||||
return false
|
||||
}
|
||||
|
||||
Log.i(TAG, "Key file verification successful")
|
||||
return true
|
||||
}
|
||||
|
||||
override fun getExposureSummary(params: GetExposureSummaryParams) {
|
||||
lifecycleScope.launchSafely {
|
||||
val response = buildExposureSummary(params.token)
|
||||
|
||||
ExposureDatabase.with(context) { database ->
|
||||
database.noteAppAction(packageName, "getExposureSummary", JSONObject().apply {
|
||||
put("request_token", params.token)
|
||||
put("response_days_since", response.daysSinceLastExposure)
|
||||
put("response_matched_keys", response.matchedKeyCount)
|
||||
put("response_max_risk", response.maximumRiskScore)
|
||||
put("response_attenuation_durations", JSONArray().apply {
|
||||
response.attenuationDurationsInMinutes.forEach { put(it) }
|
||||
})
|
||||
put("response_summation_risk", response.summationRiskScore)
|
||||
}.toString())
|
||||
}
|
||||
try {
|
||||
params.callback.onResult(Status.SUCCESS, response)
|
||||
} catch (e: Exception) {
|
||||
Log.w(TAG, "Callback failed", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getExposureInformation(params: GetExposureInformationParams) {
|
||||
lifecycleScope.launchSafely {
|
||||
ExposureDatabase.with(context) { database ->
|
||||
val pair = database.loadConfiguration(packageName, params.token)
|
||||
val response = if (pair != null && database.isAppAuthorized(packageName)) {
|
||||
database.findAllMeasuredExposures(pair.first).merge().map {
|
||||
it.toExposureInformation(pair.second.orDefault())
|
||||
}
|
||||
} else {
|
||||
// Not providing information if app not authorized
|
||||
Log.d(TAG, "$packageName not yet authorized")
|
||||
emptyList()
|
||||
}
|
||||
|
||||
database.noteAppAction(packageName, "getExposureInformation", JSONObject().apply {
|
||||
put("request_token", params.token)
|
||||
put("response_size", response.size)
|
||||
}.toString())
|
||||
try {
|
||||
params.callback.onResult(Status.SUCCESS, response)
|
||||
} catch (e: Exception) {
|
||||
Log.w(TAG, "Callback failed", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun ScanInstance.Builder.apply(subExposure: MergedSubExposure): ScanInstance.Builder {
|
||||
return this
|
||||
.setSecondsSinceLastScan(subExposure.duration.coerceAtMost(5 * 60).toInt())
|
||||
.setMinAttenuationDb(subExposure.attenuation) // FIXME: We use the average for both, because we don't store the minimum attenuation yet
|
||||
.setTypicalAttenuationDb(subExposure.attenuation)
|
||||
}
|
||||
|
||||
private fun List<MergedSubExposure>.toScanInstances(): List<ScanInstance> {
|
||||
val res = arrayListOf<ScanInstance>()
|
||||
for (subExposure in this) {
|
||||
res.add(ScanInstance.Builder().apply(subExposure).build())
|
||||
if (subExposure.duration > 5 * 60 * 1000L) {
|
||||
res.add(ScanInstance.Builder().apply(subExposure).setSecondsSinceLastScan((subExposure.duration - 5 * 60).coerceAtMost(5 * 60).toInt()).build())
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
private fun DiagnosisKeysDataMapping?.orDefault() = this ?: DiagnosisKeysDataMapping()
|
||||
|
||||
private suspend fun getExposureWindowsInternal(token: String = TOKEN_A): List<ExposureWindow> {
|
||||
val (exposures, mapping) = ExposureDatabase.with(context) { database ->
|
||||
val triple = database.loadConfiguration(packageName, token)
|
||||
if (triple != null && database.isAppAuthorized(packageName)) {
|
||||
database.findAllMeasuredExposures(triple.first).merge() to triple.third.orDefault()
|
||||
} else {
|
||||
// Not providing windows if app not authorized
|
||||
Log.d(TAG, "$packageName not yet authorized")
|
||||
emptyList<MergedExposure>() to DiagnosisKeysDataMapping()
|
||||
}
|
||||
}
|
||||
return exposures.map {
|
||||
val infectiousness =
|
||||
if (it.key.daysSinceOnsetOfSymptoms == DAYS_SINCE_ONSET_OF_SYMPTOMS_UNKNOWN)
|
||||
mapping.infectiousnessWhenDaysSinceOnsetMissing
|
||||
else
|
||||
mapping.daysSinceOnsetToInfectiousness[it.key.daysSinceOnsetOfSymptoms]
|
||||
?: Infectiousness.NONE
|
||||
val reportType =
|
||||
if (it.key.reportType == ReportType.UNKNOWN)
|
||||
mapping.reportTypeWhenMissing
|
||||
else
|
||||
it.key.reportType
|
||||
|
||||
ExposureWindow.Builder()
|
||||
.setCalibrationConfidence(it.confidence)
|
||||
.setDateMillisSinceEpoch(it.key.rollingStartIntervalNumber.toLong() * ROLLING_WINDOW_LENGTH_MS)
|
||||
.setInfectiousness(infectiousness)
|
||||
.setReportType(reportType)
|
||||
.setScanInstances(it.subs.toScanInstances())
|
||||
.build()
|
||||
}
|
||||
}
|
||||
|
||||
override fun getExposureWindows(params: GetExposureWindowsParams) {
|
||||
lifecycleScope.launchSafely {
|
||||
val response = getExposureWindowsInternal(params.token ?: TOKEN_A)
|
||||
|
||||
ExposureDatabase.with(context) { database ->
|
||||
database.noteAppAction(packageName, "getExposureWindows", JSONObject().apply {
|
||||
put("request_token", params.token)
|
||||
put("response_size", response.size)
|
||||
}.toString())
|
||||
}
|
||||
|
||||
try {
|
||||
params.callback.onResult(Status.SUCCESS, response)
|
||||
} catch (e: Exception) {
|
||||
Log.w(TAG, "Callback failed", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun DailySummariesConfig.bucketFor(attenuation: Int): Int {
|
||||
if (attenuation < attenuationBucketThresholdDb[0]) return 0
|
||||
if (attenuation < attenuationBucketThresholdDb[1]) return 1
|
||||
if (attenuation < attenuationBucketThresholdDb[2]) return 2
|
||||
return 3
|
||||
}
|
||||
|
||||
private fun DailySummariesConfig.weightedDurationFor(attenuation: Int, seconds: Int): Double {
|
||||
return attenuationBucketWeights[bucketFor(attenuation)] * seconds
|
||||
}
|
||||
|
||||
private fun Collection<DailySummary.ExposureSummaryData>.sum(): DailySummary.ExposureSummaryData {
|
||||
return DailySummary.ExposureSummaryData(map { it.maximumScore }.maxOrNull()
|
||||
?: 0.0, sumByDouble { it.scoreSum }, sumByDouble { it.weightedDurationSum })
|
||||
}
|
||||
|
||||
override fun getDailySummaries(params: GetDailySummariesParams) {
|
||||
lifecycleScope.launchSafely {
|
||||
val response = getExposureWindowsInternal().groupBy { it.dateMillisSinceEpoch }.map {
|
||||
val map = arrayListOf<DailySummary.ExposureSummaryData>()
|
||||
for (i in 0 until ReportType.VALUES) {
|
||||
map[i] = DailySummary.ExposureSummaryData(0.0, 0.0, 0.0)
|
||||
}
|
||||
for (entry in it.value.groupBy { it.reportType }) {
|
||||
for (window in entry.value) {
|
||||
val weightedDuration = window.scanInstances.map { params.config.weightedDurationFor(it.typicalAttenuationDb, it.secondsSinceLastScan) }.sum()
|
||||
val score = (params.config.reportTypeWeights[window.reportType] ?: 1.0) *
|
||||
(params.config.infectiousnessWeights[window.infectiousness] ?: 1.0) *
|
||||
weightedDuration
|
||||
if (score >= params.config.minimumWindowScore) {
|
||||
map[entry.key] = DailySummary.ExposureSummaryData(max(map[entry.key].maximumScore, score), map[entry.key].scoreSum + score, map[entry.key].weightedDurationSum + weightedDuration)
|
||||
}
|
||||
}
|
||||
}
|
||||
DailySummary((it.key / (1000L * 60 * 60 * 24)).toInt(), map, map.sum())
|
||||
}
|
||||
|
||||
ExposureDatabase.with(context) { database ->
|
||||
database.noteAppAction(packageName, "getDailySummaries", JSONObject().apply {
|
||||
put("response_size", response.size)
|
||||
}.toString())
|
||||
}
|
||||
|
||||
try {
|
||||
params.callback.onResult(Status.SUCCESS, response)
|
||||
} catch (e: Exception) {
|
||||
Log.w(TAG, "Callback failed", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun setDiagnosisKeysDataMapping(params: SetDiagnosisKeysDataMappingParams) {
|
||||
lifecycleScope.launchSafely {
|
||||
ExposureDatabase.with(context) { database ->
|
||||
database.storeConfiguration(packageName, TOKEN_A, params.mapping)
|
||||
database.noteAppAction(packageName, "setDiagnosisKeysDataMapping")
|
||||
}
|
||||
try {
|
||||
params.callback.onResult(Status.SUCCESS)
|
||||
} catch (e: Exception) {
|
||||
Log.w(TAG, "Callback failed", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getDiagnosisKeysDataMapping(params: GetDiagnosisKeysDataMappingParams) {
|
||||
lifecycleScope.launchSafely {
|
||||
val mapping = ExposureDatabase.with(context) { database ->
|
||||
val triple = database.loadConfiguration(packageName, TOKEN_A)
|
||||
database.noteAppAction(packageName, "getDiagnosisKeysDataMapping")
|
||||
triple?.third
|
||||
}
|
||||
try {
|
||||
params.callback.onResult(Status.SUCCESS, mapping.orDefault())
|
||||
} catch (e: Exception) {
|
||||
Log.w(TAG, "Callback failed", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getPackageConfiguration(params: GetPackageConfigurationParams) {
|
||||
Log.w(TAG, "Not yet implemented: getPackageConfiguration")
|
||||
lifecycleScope.launchSafely {
|
||||
ExposureDatabase.with(context) { database ->
|
||||
database.noteAppAction(packageName, "getPackageConfiguration")
|
||||
}
|
||||
try {
|
||||
params.callback.onResult(Status.SUCCESS, PackageConfiguration.PackageConfigurationBuilder().setValues(Bundle.EMPTY).build())
|
||||
} catch (e: Exception) {
|
||||
Log.w(TAG, "Callback failed", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getStatus(params: GetStatusParams) {
|
||||
lifecycleScope.launchSafely {
|
||||
val isAuthorized = ExposureDatabase.with(context) { database ->
|
||||
database.noteAppAction(packageName, "getStatus")
|
||||
database.isAppAuthorized(packageName)
|
||||
}
|
||||
val flags = hashSetOf<ExposureNotificationStatus>()
|
||||
val adapter = BluetoothAdapter.getDefaultAdapter()
|
||||
if (adapter == null || !adapter.isEnabled) {
|
||||
flags.add(ExposureNotificationStatus.BLUETOOTH_DISABLED)
|
||||
flags.add(ExposureNotificationStatus.BLUETOOTH_SUPPORT_UNKNOWN)
|
||||
} else if (Build.VERSION.SDK_INT < 21) {
|
||||
flags.add(ExposureNotificationStatus.EN_NOT_SUPPORT)
|
||||
} else if (adapter.bluetoothLeScanner == null){
|
||||
flags.add(ExposureNotificationStatus.HW_NOT_SUPPORT)
|
||||
}
|
||||
if (!LocationManagerCompat.isLocationEnabled(context.getSystemService(Context.LOCATION_SERVICE) as LocationManager)) {
|
||||
flags.add(ExposureNotificationStatus.LOCATION_DISABLED)
|
||||
}
|
||||
if (!isAuthorized) {
|
||||
flags.add(ExposureNotificationStatus.NO_CONSENT)
|
||||
}
|
||||
if (isAuthorized && ExposurePreferences(context).enabled) {
|
||||
flags.add(ExposureNotificationStatus.ACTIVATED)
|
||||
} else {
|
||||
flags.add(ExposureNotificationStatus.INACTIVATED)
|
||||
}
|
||||
try {
|
||||
params.callback.onResult(Status.SUCCESS, ExposureNotificationStatus.setToFlags(flags))
|
||||
} catch (e: Exception) {
|
||||
Log.w(TAG, "Callback failed", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun requestPreAuthorizedTemporaryExposureKeyHistory(params: RequestPreAuthorizedTemporaryExposureKeyHistoryParams) {
|
||||
// TODO: Proper implementation
|
||||
lifecycleScope.launchSafely {
|
||||
params.callback.onResult(Status.CANCELED)
|
||||
}
|
||||
}
|
||||
|
||||
override fun requestPreAuthorizedTemporaryExposureKeyRelease(params: RequestPreAuthorizedTemporaryExposureKeyReleaseParams) {
|
||||
// TODO: Proper implementation
|
||||
lifecycleScope.launchSafely {
|
||||
params.callback.onResult(Status(FAILED_KEY_RELEASE_NOT_PREAUTHORIZED))
|
||||
}
|
||||
}
|
||||
|
||||
override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean = warnOnTransactionIssues(code, reply, flags, TAG) { super.onTransact(code, data, reply, flags) }
|
||||
|
||||
companion object {
|
||||
private val tempGrantedPermissions: MutableSet<Pair<String, String>> = hashSetOf()
|
||||
private const val VERSION = 18
|
||||
private const val VERSION_FULL = VERSION.toLong() * 1000000000L + Constants.GMS_VERSION_CODE
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2020, microG Project Team
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package org.microg.gms.nearby.exposurenotification
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import org.microg.gms.settings.SettingsContract.Exposure.getContentUri
|
||||
import org.microg.gms.settings.SettingsContract.Exposure.LAST_CLEANUP
|
||||
import org.microg.gms.settings.SettingsContract.Exposure.SCANNER_ENABLED
|
||||
import org.microg.gms.settings.SettingsContract.getSettings
|
||||
import org.microg.gms.settings.SettingsContract.setSettings
|
||||
|
||||
class ExposurePreferences(private val context: Context) {
|
||||
|
||||
var enabled
|
||||
get() = getSettings(context, getContentUri(context), arrayOf(SCANNER_ENABLED)) { c ->
|
||||
c.getInt(0) != 0
|
||||
}
|
||||
set(newStatus) {
|
||||
val changed = enabled != newStatus
|
||||
setSettings(context, getContentUri(context)) {
|
||||
put(SCANNER_ENABLED, newStatus)
|
||||
}
|
||||
if (!changed) return
|
||||
if (newStatus) {
|
||||
context.sendOrderedBroadcast(Intent(context, ServiceTrigger::class.java), null)
|
||||
} else {
|
||||
context.stopService(Intent(context, ScannerService::class.java))
|
||||
context.stopService(Intent(context, AdvertiserService::class.java))
|
||||
}
|
||||
}
|
||||
|
||||
var lastCleanup
|
||||
get() = getSettings(context, getContentUri(context), arrayOf(LAST_CLEANUP)) { c ->
|
||||
c.getLong(0)
|
||||
}
|
||||
set(value) = setSettings(context, getContentUri(context)) {
|
||||
put(LAST_CLEANUP, value)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2020, microG Project Team
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package org.microg.gms.nearby.exposurenotification
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.bluetooth.BluetoothAdapter
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.util.Log
|
||||
import kotlinx.coroutines.CompletableDeferred
|
||||
import kotlinx.coroutines.withTimeout
|
||||
|
||||
@SuppressLint("MissingPermission")
|
||||
suspend fun BluetoothAdapter.enableAsync(context: Context): Boolean {
|
||||
val deferred = CompletableDeferred<Unit>()
|
||||
val receiver: BroadcastReceiver = object : BroadcastReceiver() {
|
||||
override fun onReceive(receiverContext: Context?, intent: Intent?) {
|
||||
if (intent?.action == BluetoothAdapter.ACTION_STATE_CHANGED) {
|
||||
val state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR)
|
||||
if (state == BluetoothAdapter.STATE_ON) deferred.complete(Unit)
|
||||
}
|
||||
}
|
||||
}
|
||||
context.registerReceiver(receiver, IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED))
|
||||
if (!isEnabled) {
|
||||
try {
|
||||
enable()
|
||||
withTimeout(5000) { deferred.await() }
|
||||
} catch (e: Exception) {
|
||||
Log.w(TAG, "Failed enabling Bluetooth")
|
||||
}
|
||||
}
|
||||
context.unregisterReceiver(receiver)
|
||||
return isEnabled
|
||||
}
|
||||
|
|
@ -0,0 +1,146 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2020, microG Project Team
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package org.microg.gms.nearby.exposurenotification
|
||||
|
||||
import android.util.Log
|
||||
import com.google.android.gms.nearby.exposurenotification.*
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
data class ExposureScanSummary(val time: Long, val rpis: Int, val records: Int)
|
||||
|
||||
data class PlainExposure(val rpi: ByteArray, val aem: ByteArray, val timestamp: Long, val duration: Long, val rssi: Int)
|
||||
|
||||
data class MeasuredExposure(val timestamp: Long, val duration: Long, val rssi: Int, val txPower: Int, @CalibrationConfidence val confidence: Int, val key: TemporaryExposureKey) {
|
||||
val attenuation
|
||||
get() = txPower - (rssi + currentDeviceInfo.rssiCorrection)
|
||||
}
|
||||
|
||||
fun List<MeasuredExposure>.merge(): List<MergedExposure> {
|
||||
val keys = map { it.key }.distinct()
|
||||
val result = arrayListOf<MergedExposure>()
|
||||
for (key in keys) {
|
||||
var merged: MergedExposure? = null
|
||||
for (exposure in filter { it.key == key }.distinctBy { it.timestamp }.sortedBy { it.timestamp }) {
|
||||
if (merged != null && merged.timestamp + MergedExposure.MAXIMUM_DURATION > exposure.timestamp) {
|
||||
merged += exposure
|
||||
} else {
|
||||
if (merged != null) {
|
||||
result.add(merged)
|
||||
}
|
||||
merged = MergedExposure(key, exposure.timestamp, exposure.txPower, exposure.confidence, listOf(MergedSubExposure(exposure.attenuation, exposure.duration)))
|
||||
}
|
||||
if (merged.durationInMinutes >= 30) {
|
||||
result.add(merged)
|
||||
merged = null
|
||||
}
|
||||
}
|
||||
if (merged != null) {
|
||||
result.add(merged)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
data class MergedSubExposure(val attenuation: Int, val duration: Long)
|
||||
|
||||
data class MergedExposure internal constructor(val key: TemporaryExposureKey, val timestamp: Long, val txPower: Int, @CalibrationConfidence val confidence: Int, val subs: List<MergedSubExposure>) {
|
||||
@RiskLevel
|
||||
val transmissionRiskLevel: Int
|
||||
get() = key.transmissionRiskLevel
|
||||
|
||||
val durationInMinutes
|
||||
get() = TimeUnit.MILLISECONDS.toMinutes(subs.map { it.duration }.sum())
|
||||
|
||||
val daysSinceExposure
|
||||
get() = TimeUnit.MILLISECONDS.toDays(System.currentTimeMillis() - timestamp)
|
||||
|
||||
val attenuation
|
||||
get() = if (subs.map { it.duration }.sum() == 0L) subs[0].attenuation else (subs.map { it.attenuation * it.duration }.sum().toDouble() / subs.map { it.duration }.sum().toDouble()).toInt()
|
||||
|
||||
fun getAttenuationRiskScore(configuration: ExposureConfiguration): Int {
|
||||
return when {
|
||||
attenuation > 73 -> configuration.attenuationScores[0]
|
||||
attenuation > 63 -> configuration.attenuationScores[1]
|
||||
attenuation > 51 -> configuration.attenuationScores[2]
|
||||
attenuation > 33 -> configuration.attenuationScores[3]
|
||||
attenuation > 27 -> configuration.attenuationScores[4]
|
||||
attenuation > 15 -> configuration.attenuationScores[5]
|
||||
attenuation > 10 -> configuration.attenuationScores[6]
|
||||
else -> configuration.attenuationScores[7]
|
||||
}
|
||||
}
|
||||
|
||||
fun getDaysSinceLastExposureRiskScore(configuration: ExposureConfiguration): Int {
|
||||
return when {
|
||||
daysSinceExposure >= 14 -> configuration.daysSinceLastExposureScores[0]
|
||||
daysSinceExposure >= 12 -> configuration.daysSinceLastExposureScores[1]
|
||||
daysSinceExposure >= 10 -> configuration.daysSinceLastExposureScores[2]
|
||||
daysSinceExposure >= 8 -> configuration.daysSinceLastExposureScores[3]
|
||||
daysSinceExposure >= 6 -> configuration.daysSinceLastExposureScores[4]
|
||||
daysSinceExposure >= 4 -> configuration.daysSinceLastExposureScores[5]
|
||||
daysSinceExposure >= 2 -> configuration.daysSinceLastExposureScores[6]
|
||||
else -> configuration.daysSinceLastExposureScores[7]
|
||||
}
|
||||
}
|
||||
|
||||
fun getDurationRiskScore(configuration: ExposureConfiguration): Int {
|
||||
return when {
|
||||
durationInMinutes == 0L -> configuration.durationScores[0]
|
||||
durationInMinutes <= 5 -> configuration.durationScores[1]
|
||||
durationInMinutes <= 10 -> configuration.durationScores[2]
|
||||
durationInMinutes <= 15 -> configuration.durationScores[3]
|
||||
durationInMinutes <= 20 -> configuration.durationScores[4]
|
||||
durationInMinutes <= 25 -> configuration.durationScores[5]
|
||||
durationInMinutes <= 30 -> configuration.durationScores[6]
|
||||
else -> configuration.durationScores[7]
|
||||
}
|
||||
}
|
||||
|
||||
fun getTransmissionRiskScore(configuration: ExposureConfiguration): Int {
|
||||
return when (transmissionRiskLevel) {
|
||||
RiskLevel.RISK_LEVEL_LOWEST -> configuration.transmissionRiskScores[0]
|
||||
RiskLevel.RISK_LEVEL_LOW -> configuration.transmissionRiskScores[1]
|
||||
RiskLevel.RISK_LEVEL_LOW_MEDIUM -> configuration.transmissionRiskScores[2]
|
||||
RiskLevel.RISK_LEVEL_MEDIUM -> configuration.transmissionRiskScores[3]
|
||||
RiskLevel.RISK_LEVEL_MEDIUM_HIGH -> configuration.transmissionRiskScores[4]
|
||||
RiskLevel.RISK_LEVEL_HIGH -> configuration.transmissionRiskScores[5]
|
||||
RiskLevel.RISK_LEVEL_VERY_HIGH -> configuration.transmissionRiskScores[6]
|
||||
RiskLevel.RISK_LEVEL_HIGHEST -> configuration.transmissionRiskScores[7]
|
||||
else -> 1
|
||||
}
|
||||
}
|
||||
|
||||
fun getRiskScore(configuration: ExposureConfiguration): Int {
|
||||
val risk = getAttenuationRiskScore(configuration) * getDaysSinceLastExposureRiskScore(configuration) * getDurationRiskScore(configuration) * getTransmissionRiskScore(configuration)
|
||||
Log.d(TAG, "Risk score calculation: ${getAttenuationRiskScore(configuration)} * ${getDaysSinceLastExposureRiskScore(configuration)} * ${getDurationRiskScore(configuration)} * ${getTransmissionRiskScore(configuration)} = $risk")
|
||||
if (risk < configuration.minimumRiskScore) return 0
|
||||
return risk
|
||||
}
|
||||
|
||||
fun getAttenuationDurations(configuration: ExposureConfiguration): IntArray {
|
||||
return intArrayOf(
|
||||
TimeUnit.MILLISECONDS.toMinutes(subs.filter { it.attenuation < configuration.durationAtAttenuationThresholds[0] }.map { it.duration }.sum()).toInt(),
|
||||
TimeUnit.MILLISECONDS.toMinutes(subs.filter { it.attenuation >= configuration.durationAtAttenuationThresholds[0] && it.attenuation < configuration.durationAtAttenuationThresholds[1] }.map { it.duration }.sum()).toInt(),
|
||||
TimeUnit.MILLISECONDS.toMinutes(subs.filter { it.attenuation >= configuration.durationAtAttenuationThresholds[1] }.map { it.duration }.sum()).toInt()
|
||||
)
|
||||
}
|
||||
|
||||
fun toExposureInformation(configuration: ExposureConfiguration): ExposureInformation =
|
||||
ExposureInformation.ExposureInformationBuilder()
|
||||
.setDateMillisSinceEpoch(key.rollingStartIntervalNumber.toLong() * ROLLING_WINDOW_LENGTH_MS)
|
||||
.setDurationMinutes(durationInMinutes.toInt())
|
||||
.setAttenuationValue(attenuation)
|
||||
.setTransmissionRiskLevel(transmissionRiskLevel)
|
||||
.setTotalRiskScore(getRiskScore(configuration))
|
||||
.setAttenuationDurations(getAttenuationDurations(configuration))
|
||||
.build()
|
||||
|
||||
operator fun plus(exposure: MeasuredExposure): MergedExposure = copy(subs = subs + MergedSubExposure(exposure.attenuation, exposure.duration))
|
||||
|
||||
companion object {
|
||||
const val MAXIMUM_DURATION = 30 * 60 * 1000
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,140 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2020, microG Project Team
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package org.microg.gms.nearby.exposurenotification
|
||||
|
||||
import android.annotation.TargetApi
|
||||
import android.app.*
|
||||
import android.app.PendingIntent.FLAG_UPDATE_CURRENT
|
||||
import android.bluetooth.BluetoothAdapter
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.content.pm.PackageManager
|
||||
import android.graphics.Color
|
||||
import android.location.LocationManager
|
||||
import android.os.Build.VERSION.SDK_INT
|
||||
import android.util.Log
|
||||
import android.util.TypedValue
|
||||
import androidx.core.app.NotificationCompat
|
||||
import androidx.core.app.NotificationManagerCompat
|
||||
import androidx.core.app.PendingIntentCompat
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.location.LocationManagerCompat
|
||||
import androidx.lifecycle.LifecycleService
|
||||
import com.google.android.gms.nearby.exposurenotification.ExposureNotificationClient
|
||||
import org.microg.gms.common.ForegroundServiceContext
|
||||
import org.microg.gms.common.ForegroundServiceInfo
|
||||
import org.microg.gms.nearby.core.R
|
||||
|
||||
@ForegroundServiceInfo("Exposure Notification")
|
||||
class NotifyService : LifecycleService() {
|
||||
private val notificationId = NotifyService::class.java.name.hashCode()
|
||||
private val trigger = object : BroadcastReceiver() {
|
||||
override fun onReceive(context: Context, intent: Intent?) {
|
||||
updateNotification()
|
||||
}
|
||||
}
|
||||
|
||||
@TargetApi(26)
|
||||
private fun createNotificationChannel(): String {
|
||||
val channel = NotificationChannel("exposure-notifications", "Exposure Notifications", NotificationManager.IMPORTANCE_HIGH)
|
||||
channel.setSound(null, null)
|
||||
channel.lockscreenVisibility = Notification.VISIBILITY_PUBLIC
|
||||
channel.setShowBadge(true)
|
||||
if (SDK_INT >= 29) {
|
||||
channel.setAllowBubbles(false)
|
||||
}
|
||||
channel.vibrationPattern = longArrayOf(0)
|
||||
getSystemService(NotificationManager::class.java).createNotificationChannel(channel)
|
||||
return channel.id
|
||||
}
|
||||
|
||||
@TargetApi(21)
|
||||
private fun updateNotification() {
|
||||
val location = !LocationManagerCompat.isLocationEnabled(getSystemService(Context.LOCATION_SERVICE) as LocationManager)
|
||||
val bluetooth = BluetoothAdapter.getDefaultAdapter()?.state.let { it != BluetoothAdapter.STATE_ON && it != BluetoothAdapter.STATE_TURNING_ON }
|
||||
val nearbyPermissions = arrayOf("android.permission.BLUETOOTH_ADVERTISE", "android.permission.BLUETOOTH_SCAN")
|
||||
val permissionNeedsHandling = SDK_INT >= 31 && nearbyPermissions.any {
|
||||
ContextCompat.checkSelfPermission(this, it) != PackageManager.PERMISSION_GRANTED
|
||||
}
|
||||
Log.d( TAG,"notify: location: $location, bluetooth: $bluetooth, permissionNeedsHandling: $permissionNeedsHandling")
|
||||
|
||||
val text: String = when {
|
||||
permissionNeedsHandling -> getString(R.string.exposure_notify_off_nearby)
|
||||
location && bluetooth -> getString(R.string.exposure_notify_off_bluetooth_location)
|
||||
location -> getString(R.string.exposure_notify_off_location)
|
||||
bluetooth -> getString(R.string.exposure_notify_off_bluetooth)
|
||||
else -> {
|
||||
NotificationManagerCompat.from(this).cancel(notificationId)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if (SDK_INT >= 26) {
|
||||
NotificationCompat.Builder(this, createNotificationChannel())
|
||||
} else {
|
||||
NotificationCompat.Builder(this)
|
||||
}.apply {
|
||||
val typedValue = TypedValue()
|
||||
try {
|
||||
var resolved = theme.resolveAttribute(androidx.appcompat.R.attr.colorError, typedValue, true)
|
||||
if (!resolved && SDK_INT >= 26) resolved = theme.resolveAttribute(android.R.attr.colorError, typedValue, true)
|
||||
color = if (resolved) {
|
||||
ContextCompat.getColor(this@NotifyService, typedValue.resourceId)
|
||||
} else {
|
||||
Color.RED
|
||||
}
|
||||
if (SDK_INT >= 26) setColorized(true)
|
||||
} catch (e: Exception) {
|
||||
// Ignore
|
||||
}
|
||||
setSmallIcon(R.drawable.ic_virus_outline)
|
||||
setContentTitle(getString(R.string.exposure_notify_off_title))
|
||||
setContentText(text)
|
||||
setStyle(NotificationCompat.BigTextStyle())
|
||||
try {
|
||||
val intent = Intent(ExposureNotificationClient.ACTION_EXPOSURE_NOTIFICATION_SETTINGS).apply { `package` = packageName }
|
||||
intent.resolveActivity(packageManager)
|
||||
setContentIntent(PendingIntentCompat.getActivity(this@NotifyService, notificationId, Intent(ExposureNotificationClient.ACTION_EXPOSURE_NOTIFICATION_SETTINGS).apply { `package` = packageName }, FLAG_UPDATE_CURRENT, false))
|
||||
} catch (e: Exception) {
|
||||
// Ignore
|
||||
}
|
||||
}.let {
|
||||
NotificationManagerCompat.from(this).notify(notificationId, it.build())
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
registerReceiver(trigger, IntentFilter().apply {
|
||||
addAction(BluetoothAdapter.ACTION_STATE_CHANGED)
|
||||
if (SDK_INT >= 19) addAction(LocationManager.MODE_CHANGED_ACTION)
|
||||
addAction(LocationManager.PROVIDERS_CHANGED_ACTION)
|
||||
addAction(NOTIFICATION_UPDATE_ACTION)
|
||||
})
|
||||
}
|
||||
|
||||
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||
ForegroundServiceContext.completeForegroundService(this, intent, TAG)
|
||||
Log.d(TAG, "NotifyService.start: $intent")
|
||||
super.onStartCommand(intent, flags, startId)
|
||||
updateNotification()
|
||||
return Service.START_STICKY
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
NotificationManagerCompat.from(this).cancel(notificationId)
|
||||
unregisterReceiver(trigger)
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun isNeeded(context: Context): Boolean {
|
||||
return ExposurePreferences(context).let { it.enabled }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,197 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2020, microG Project Team
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package org.microg.gms.nearby.exposurenotification
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.annotation.TargetApi
|
||||
import android.app.AlarmManager
|
||||
import android.app.PendingIntent.FLAG_ONE_SHOT
|
||||
import android.app.PendingIntent.FLAG_UPDATE_CURRENT
|
||||
import android.bluetooth.BluetoothAdapter.*
|
||||
import android.bluetooth.le.*
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.os.*
|
||||
import android.util.Log
|
||||
import androidx.core.app.PendingIntentCompat
|
||||
import androidx.lifecycle.LifecycleService
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import org.microg.gms.common.ForegroundServiceContext
|
||||
import org.microg.gms.common.ForegroundServiceInfo
|
||||
import java.io.FileDescriptor
|
||||
import java.io.PrintWriter
|
||||
import java.util.*
|
||||
|
||||
@TargetApi(21)
|
||||
@ForegroundServiceInfo("Exposure Notification")
|
||||
class ScannerService : LifecycleService() {
|
||||
private var scanning = false
|
||||
private var lastStartTime = 0L
|
||||
private var seenAdvertisements = 0L
|
||||
private var lastAdvertisement = 0L
|
||||
private val callback = object : ScanCallback() {
|
||||
override fun onScanResult(callbackType: Int, result: ScanResult?) {
|
||||
result?.let { onScanResult(it) }
|
||||
}
|
||||
|
||||
override fun onBatchScanResults(results: MutableList<ScanResult>) {
|
||||
for (result in results) {
|
||||
onScanResult(result)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onScanFailed(errorCode: Int) {
|
||||
Log.w(TAG, "onScanFailed: $errorCode")
|
||||
stopScan()
|
||||
}
|
||||
}
|
||||
private val trigger = object : BroadcastReceiver() {
|
||||
override fun onReceive(context: Context?, intent: Intent?) {
|
||||
if (intent?.action == ACTION_STATE_CHANGED) {
|
||||
when (intent.getIntExtra(EXTRA_STATE, -1)) {
|
||||
STATE_TURNING_OFF, STATE_OFF -> stopScan()
|
||||
STATE_ON -> startScanIfNeeded()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
private val handler = Handler(Looper.getMainLooper())
|
||||
private val stopLaterRunnable = Runnable { stopScan() }
|
||||
|
||||
// Wake lock for the duration of scan. Otherwise we might fall asleep while scanning
|
||||
// resulting in potentially very long scan times
|
||||
private val wakeLock: PowerManager.WakeLock by lazy {
|
||||
powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, ScannerService::class.java.canonicalName).apply { setReferenceCounted(false) }
|
||||
}
|
||||
|
||||
private val scanner: BluetoothLeScanner?
|
||||
get() = getDefaultAdapter()?.bluetoothLeScanner
|
||||
private val alarmManager: AlarmManager
|
||||
get() = getSystemService(Context.ALARM_SERVICE) as AlarmManager
|
||||
private val powerManager: PowerManager
|
||||
get() = getSystemService(Context.POWER_SERVICE) as PowerManager
|
||||
|
||||
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||
ForegroundServiceContext.completeForegroundService(this, intent, TAG)
|
||||
Log.d(TAG, "ScannerService.start: $intent")
|
||||
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
|
||||
seenAdvertisements++
|
||||
lastAdvertisement = System.currentTimeMillis()
|
||||
lifecycleScope.launchWhenStarted {
|
||||
ExposureDatabase.with(this@ScannerService) { database ->
|
||||
database.noteAdvertisement(data.sliceArray(0..15), data.drop(16).toByteArray(), result.rssi)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun startScanIfNeeded() {
|
||||
if (ExposurePreferences(this).enabled) {
|
||||
startScan()
|
||||
} else {
|
||||
stopSelf()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
registerReceiver(trigger, IntentFilter().apply { addAction(ACTION_STATE_CHANGED) })
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
unregisterReceiver(trigger)
|
||||
stopScan()
|
||||
}
|
||||
|
||||
@SuppressLint("WakelockTimeout", "MissingPermission")
|
||||
@Synchronized
|
||||
private fun startScan() {
|
||||
if (scanning) return
|
||||
val scanner = scanner ?: return
|
||||
Log.i(TAG, "Starting scanner for service $SERVICE_UUID for ${SCANNING_TIME_MS}ms")
|
||||
seenAdvertisements = 0
|
||||
wakeLock.acquire()
|
||||
try {
|
||||
scanner.startScan(
|
||||
listOf(ScanFilter.Builder()
|
||||
.setServiceUuid(SERVICE_UUID)
|
||||
.setServiceData(SERVICE_UUID, byteArrayOf(0), byteArrayOf(0))
|
||||
.build()),
|
||||
ScanSettings.Builder().build(),
|
||||
callback
|
||||
)
|
||||
} catch (e: SecurityException) {
|
||||
Log.e(TAG, "Couldn't start ScannerService, need android.permission.BLUETOOTH_SCAN permission.")
|
||||
}
|
||||
scanning = true
|
||||
lastStartTime = System.currentTimeMillis()
|
||||
handler.postDelayed(stopLaterRunnable, SCANNING_TIME_MS)
|
||||
}
|
||||
|
||||
@SuppressLint("MissingPermission")
|
||||
@Synchronized
|
||||
private fun stopScan() {
|
||||
if (!scanning) return
|
||||
Log.i(TAG, "Stopping scanner for service $SERVICE_UUID, had seen $seenAdvertisements advertisements")
|
||||
handler.removeCallbacks(stopLaterRunnable)
|
||||
scanning = false
|
||||
try {
|
||||
scanner?.stopScan(callback)
|
||||
} catch (e: Exception) {
|
||||
// Ignored
|
||||
}
|
||||
if (ExposurePreferences(this).enabled) {
|
||||
scheduleStartScan(((lastStartTime + SCANNING_INTERVAL_MS) - System.currentTimeMillis()).coerceIn(0, SCANNING_INTERVAL_MS))
|
||||
}
|
||||
wakeLock.release()
|
||||
}
|
||||
|
||||
private fun scheduleStartScan(nextScan: Long) {
|
||||
val intent = Intent(this, ScannerService::class.java)
|
||||
val pendingIntent = PendingIntentCompat.getService(this, ScannerService::class.java.hashCode(), intent, FLAG_ONE_SHOT or FLAG_UPDATE_CURRENT, false)!!
|
||||
if (Build.VERSION.SDK_INT >= 23) {
|
||||
// Note: there is no setWindowAndAllowWhileIdle()
|
||||
alarmManager.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + nextScan, pendingIntent)
|
||||
} else {
|
||||
alarmManager.setWindow(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + nextScan - SCANNING_TIME_MS / 2, SCANNING_TIME_MS, pendingIntent)
|
||||
}
|
||||
}
|
||||
|
||||
override fun dump(fd: FileDescriptor?, writer: PrintWriter?, args: Array<out String>?) {
|
||||
writer?.println("Scanning now: $scanning")
|
||||
writer?.println("Last scan start: ${Date(lastStartTime)}")
|
||||
if (Build.VERSION.SDK_INT >= 29) {
|
||||
writer?.println("Scan stop pending: ${handler.hasCallbacks(stopLaterRunnable)}")
|
||||
}
|
||||
writer?.println("Seen advertisements since last scan start: $seenAdvertisements")
|
||||
writer?.println("Last advertisement seen: ${Date(lastAdvertisement)}")
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun isNeeded(context: Context): Boolean {
|
||||
return ExposurePreferences(context).enabled
|
||||
}
|
||||
|
||||
fun isSupported(context: Context): Boolean? {
|
||||
val adapter = getDefaultAdapter()
|
||||
return when {
|
||||
adapter == null -> false
|
||||
adapter.state != STATE_ON -> null
|
||||
adapter.bluetoothLeScanner != null -> true
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2020, microG Project Team
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package org.microg.gms.nearby.exposurenotification
|
||||
|
||||
import android.content.Context
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.io.Serializable
|
||||
|
||||
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)
|
||||
|
||||
suspend fun getExposureNotificationsServiceInfo(context: Context): ServiceInfo =
|
||||
withContext(Dispatchers.IO) {
|
||||
ServiceInfo(ExposurePreferences(context).toConfiguration())
|
||||
}
|
||||
|
||||
suspend fun setExposureNotificationsServiceConfiguration(context: Context, configuration: ServiceConfiguration) =
|
||||
withContext(Dispatchers.IO) {
|
||||
ExposurePreferences(context).enabled = configuration.enabled
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2020, microG Project Team
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package org.microg.gms.nearby.exposurenotification
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.util.Log
|
||||
import org.microg.gms.common.ForegroundServiceContext
|
||||
|
||||
class ServiceTrigger : BroadcastReceiver() {
|
||||
@SuppressLint("UnsafeProtectedBroadcastReceiver")
|
||||
override fun onReceive(context: Context, intent: Intent?) {
|
||||
Log.d(TAG, "ServiceTrigger: $intent")
|
||||
val serviceContext = ForegroundServiceContext(context)
|
||||
if (ScannerService.isNeeded(context)) {
|
||||
Log.d(TAG, "Trigger ${ScannerService::class.java}")
|
||||
serviceContext.startService(Intent(context, ScannerService::class.java))
|
||||
}
|
||||
if (AdvertiserService.isNeeded(context)) {
|
||||
Log.d(TAG, "Trigger ${AdvertiserService::class.java}")
|
||||
serviceContext.startService(Intent(context, AdvertiserService::class.java))
|
||||
}
|
||||
if (CleanupService.isNeeded(context)) {
|
||||
Log.d(TAG, "Trigger ${CleanupService::class.java}")
|
||||
serviceContext.startService(Intent(context, CleanupService::class.java))
|
||||
}
|
||||
if (NotifyService.isNeeded(context)) {
|
||||
Log.d(TAG, "Trigger ${NotifyService::class.java}")
|
||||
serviceContext.startService(Intent(context, NotifyService::class.java))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2022 microG Project Team
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package org.microg.gms.nearby.exposurenotification.ui
|
||||
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import androidx.preference.Preference
|
||||
import androidx.preference.PreferenceViewHolder
|
||||
import org.microg.gms.nearby.core.R
|
||||
import org.microg.gms.nearby.exposurenotification.ExposureScanSummary
|
||||
|
||||
class DotChartPreference : Preference {
|
||||
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes)
|
||||
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
|
||||
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
|
||||
constructor(context: Context) : super(context)
|
||||
|
||||
init {
|
||||
layoutResource = R.layout.preference_dot_chart
|
||||
}
|
||||
|
||||
private lateinit var chart: DotChartView
|
||||
var data: Set<ExposureScanSummary> = emptySet()
|
||||
set(value) {
|
||||
field = value
|
||||
if (this::chart.isInitialized) {
|
||||
chart.data = data
|
||||
}
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: PreferenceViewHolder) {
|
||||
super.onBindViewHolder(holder)
|
||||
chart = holder.itemView as? DotChartView ?: holder.findViewById(R.id.dot_chart) as DotChartView
|
||||
chart.data = data
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,285 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2022 microG Project Team
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package org.microg.gms.nearby.exposurenotification.ui
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.annotation.TargetApi
|
||||
import android.content.Context
|
||||
import android.graphics.*
|
||||
import android.os.Build.VERSION.SDK_INT
|
||||
import android.text.format.DateFormat
|
||||
import android.text.format.DateUtils
|
||||
import android.util.AttributeSet
|
||||
import android.view.MotionEvent
|
||||
import android.view.View
|
||||
import org.microg.gms.nearby.exposurenotification.ExposureScanSummary
|
||||
import org.microg.gms.nearby.core.R
|
||||
import org.microg.gms.ui.resolveColor
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
|
||||
|
||||
class DotChartView : View {
|
||||
@TargetApi(21)
|
||||
constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes)
|
||||
constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
|
||||
constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs)
|
||||
constructor(context: Context?) : super(context)
|
||||
|
||||
var data: Set<ExposureScanSummary>? = null
|
||||
@SuppressLint("SimpleDateFormat")
|
||||
set(value) {
|
||||
field = value
|
||||
val displayData = hashMapOf<Int, Pair<String, MutableMap<Int, Int>>>()
|
||||
val now = System.currentTimeMillis()
|
||||
val min = now - 14 * 24 * 60 * 60 * 1000L
|
||||
val date = Date(min)
|
||||
val dateFormat = DateFormat.getMediumDateFormat(context)
|
||||
val hourFormat = SimpleDateFormat("H")
|
||||
val lowest = dateFormat.parse(dateFormat.format(date))?.time ?: date.time
|
||||
fun formatDateForView(date: Date) = DateUtils.formatDateTime(context, date.time, DateUtils.FORMAT_ABBREV_MONTH or DateUtils.FORMAT_NO_YEAR)
|
||||
for (day in 0 until 15) {
|
||||
date.time = now - (14 - day) * 24 * 60 * 60 * 1000L
|
||||
displayData[day] = formatDateForView(date) to hashMapOf()
|
||||
}
|
||||
fun dayByDate(date: Date) : Int? {
|
||||
val dateString = formatDateForView(date)
|
||||
return displayData.entries.firstOrNull { it.value.first == dateString }?.key
|
||||
}
|
||||
if (value != null) {
|
||||
for (summary in value) {
|
||||
val off = summary.time - lowest
|
||||
if (off < 0) continue
|
||||
val totalHours = (off / 1000 / 60 / 60).toInt()
|
||||
date.time = summary.time
|
||||
val day = dayByDate(date) ?: (totalHours / 24)
|
||||
val hour = hourFormat.format(date).toIntOrNull() ?: (totalHours % 24)
|
||||
displayData[day]?.second?.set(hour, (displayData[day]?.second?.get(hour) ?: 0) + summary.rpis)
|
||||
}
|
||||
}
|
||||
for (hour in 0..((min - lowest) / 1000 / 60 / 60).toInt()) {
|
||||
displayData[0]?.second?.set(hour, displayData[0]?.second?.get(hour) ?: -1)
|
||||
}
|
||||
for (hour in ((min - lowest) / 1000 / 60 / 60).toInt() until 24) {
|
||||
displayData[14]?.second?.set(hour, displayData[14]?.second?.get(hour) ?: -1)
|
||||
}
|
||||
this.displayData = displayData
|
||||
this.displayDataList = displayData.values.map { it.second.values }.flatten().sorted()
|
||||
invalidate()
|
||||
}
|
||||
|
||||
private var displayData: Map<Int, Pair<String, Map<Int, Int>>> = emptyMap()
|
||||
private var displayDataList: List<Int> = emptyList()
|
||||
private val drawPaint = Paint()
|
||||
private val drawTempRect = RectF()
|
||||
private val fontPaint = Paint()
|
||||
private val fontTempRect = Rect()
|
||||
|
||||
fun Canvas.drawMyRect(x: Float, y: Float, width: Float, height: Float, color: Int) {
|
||||
drawTempRect.set(x + drawPaint.strokeWidth, y + drawPaint.strokeWidth, x + width - drawPaint.strokeWidth, y + height - drawPaint.strokeWidth)
|
||||
if (Color.alpha(color) >= 80) {
|
||||
drawPaint.style = Paint.Style.FILL_AND_STROKE
|
||||
drawPaint.color = color
|
||||
drawRoundRect(drawTempRect, 2f, 2f, drawPaint)
|
||||
drawPaint.style = Paint.Style.FILL
|
||||
} else {
|
||||
drawPaint.color = color or (80 shl 24) and (80 shl 24 or 0xffffff)
|
||||
drawPaint.style = Paint.Style.STROKE
|
||||
drawRoundRect(drawTempRect, 2f, 2f, drawPaint)
|
||||
drawPaint.style = Paint.Style.FILL
|
||||
drawPaint.color = color
|
||||
drawRoundRect(drawTempRect, 2f, 2f, drawPaint)
|
||||
}
|
||||
}
|
||||
|
||||
private fun <T> List<T>.relativePosition(element: T): Double? = indexOf(element).takeIf { it >= 0 }?.toDouble()?.let { it / size.toDouble() }
|
||||
|
||||
private var focusPoint: PointF? = null
|
||||
override fun onDraw(canvas: Canvas) {
|
||||
if (data == null) data = emptySet()
|
||||
val d = resources.displayMetrics.scaledDensity
|
||||
fontPaint.textSize = 10 * d
|
||||
fontPaint.isAntiAlias = true
|
||||
drawPaint.isAntiAlias = true
|
||||
drawPaint.strokeWidth = 2f
|
||||
val innerPadding = 2 * d
|
||||
var maxTextWidth = 0
|
||||
var maxTextHeight = 0
|
||||
for (dateString in displayData.values.map { it.first }) {
|
||||
fontPaint.getTextBounds(dateString, 0, dateString.length, fontTempRect)
|
||||
maxTextWidth = max(maxTextWidth, fontTempRect.width())
|
||||
maxTextHeight = max(maxTextHeight, fontTempRect.height())
|
||||
}
|
||||
|
||||
val legendLeft = max(56 * d, maxTextWidth + 8 * d)
|
||||
val legendBottom = maxTextHeight + 8 * d
|
||||
val subHeight = maxTextHeight + 4 * d + paddingBottom
|
||||
|
||||
val distHeight = (height - innerPadding * 14 - paddingTop - paddingBottom - legendBottom - subHeight).toDouble()
|
||||
val distWidth = (width - innerPadding * 23 - paddingLeft - paddingRight - legendLeft).toDouble()
|
||||
val perHeight = distHeight / 15.0
|
||||
val perWidth = distWidth / 24.0
|
||||
|
||||
val maxValue = displayDataList.last()
|
||||
val accentColor = context.resolveColor(androidx.appcompat.R.attr.colorAccent) ?: 0
|
||||
val fontColor = context.resolveColor(android.R.attr.textColorSecondary) ?: 0
|
||||
val grayBoxColor = fontColor or (255 shl 24) and (80 shl 24 or 0xffffff)
|
||||
fontPaint.textAlign = Paint.Align.RIGHT
|
||||
fontPaint.color = fontColor
|
||||
var focusDay = -1
|
||||
var focusHour = -1
|
||||
for (day in 0 until 15) {
|
||||
val (dateString, hours) = displayData[day] ?: "" to emptyMap()
|
||||
val top = day * (perHeight + innerPadding) + paddingTop
|
||||
if (day % 2 == 0) {
|
||||
canvas.drawText(dateString, (paddingLeft + legendLeft - 8 * d), (top + perHeight / 2.0 + maxTextHeight / 2.0).toFloat(), fontPaint)
|
||||
}
|
||||
focusPoint?.let { if (it.y > top && it.y < top + perHeight) focusDay = day }
|
||||
for (hour in 0 until 24) {
|
||||
val value = hours[hour]
|
||||
val left = hour * (perWidth + innerPadding) + paddingLeft + legendLeft
|
||||
when {
|
||||
value == null -> {
|
||||
canvas.drawMyRect(left.toFloat(), top.toFloat(), perWidth.toFloat(), perHeight.toFloat(), grayBoxColor)
|
||||
}
|
||||
maxValue == 0 -> {
|
||||
canvas.drawMyRect(left.toFloat(), top.toFloat(), perWidth.toFloat(), perHeight.toFloat(), accentColor and 0xffffff)
|
||||
}
|
||||
value >= 0 -> {
|
||||
val byBucket = ((displayDataList.relativePosition(value) ?: 0.0) * 180.0).toInt()
|
||||
val byMax = (value.toDouble() / maxValue.toDouble() * 80.0).toInt()
|
||||
val alpha = max(0, min(byBucket + byMax, 255))
|
||||
canvas.drawMyRect(left.toFloat(), top.toFloat(), perWidth.toFloat(), perHeight.toFloat(), accentColor and (alpha shl 24 or 0xffffff))
|
||||
}
|
||||
}
|
||||
if (focusDay == day && (value == null || value >= 0)) focusPoint?.let {
|
||||
if (it.x > left && it.x < left + perWidth) {
|
||||
focusHour = hour
|
||||
canvas.drawMyRect(left.toFloat(), top.toFloat(), perWidth.toFloat(), perHeight.toFloat(), accentColor and 0xffffff)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
val legendTop = 15 * (perHeight + innerPadding) + paddingTop + maxTextHeight + 8 * d
|
||||
fontPaint.textAlign = Paint.Align.CENTER
|
||||
for (hour in 0 until 24) {
|
||||
if (hour % 3 == 0) {
|
||||
val left = hour * (perWidth + innerPadding) + paddingLeft + legendLeft + perWidth / 2.0
|
||||
canvas.drawText("${hour}:00", left.toFloat(), legendTop.toFloat(), fontPaint)
|
||||
}
|
||||
}
|
||||
|
||||
val subTop = legendTop + paddingBottom
|
||||
val subLeft = paddingLeft + legendLeft
|
||||
|
||||
canvas.drawMyRect(subLeft, subTop.toFloat(), perWidth.toFloat(), perHeight.toFloat(), grayBoxColor)
|
||||
|
||||
val strNoRecords = context.getString(R.string.pref_exposure_rpis_histogram_legend_no_records)
|
||||
fontPaint.textAlign = Paint.Align.LEFT
|
||||
fontPaint.getTextBounds(strNoRecords, 0, strNoRecords.length, fontTempRect)
|
||||
canvas.drawText(strNoRecords, (subLeft + perWidth + 4 * d).toFloat(), (subTop + perHeight / 2.0 + fontTempRect.height() / 2.0).toFloat(), fontPaint)
|
||||
|
||||
if (maxValue >= 0) {
|
||||
canvas.drawMyRect((subLeft + (perWidth + innerPadding) * 1 + 12 * d + fontTempRect.width()).toFloat(), subTop.toFloat(), perWidth.toFloat(), perHeight.toFloat(), accentColor and 0xffffff)
|
||||
canvas.drawMyRect((subLeft + (perWidth + innerPadding) * 2 + 12 * d + fontTempRect.width()).toFloat(), subTop.toFloat(), perWidth.toFloat(), perHeight.toFloat(), accentColor and (80 shl 24 or 0xffffff))
|
||||
canvas.drawMyRect((subLeft + (perWidth + innerPadding) * 3 + 12 * d + fontTempRect.width()).toFloat(), subTop.toFloat(), perWidth.toFloat(), perHeight.toFloat(), accentColor and (170 shl 24 or 0xffffff))
|
||||
canvas.drawMyRect((subLeft + (perWidth + innerPadding) * 4 + 12 * d + fontTempRect.width()).toFloat(), subTop.toFloat(), perWidth.toFloat(), perHeight.toFloat(), accentColor)
|
||||
|
||||
val strRecords = context.getString(R.string.pref_exposure_rpis_histogram_legend_records, "0 - $maxValue")
|
||||
canvas.drawText(strRecords, (subLeft + (perWidth + innerPadding) * 4 + 16 * d + fontTempRect.width() + perWidth).toFloat(), (subTop + perHeight / 2.0 + fontTempRect.height() / 2.0).toFloat(), fontPaint)
|
||||
}
|
||||
|
||||
if (focusHour != -1 && SDK_INT >= 23) {
|
||||
val floatingColor = context.resolveColor(androidx.appcompat.R.attr.colorBackgroundFloating) ?: 0
|
||||
val line1 = "${displayData[focusDay]?.first}, $focusHour:00"
|
||||
val line2 = displayData[focusDay]?.second?.get(focusHour)?.let { context.getString(R.string.pref_exposure_rpis_histogram_legend_records, it.toString()) }
|
||||
?: strNoRecords
|
||||
fontPaint.textSize = 14 * d
|
||||
fontPaint.isFakeBoldText = true
|
||||
fontPaint.getTextBounds(line1, 0, line1.length, fontTempRect)
|
||||
var fontWidth = fontTempRect.width()
|
||||
val line1Height = fontTempRect.height() + innerPadding
|
||||
fontPaint.isFakeBoldText = false
|
||||
fontPaint.getTextBounds(line2, 0, line2.length, fontTempRect)
|
||||
fontWidth = max(fontWidth, fontTempRect.width())
|
||||
val totalHeight = line1Height + innerPadding + fontTempRect.height()
|
||||
drawPaint.color = floatingColor
|
||||
drawPaint.style = Paint.Style.FILL_AND_STROKE
|
||||
val refTop = focusDay * (perHeight + innerPadding) + paddingTop + perHeight / 2
|
||||
val refLeft = focusHour * (perWidth + innerPadding) + paddingLeft + legendLeft
|
||||
if (refLeft - fontWidth < 50 * d) {
|
||||
// To the right
|
||||
drawTempRect.set((refLeft + perWidth + innerPadding).toFloat(), (refTop - innerPadding - 5 * d - totalHeight / 2f).toFloat(), (refLeft + perWidth + innerPadding + 10 * d + fontWidth).toFloat(), (refTop + innerPadding + 5 * d + totalHeight / 2f).toFloat())
|
||||
} else {
|
||||
// To the left
|
||||
drawTempRect.set((refLeft - innerPadding - 10 * d - fontWidth).toFloat(), (refTop - innerPadding - 5 * d - totalHeight / 2f).toFloat(), (refLeft - innerPadding).toFloat(), (refTop + innerPadding + 5 * d + totalHeight / 2f).toFloat())
|
||||
}
|
||||
canvas.drawRoundRect(drawTempRect, drawPaint.strokeWidth, drawPaint.strokeWidth, drawPaint)
|
||||
val path = Path()
|
||||
if (refLeft - fontWidth < 50 * d) {
|
||||
// To the right
|
||||
val off = refLeft + perWidth + innerPadding + drawPaint.strokeWidth
|
||||
val corr = (perWidth / 2 - innerPadding + drawPaint.strokeWidth)
|
||||
path.moveTo(off.toFloat(), (refTop - corr).toFloat())
|
||||
path.lineTo((refLeft + perWidth / 2).toFloat(), refTop.toFloat())
|
||||
path.lineTo(off.toFloat(), (refTop + corr).toFloat())
|
||||
} else {
|
||||
// To the left
|
||||
val off = refLeft - innerPadding - drawPaint.strokeWidth
|
||||
val corr = (perWidth / 2 - innerPadding + drawPaint.strokeWidth)
|
||||
path.moveTo(off.toFloat(), (refTop - corr).toFloat())
|
||||
path.lineTo((refLeft + perWidth / 2).toFloat(), refTop.toFloat())
|
||||
path.lineTo(off.toFloat(), (refTop + corr).toFloat())
|
||||
}
|
||||
drawPaint.style = Paint.Style.STROKE
|
||||
drawPaint.color = accentColor and (130 shl 24 or 0xffffff)
|
||||
canvas.drawRoundRect(drawTempRect, drawPaint.strokeWidth, drawPaint.strokeWidth, drawPaint)
|
||||
|
||||
drawPaint.color = floatingColor
|
||||
drawPaint.style = Paint.Style.FILL_AND_STROKE
|
||||
path.fillType = Path.FillType.EVEN_ODD
|
||||
canvas.drawPath(path, drawPaint)
|
||||
drawPaint.style = Paint.Style.STROKE
|
||||
drawPaint.color = accentColor and (130 shl 24 or 0xffffff)
|
||||
path.fillType = Path.FillType.EVEN_ODD
|
||||
canvas.drawPath(path, drawPaint)
|
||||
|
||||
canvas.drawText(line2, drawTempRect.left + 5 * d, drawTempRect.top + 5 * d + totalHeight, fontPaint)
|
||||
fontPaint.isFakeBoldText = true
|
||||
canvas.drawText(line1, drawTempRect.left + 5 * d, drawTempRect.top + 5 * d + line1Height, fontPaint)
|
||||
fontPaint.isFakeBoldText = false
|
||||
}
|
||||
}
|
||||
|
||||
private val removeFocusPoint = Runnable { unfocus() }
|
||||
|
||||
fun unfocus() {
|
||||
focusPoint = null
|
||||
invalidate()
|
||||
}
|
||||
|
||||
override fun onTouchEvent(event: MotionEvent): Boolean {
|
||||
when (event.actionMasked) {
|
||||
MotionEvent.ACTION_UP, MotionEvent.ACTION_POINTER_UP, MotionEvent.ACTION_CANCEL -> {
|
||||
postDelayed(removeFocusPoint, POPUP_DELAY)
|
||||
return true
|
||||
}
|
||||
MotionEvent.ACTION_DOWN, MotionEvent.ACTION_POINTER_DOWN, MotionEvent.ACTION_MOVE -> {
|
||||
removeCallbacks(removeFocusPoint)
|
||||
focusPoint = PointF(event.x, event.y)
|
||||
invalidate()
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val POPUP_DELAY = 3000L
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2022 microG Project Team
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package org.microg.gms.nearby.exposurenotification.ui
|
||||
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.provider.Settings
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.appcompat.content.res.AppCompatResources
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import org.microg.gms.nearby.core.databinding.ExposureNotificationsAppFragmentBinding
|
||||
import org.microg.gms.nearby.core.R
|
||||
import org.microg.gms.ui.getApplicationInfoIfExists
|
||||
|
||||
class ExposureNotificationsAppFragment : Fragment(R.layout.exposure_notifications_app_fragment) {
|
||||
private lateinit var binding: ExposureNotificationsAppFragmentBinding
|
||||
val packageName: String?
|
||||
get() = arguments?.getString("package")
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
binding = ExposureNotificationsAppFragmentBinding.inflate(inflater, container, false)
|
||||
binding.callbacks = object : ExposureNotificationsAppFragmentCallbacks {
|
||||
override fun onAppClicked() {
|
||||
val intent = Intent()
|
||||
intent.action = Settings.ACTION_APPLICATION_DETAILS_SETTINGS
|
||||
val uri: Uri = Uri.fromParts("package", packageName, null)
|
||||
intent.data = uri
|
||||
context!!.startActivity(intent)
|
||||
}
|
||||
}
|
||||
childFragmentManager.findFragmentById(R.id.sub_preferences)?.arguments = arguments
|
||||
return binding.root
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
val context = requireContext()
|
||||
lifecycleScope.launchWhenResumed {
|
||||
val pm = context.packageManager
|
||||
val applicationInfo = pm.getApplicationInfoIfExists(packageName)
|
||||
binding.appName = applicationInfo?.loadLabel(pm)?.toString() ?: packageName
|
||||
binding.appIcon = applicationInfo?.loadIcon(pm)
|
||||
?: AppCompatResources.getDrawable(context, android.R.mipmap.sym_def_app_icon)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
interface ExposureNotificationsAppFragmentCallbacks {
|
||||
fun onAppClicked()
|
||||
}
|
||||
|
|
@ -0,0 +1,138 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2022 microG Project Team
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package org.microg.gms.nearby.exposurenotification.ui
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.text.format.DateUtils
|
||||
import android.widget.TextView
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.text.HtmlCompat
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.preference.Preference
|
||||
import androidx.preference.PreferenceCategory
|
||||
import androidx.preference.PreferenceFragmentCompat
|
||||
import androidx.preference.PreferenceViewHolder
|
||||
import com.google.android.gms.nearby.exposurenotification.ExposureConfiguration
|
||||
import org.json.JSONObject
|
||||
import org.microg.gms.nearby.core.R
|
||||
import org.microg.gms.nearby.exposurenotification.ExposureDatabase
|
||||
import org.microg.gms.nearby.exposurenotification.merge
|
||||
|
||||
class ExposureNotificationsAppPreferencesFragment : PreferenceFragmentCompat() {
|
||||
private lateinit var open: Preference
|
||||
private lateinit var reportedExposures: PreferenceCategory
|
||||
private lateinit var reportedExposuresNone: Preference
|
||||
private lateinit var reportedExposuresUpdated: Preference
|
||||
private lateinit var apiUsage: Preference
|
||||
private val packageName: String?
|
||||
get() = arguments?.getString("package")
|
||||
|
||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||
addPreferencesFromResource(R.xml.preferences_exposure_notifications_app)
|
||||
}
|
||||
|
||||
@SuppressLint("RestrictedApi")
|
||||
override fun onBindPreferences() {
|
||||
open = preferenceScreen.findPreference("pref_exposure_app_open") ?: open
|
||||
reportedExposures = preferenceScreen.findPreference("prefcat_exposure_app_report") ?: reportedExposures
|
||||
reportedExposuresNone = preferenceScreen.findPreference("pref_exposure_app_report_none")
|
||||
?: reportedExposuresNone
|
||||
reportedExposuresUpdated = preferenceScreen.findPreference("pref_exposure_app_report_updated")
|
||||
?: reportedExposuresUpdated
|
||||
apiUsage = preferenceScreen.findPreference("pref_exposure_app_api_usage") ?: apiUsage
|
||||
open.onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
||||
try {
|
||||
packageName?.let {
|
||||
context?.packageManager?.getLaunchIntentForPackage(it)?.let { intent ->
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
context?.startActivity(intent)
|
||||
}
|
||||
}
|
||||
} catch (ignored: Exception) {
|
||||
}
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
updateContent()
|
||||
}
|
||||
|
||||
private fun ExposureConfiguration?.orDefault() = this
|
||||
?: ExposureConfiguration.ExposureConfigurationBuilder().build()
|
||||
|
||||
private fun formatRelativeDateTimeString(time: Long): CharSequence? =
|
||||
DateUtils.getRelativeDateTimeString(
|
||||
requireContext(),
|
||||
time,
|
||||
DateUtils.DAY_IN_MILLIS,
|
||||
DateUtils.DAY_IN_MILLIS * 2,
|
||||
0
|
||||
)
|
||||
|
||||
fun updateContent() {
|
||||
packageName?.let { packageName ->
|
||||
lifecycleScope.launchWhenResumed {
|
||||
data class NTuple4<T1, T2, T3, T4>(val t1: T1, val t2: T2, val t3: T3, val t4: T4)
|
||||
val (mergedExposures, keysInvolved, lastCheckTime, methodUsageHistogram) = ExposureDatabase.with(requireContext()) { database ->
|
||||
val methodUsageHistogram = database.methodUsageHistogram(packageName)
|
||||
|
||||
val token = database.lastMethodCallArgs(packageName, "provideDiagnosisKeys")?.let { JSONObject(it).getString("request_token") }
|
||||
?: return@with NTuple4(null, null, null, methodUsageHistogram)
|
||||
val lastCheckTime = database.lastMethodCall(packageName, "provideDiagnosisKeys")
|
||||
?: return@with NTuple4(null, null, null, methodUsageHistogram)
|
||||
val config = database.loadConfiguration(packageName, token)
|
||||
?: return@with NTuple4(null, null, null, methodUsageHistogram)
|
||||
val mergedExposures = database.findAllMeasuredExposures(config.first).merge().sortedBy { it.timestamp }
|
||||
val keysInvolved = database.countDiagnosisKeysInvolved(config.first)
|
||||
NTuple4(mergedExposures, keysInvolved, lastCheckTime, methodUsageHistogram)
|
||||
}
|
||||
|
||||
reportedExposures.removeAll()
|
||||
reportedExposures.addPreference(reportedExposuresNone)
|
||||
if (mergedExposures.isNullOrEmpty()) {
|
||||
reportedExposuresNone.isVisible = true
|
||||
} else {
|
||||
reportedExposuresNone.isVisible = false
|
||||
for (exposure in mergedExposures) {
|
||||
val minAttenuation = exposure.subs.map { it.attenuation }.minOrNull() ?: exposure.attenuation
|
||||
val nearby = exposure.attenuation < 63 || minAttenuation < 55
|
||||
val distanceString = if (nearby) getString(R.string.pref_exposure_app_report_entry_distance_close) else getString(R.string.pref_exposure_app_report_entry_distance_far)
|
||||
val durationString = if (exposure.durationInMinutes < 5) getString(R.string.pref_exposure_app_report_entry_time_short) else getString(R.string.pref_exposure_app_report_entry_time_about, exposure.durationInMinutes)
|
||||
val preference = object : Preference(requireContext()) {
|
||||
override fun onBindViewHolder(holder: PreferenceViewHolder) {
|
||||
val titleView = holder.findViewById(android.R.id.title) as? TextView
|
||||
val titleViewTextColor = titleView?.textColors
|
||||
super.onBindViewHolder(holder)
|
||||
if (titleViewTextColor != null) titleView.setTextColor(titleViewTextColor)
|
||||
}
|
||||
}
|
||||
preference.icon = ContextCompat.getDrawable(requireContext(), R.drawable.ic_alert)
|
||||
preference.title = DateUtils.formatDateRange(requireContext(), exposure.timestamp, exposure.timestamp + exposure.durationInMinutes * 60 * 1000L, DateUtils.FORMAT_SHOW_TIME or DateUtils.FORMAT_SHOW_DATE or DateUtils.FORMAT_SHOW_WEEKDAY or DateUtils.FORMAT_ABBREV_WEEKDAY)
|
||||
preference.summary = getString(R.string.pref_exposure_app_report_entry_combined, durationString, distanceString)
|
||||
preference.isSelectable = false
|
||||
reportedExposures.addPreference(preference)
|
||||
}
|
||||
}
|
||||
|
||||
reportedExposuresUpdated.isVisible = lastCheckTime != null
|
||||
reportedExposuresUpdated.title = if (lastCheckTime != null) getString(R.string.pref_exposure_app_report_updated_title, DateUtils.getRelativeDateTimeString(requireContext(), lastCheckTime, DateUtils.DAY_IN_MILLIS, DateUtils.DAY_IN_MILLIS * 2, 0)) else null
|
||||
reportedExposuresUpdated.summary = getString(R.string.pref_exposure_app_last_report_summary_diagnosis_keys, keysInvolved?.toInt()
|
||||
?: 0)
|
||||
reportedExposures.addPreference(reportedExposuresUpdated)
|
||||
|
||||
val apiUsageSummary = methodUsageHistogram.map {
|
||||
getString(R.string.pref_exposure_app_api_usage_summary_line, it.second, it.first.let { "<small><tt>$it</tt></small>" })
|
||||
}.joinToString("<br>").takeIf { it.isNotEmpty() }
|
||||
apiUsage.isVisible = apiUsageSummary != null
|
||||
apiUsage.summary = HtmlCompat.fromHtml(apiUsageSummary.orEmpty(), HtmlCompat.FROM_HTML_MODE_COMPACT).trim()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,252 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2022 microG Project Team
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package org.microg.gms.nearby.exposurenotification.ui
|
||||
|
||||
import android.Manifest.permission.*
|
||||
import android.annotation.SuppressLint
|
||||
import android.bluetooth.BluetoothAdapter
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageInfo.REQUESTED_PERMISSION_NEVER_FOR_LOCATION
|
||||
import android.content.pm.PackageManager
|
||||
import android.content.pm.PackageManager.PERMISSION_GRANTED
|
||||
import android.location.LocationManager
|
||||
import android.os.Build.VERSION.SDK_INT
|
||||
import android.os.Bundle
|
||||
import android.os.ResultReceiver
|
||||
import android.provider.Settings
|
||||
import android.view.View
|
||||
import android.widget.Button
|
||||
import android.widget.TextView
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.content.ContextCompat.checkSelfPermission
|
||||
import androidx.core.location.LocationManagerCompat
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import org.microg.gms.nearby.core.R
|
||||
import org.microg.gms.nearby.exposurenotification.*
|
||||
import org.microg.gms.ui.getApplicationInfoIfExists
|
||||
|
||||
|
||||
class ExposureNotificationsConfirmActivity : AppCompatActivity() {
|
||||
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?
|
||||
get() = intent.getStringExtra(KEY_CONFIRM_ACTION)
|
||||
private val targetPackageName: String?
|
||||
get() = intent.getStringExtra(KEY_CONFIRM_PACKAGE)
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.exposure_notifications_confirm_activity)
|
||||
val applicationInfo = packageManager.getApplicationInfoIfExists(targetPackageName)
|
||||
val selfApplicationInfo = packageManager.getApplicationInfoIfExists(packageName)
|
||||
when (action) {
|
||||
CONFIRM_ACTION_START -> {
|
||||
findViewById<TextView>(android.R.id.title).text = getString(R.string.exposure_confirm_start_title)
|
||||
findViewById<TextView>(android.R.id.summary).text = getString(R.string.exposure_confirm_start_summary, applicationInfo?.loadLabel(packageManager)
|
||||
?: targetPackageName)
|
||||
findViewById<Button>(android.R.id.button1).text = getString(R.string.exposure_confirm_start_button)
|
||||
findViewById<TextView>(R.id.grant_permission_summary).text = getString(R.string.exposure_confirm_permission_description, selfApplicationInfo?.loadLabel(packageManager)
|
||||
?: packageName)
|
||||
checkPermissions()
|
||||
checkBluetooth()
|
||||
checkLocation()
|
||||
}
|
||||
CONFIRM_ACTION_STOP -> {
|
||||
findViewById<TextView>(android.R.id.title).text = getString(R.string.exposure_confirm_stop_title)
|
||||
findViewById<TextView>(android.R.id.summary).text = getString(R.string.exposure_confirm_stop_summary)
|
||||
findViewById<Button>(android.R.id.button1).text = getString(R.string.exposure_confirm_stop_button)
|
||||
}
|
||||
CONFIRM_ACTION_KEYS -> {
|
||||
findViewById<TextView>(android.R.id.title).text = getString(R.string.exposure_confirm_keys_title, applicationInfo?.loadLabel(packageManager)
|
||||
?: targetPackageName)
|
||||
findViewById<TextView>(android.R.id.summary).text = getString(R.string.exposure_confirm_keys_summary)
|
||||
findViewById<Button>(android.R.id.button1).text = getString(R.string.exposure_confirm_keys_button)
|
||||
}
|
||||
else -> {
|
||||
resultCode = RESULT_CANCELED
|
||||
finish()
|
||||
}
|
||||
}
|
||||
findViewById<Button>(android.R.id.button1).setOnClickListener {
|
||||
resultCode = RESULT_OK
|
||||
finish()
|
||||
}
|
||||
findViewById<Button>(android.R.id.button2).setOnClickListener {
|
||||
resultCode = RESULT_CANCELED
|
||||
finish()
|
||||
}
|
||||
findViewById<Button>(R.id.grant_permission_button).setOnClickListener {
|
||||
requestPermissions()
|
||||
}
|
||||
findViewById<Button>(R.id.grant_background_location_button).setOnClickListener {
|
||||
requestBackgroundLocation()
|
||||
}
|
||||
findViewById<Button>(R.id.enable_bluetooth_button).setOnClickListener {
|
||||
requestBluetooth()
|
||||
}
|
||||
findViewById<Button>(R.id.enable_location_button).setOnClickListener {
|
||||
requestLocation()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
if (permissionNeedsHandling) checkPermissions()
|
||||
if (bluetoothNeedsHandling) checkBluetooth()
|
||||
if (locationNeedsHandling) checkLocation()
|
||||
}
|
||||
|
||||
private fun updateButton() {
|
||||
findViewById<Button>(android.R.id.button1).isEnabled =
|
||||
!permissionNeedsHandling && !backgroundLocationNeedsHandling && !bluetoothNeedsHandling && !locationNeedsHandling
|
||||
}
|
||||
|
||||
// Permissions
|
||||
private var permissionNeedsHandling: Boolean = false
|
||||
private var backgroundLocationNeedsHandling: Boolean = false
|
||||
private var permissionRequestCode = 33
|
||||
private fun getRequiredPermissions(): Array<String> {
|
||||
return when {
|
||||
SDK_INT >= 31 -> {
|
||||
// We only need bluetooth permission on 31+ if it's "strongly asserted" that we won't use bluetooth for
|
||||
// location. Otherwise, we also need LOCATION permissions. See
|
||||
// https://developer.android.com/guide/topics/connectivity/bluetooth/permissions#assert-never-for-location
|
||||
try {
|
||||
val packageInfo = packageManager.getPackageInfo(packageName, PackageManager.GET_PERMISSIONS)
|
||||
val bluetoothScanIndex = packageInfo.requestedPermissions!!.indexOf(BLUETOOTH_SCAN)
|
||||
if (packageInfo.requestedPermissionsFlags!![bluetoothScanIndex] and REQUESTED_PERMISSION_NEVER_FOR_LOCATION > 0) {
|
||||
return arrayOf(BLUETOOTH_ADVERTISE, BLUETOOTH_SCAN)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
// Ignore
|
||||
}
|
||||
arrayOf(
|
||||
BLUETOOTH_ADVERTISE,
|
||||
BLUETOOTH_SCAN,
|
||||
ACCESS_COARSE_LOCATION,
|
||||
ACCESS_FINE_LOCATION
|
||||
)
|
||||
}
|
||||
SDK_INT == 29 -> {
|
||||
// We only can directly request background location permission on 29.
|
||||
// We need it on 30 (and possibly later) as well, but it has to be requested in a two
|
||||
// step process, see https://fosstodon.org/@utf8equalsX/104359649537615235
|
||||
arrayOf(
|
||||
ACCESS_BACKGROUND_LOCATION,
|
||||
ACCESS_COARSE_LOCATION,
|
||||
ACCESS_FINE_LOCATION
|
||||
)
|
||||
}
|
||||
else -> {
|
||||
// Below 29 or equals 30
|
||||
arrayOf(
|
||||
ACCESS_COARSE_LOCATION,
|
||||
ACCESS_FINE_LOCATION
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkPermissions() {
|
||||
val permissions = getRequiredPermissions()
|
||||
permissionNeedsHandling = SDK_INT >= 23 && permissions.any {
|
||||
checkSelfPermission(this, it) != PERMISSION_GRANTED
|
||||
}
|
||||
|
||||
backgroundLocationNeedsHandling = SDK_INT >= 30
|
||||
&& ACCESS_FINE_LOCATION in permissions
|
||||
&& checkSelfPermission(this, ACCESS_FINE_LOCATION) == PERMISSION_GRANTED
|
||||
&& checkSelfPermission(this, ACCESS_BACKGROUND_LOCATION) != PERMISSION_GRANTED
|
||||
|
||||
findViewById<View>(R.id.grant_permission_view).visibility =
|
||||
if (permissionNeedsHandling) View.VISIBLE else View.GONE
|
||||
findViewById<View>(R.id.grant_background_location_view).visibility =
|
||||
if (!permissionNeedsHandling && backgroundLocationNeedsHandling) View.VISIBLE else View.GONE
|
||||
updateButton()
|
||||
}
|
||||
|
||||
private fun requestPermissions() {
|
||||
if (SDK_INT >= 23) {
|
||||
requestPermissions(getRequiredPermissions(), ++permissionRequestCode)
|
||||
}
|
||||
}
|
||||
|
||||
private fun requestBackgroundLocation() {
|
||||
if (SDK_INT >= 29) {
|
||||
requestPermissions(arrayOf(ACCESS_BACKGROUND_LOCATION), ++permissionRequestCode)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
|
||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
|
||||
if (requestCode == this.permissionRequestCode) checkPermissions()
|
||||
}
|
||||
|
||||
// Bluetooth
|
||||
private var bluetoothNeedsHandling: Boolean = false
|
||||
private var bluetoothRequestCode = 112
|
||||
private fun checkBluetooth() {
|
||||
val adapter = BluetoothAdapter.getDefaultAdapter()
|
||||
bluetoothNeedsHandling = adapter?.isEnabled != true
|
||||
findViewById<View>(R.id.enable_bluetooth_view).visibility = if (adapter?.isEnabled == false) View.VISIBLE else View.GONE
|
||||
updateButton()
|
||||
}
|
||||
|
||||
private fun requestBluetooth() {
|
||||
val adapter = BluetoothAdapter.getDefaultAdapter()
|
||||
findViewById<View>(R.id.enable_bluetooth_spinner).visibility = View.VISIBLE
|
||||
findViewById<View>(R.id.enable_bluetooth_button).visibility = View.INVISIBLE
|
||||
lifecycleScope.launchWhenStarted {
|
||||
if (adapter != null && !adapter.enableAsync(this@ExposureNotificationsConfirmActivity)) {
|
||||
requestBluetoothViaIntent()
|
||||
} else {
|
||||
checkBluetooth()
|
||||
}
|
||||
findViewById<View>(R.id.enable_bluetooth_spinner).visibility = View.INVISIBLE
|
||||
findViewById<View>(R.id.enable_bluetooth_button).visibility = View.VISIBLE
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("MissingPermission")
|
||||
private fun requestBluetoothViaIntent() {
|
||||
val intent = Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE)
|
||||
try {
|
||||
startActivityForResult(intent, ++bluetoothRequestCode)
|
||||
} catch (e: Exception) {
|
||||
// Ignored
|
||||
}
|
||||
}
|
||||
|
||||
// Location
|
||||
private var locationNeedsHandling: Boolean = false
|
||||
private var locationRequestCode = 231
|
||||
private fun checkLocation() {
|
||||
locationNeedsHandling = !LocationManagerCompat.isLocationEnabled(getSystemService(Context.LOCATION_SERVICE) as LocationManager)
|
||||
findViewById<View>(R.id.enable_location_view).visibility = if (locationNeedsHandling) View.VISIBLE else View.GONE
|
||||
updateButton()
|
||||
}
|
||||
|
||||
private fun requestLocation() {
|
||||
val intent = Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS)
|
||||
startActivityForResult(intent, ++locationRequestCode)
|
||||
}
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
if (requestCode == bluetoothRequestCode) checkBluetooth()
|
||||
}
|
||||
|
||||
override fun finish() {
|
||||
receiver?.send(resultCode, Bundle())
|
||||
super.finish()
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,206 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2022 microG Project Team
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package org.microg.gms.nearby.exposurenotification.ui
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.bluetooth.BluetoothAdapter
|
||||
import android.content.Context.LOCATION_SERVICE
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.location.LocationManager
|
||||
import android.os.Build.VERSION.SDK_INT
|
||||
import android.os.Bundle
|
||||
import android.os.Handler
|
||||
import android.provider.Settings
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.location.LocationManagerCompat
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import androidx.preference.Preference
|
||||
import androidx.preference.PreferenceCategory
|
||||
import androidx.preference.PreferenceFragmentCompat
|
||||
import org.microg.gms.nearby.core.R
|
||||
import org.microg.gms.nearby.exposurenotification.*
|
||||
import org.microg.gms.ui.AppIconPreference
|
||||
import org.microg.gms.ui.SwitchBarPreference
|
||||
import org.microg.gms.ui.getApplicationInfoIfExists
|
||||
import org.microg.gms.ui.navigate
|
||||
|
||||
|
||||
class ExposureNotificationsFragment : PreferenceFragmentCompat() {
|
||||
private lateinit var switchBarPreference: SwitchBarPreference
|
||||
private lateinit var exposureEnableInfo: Preference
|
||||
private lateinit var exposureBluetoothOff: Preference
|
||||
private lateinit var exposureLocationOff: Preference
|
||||
private lateinit var exposureNearbyNotGranted: Preference
|
||||
private lateinit var exposureBluetoothUnsupported: Preference
|
||||
private lateinit var exposureBluetoothNoAdvertisement: Preference
|
||||
private lateinit var exposureApps: PreferenceCategory
|
||||
private lateinit var exposureAppsNone: Preference
|
||||
private lateinit var collectedRpis: Preference
|
||||
private lateinit var advertisingId: Preference
|
||||
private var turningBluetoothOn: Boolean = false
|
||||
private val handler = Handler()
|
||||
private val updateStatusRunnable = Runnable { updateStatus() }
|
||||
private val updateContentRunnable = Runnable { updateContent() }
|
||||
private var permissionRequestCode = 33
|
||||
|
||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||
addPreferencesFromResource(R.xml.preferences_exposure_notifications)
|
||||
}
|
||||
|
||||
@SuppressLint("RestrictedApi")
|
||||
override fun onBindPreferences() {
|
||||
switchBarPreference = preferenceScreen.findPreference("pref_exposure_enabled") ?: switchBarPreference
|
||||
exposureEnableInfo = preferenceScreen.findPreference("pref_exposure_enable_info") ?: exposureEnableInfo
|
||||
exposureBluetoothOff = preferenceScreen.findPreference("pref_exposure_error_bluetooth_off") ?: exposureBluetoothOff
|
||||
exposureLocationOff = preferenceScreen.findPreference("pref_exposure_error_location_off") ?: exposureLocationOff
|
||||
exposureNearbyNotGranted = preferenceScreen.findPreference("pref_exposure_error_nearby_not_granted") ?: exposureNearbyNotGranted
|
||||
exposureBluetoothUnsupported = preferenceScreen.findPreference("pref_exposure_error_bluetooth_unsupported") ?: exposureBluetoothUnsupported
|
||||
exposureBluetoothNoAdvertisement = preferenceScreen.findPreference("pref_exposure_error_bluetooth_no_advertise") ?: exposureBluetoothNoAdvertisement
|
||||
exposureApps = preferenceScreen.findPreference("prefcat_exposure_apps") ?: exposureApps
|
||||
exposureAppsNone = preferenceScreen.findPreference("pref_exposure_apps_none") ?: exposureAppsNone
|
||||
collectedRpis = preferenceScreen.findPreference("pref_exposure_collected_rpis") ?: collectedRpis
|
||||
advertisingId = preferenceScreen.findPreference("pref_exposure_advertising_id") ?: advertisingId
|
||||
|
||||
switchBarPreference.setOnPreferenceChangeListener { _, newValue ->
|
||||
val newStatus = newValue as Boolean
|
||||
ExposurePreferences(requireContext()).enabled = newStatus
|
||||
true
|
||||
}
|
||||
|
||||
exposureLocationOff.onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
||||
val intent = Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS)
|
||||
startActivity(intent)
|
||||
true
|
||||
}
|
||||
|
||||
exposureBluetoothOff.onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
||||
lifecycleScope.launchWhenStarted {
|
||||
turningBluetoothOn = true
|
||||
it.isVisible = false
|
||||
val adapter = BluetoothAdapter.getDefaultAdapter()
|
||||
if (adapter != null && !adapter.enableAsync(requireContext())) {
|
||||
turningBluetoothOn = false
|
||||
val intent = Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE)
|
||||
startActivityForResult(intent, 144)
|
||||
} else {
|
||||
turningBluetoothOn = false
|
||||
updateStatus()
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
exposureNearbyNotGranted.onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
||||
val nearbyPermissions = arrayOf("android.permission.BLUETOOTH_ADVERTISE", "android.permission.BLUETOOTH_SCAN")
|
||||
requestPermissions(nearbyPermissions, ++permissionRequestCode)
|
||||
true
|
||||
}
|
||||
|
||||
collectedRpis.onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
||||
findNavController().navigate(requireContext(), R.id.openExposureRpis)
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
|
||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
|
||||
if (requestCode == this.permissionRequestCode) {
|
||||
updateStatus()
|
||||
// Tell the NotifyService that it should update the notification
|
||||
val intent = Intent(NOTIFICATION_UPDATE_ACTION)
|
||||
requireContext().sendBroadcast(intent)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
|
||||
updateStatus()
|
||||
updateContent()
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
|
||||
handler.removeCallbacks(updateStatusRunnable)
|
||||
handler.removeCallbacks(updateContentRunnable)
|
||||
}
|
||||
|
||||
private fun updateStatus() {
|
||||
val appContext = requireContext().applicationContext
|
||||
lifecycleScope.launchWhenResumed {
|
||||
handler.postDelayed(updateStatusRunnable, UPDATE_STATUS_INTERVAL)
|
||||
val enabled = getExposureNotificationsServiceInfo(appContext).configuration.enabled
|
||||
exposureEnableInfo.isVisible = !enabled
|
||||
|
||||
val bluetoothSupported = ScannerService.isSupported(appContext)
|
||||
val advertisingSupported = if (bluetoothSupported == true) AdvertiserService.isSupported(appContext) else bluetoothSupported
|
||||
|
||||
val nearbyPermissions = arrayOf("android.permission.BLUETOOTH_ADVERTISE", "android.permission.BLUETOOTH_SCAN")
|
||||
// Expresses implication (API 31+ → all new permissions granted) ≡ (¬API 31+ | all new permissions granted)
|
||||
val nearbyPermissionsGranted = SDK_INT < 31 || nearbyPermissions.all {
|
||||
ContextCompat.checkSelfPermission(appContext, it) == PackageManager.PERMISSION_GRANTED
|
||||
}
|
||||
exposureNearbyNotGranted.isVisible = enabled && !nearbyPermissionsGranted
|
||||
exposureLocationOff.isVisible = enabled && bluetoothSupported != false && !LocationManagerCompat.isLocationEnabled(appContext.getSystemService(LOCATION_SERVICE) as LocationManager)
|
||||
exposureBluetoothOff.isVisible = enabled && bluetoothSupported == null && !turningBluetoothOn
|
||||
exposureBluetoothUnsupported.isVisible = enabled && bluetoothSupported == false
|
||||
exposureBluetoothNoAdvertisement.isVisible = enabled && bluetoothSupported == true && advertisingSupported != true
|
||||
|
||||
advertisingId.isVisible = enabled && advertisingSupported == true
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateContent() {
|
||||
val context = requireContext()
|
||||
lifecycleScope.launchWhenResumed {
|
||||
handler.postDelayed(updateContentRunnable, UPDATE_CONTENT_INTERVAL)
|
||||
val (apps, lastHourKeys, currentId) = ExposureDatabase.with(context) { database ->
|
||||
val apps = database.appList.map { packageName ->
|
||||
context.packageManager.getApplicationInfoIfExists(packageName)
|
||||
}.filterNotNull().mapIndexed { idx, applicationInfo ->
|
||||
val pref = AppIconPreference(context)
|
||||
pref.order = idx
|
||||
pref.applicationInfo = applicationInfo
|
||||
pref.onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
||||
findNavController().navigate(requireContext(), R.id.openExposureAppDetails, bundleOf(
|
||||
"package" to applicationInfo.packageName
|
||||
))
|
||||
true
|
||||
}
|
||||
pref.key = "pref_exposure_app_" + applicationInfo.packageName
|
||||
pref
|
||||
}
|
||||
val lastHourKeys = database.hourRpiCount
|
||||
val currentId = database.currentRpiId
|
||||
Triple(apps, lastHourKeys, currentId)
|
||||
}
|
||||
collectedRpis.summary = getString(R.string.pref_exposure_collected_rpis_summary, lastHourKeys)
|
||||
if (currentId != null) {
|
||||
advertisingId.isVisible = true
|
||||
advertisingId.summary = currentId.toString()
|
||||
} else {
|
||||
advertisingId.isVisible = false
|
||||
}
|
||||
exposureApps.removeAll()
|
||||
if (apps.isEmpty()) {
|
||||
exposureApps.addPreference(exposureAppsNone)
|
||||
} else {
|
||||
for (app in apps) {
|
||||
exposureApps.addPreference(app)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val UPDATE_STATUS_INTERVAL = 1000L
|
||||
private const val UPDATE_CONTENT_INTERVAL = 60000L
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2022 microG Project Team
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package org.microg.gms.nearby.exposurenotification.ui
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.annotation.TargetApi
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.preference.Preference
|
||||
import androidx.preference.PreferenceCategory
|
||||
import androidx.preference.PreferenceFragmentCompat
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import org.microg.gms.nearby.core.R
|
||||
import org.microg.gms.nearby.exposurenotification.ExposureDatabase
|
||||
import org.microg.gms.ui.buildAlertDialog
|
||||
|
||||
@TargetApi(21)
|
||||
class ExposureNotificationsRpisFragment : PreferenceFragmentCompat() {
|
||||
private lateinit var histogramCategory: PreferenceCategory
|
||||
private lateinit var histogram: DotChartPreference
|
||||
private lateinit var deleteAll: Preference
|
||||
private lateinit var exportDb: Preference
|
||||
|
||||
override fun onCreateRecyclerView(
|
||||
inflater: LayoutInflater,
|
||||
parent: ViewGroup,
|
||||
savedInstanceState: Bundle?
|
||||
): RecyclerView {
|
||||
return super.onCreateRecyclerView(inflater, parent, savedInstanceState).apply {
|
||||
// Allow drawing under system navbar / status bar
|
||||
fitsSystemWindows = true
|
||||
clipToPadding = false
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||
addPreferencesFromResource(R.xml.preferences_exposure_notifications_rpis)
|
||||
}
|
||||
|
||||
@SuppressLint("RestrictedApi")
|
||||
override fun onBindPreferences() {
|
||||
histogramCategory = preferenceScreen.findPreference("prefcat_exposure_rpi_histogram") ?: histogramCategory
|
||||
histogram = preferenceScreen.findPreference("pref_exposure_rpi_histogram") ?: histogram
|
||||
deleteAll = preferenceScreen.findPreference("pref_exposure_rpi_delete_all") ?: deleteAll
|
||||
exportDb = preferenceScreen.findPreference("pref_exposure_export_database") ?: exportDb
|
||||
deleteAll.onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
||||
requireContext().buildAlertDialog()
|
||||
.setTitle(R.string.pref_exposure_rpi_delete_all_title)
|
||||
.setView(R.layout.exposure_notifications_confirm_delete)
|
||||
.setPositiveButton(R.string.pref_exposure_rpi_delete_all_warning_confirm_button) { _, _ ->
|
||||
lifecycleScope.launchWhenStarted {
|
||||
ExposureDatabase.with(requireContext()) { it.deleteAllCollectedAdvertisements() }
|
||||
updateChart()
|
||||
}
|
||||
}
|
||||
.setNegativeButton(android.R.string.cancel) { _, _ -> }
|
||||
.create()
|
||||
.show()
|
||||
true
|
||||
}
|
||||
exportDb.onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
||||
ExposureDatabase.export(requireContext())
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
updateChart()
|
||||
}
|
||||
|
||||
fun updateChart() {
|
||||
val appContext = requireContext().applicationContext
|
||||
lifecycleScope.launchWhenResumed {
|
||||
val rpiHourHistogram = ExposureDatabase.with(appContext) { database -> database.rpiHourHistogram }
|
||||
val totalRpiCount = rpiHourHistogram.map { it.rpis }.sum()
|
||||
deleteAll.isEnabled = totalRpiCount > 0
|
||||
histogramCategory.title = getString(R.string.prefcat_exposure_rpis_histogram_title, totalRpiCount)
|
||||
histogram.data = rpiHourHistogram
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2022 microG Project Team
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
package org.microg.gms.nearby.exposurenotification.ui
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.navigation.NavController
|
||||
import androidx.navigation.fragment.NavHostFragment
|
||||
import androidx.navigation.ui.AppBarConfiguration
|
||||
import androidx.navigation.ui.NavigationUI
|
||||
import org.microg.gms.nearby.core.R
|
||||
|
||||
class ExposureNotificationsSettingsActivity : AppCompatActivity() {
|
||||
private var appBarConfiguration: AppBarConfiguration? = null
|
||||
|
||||
private val navController: NavController
|
||||
get() = (supportFragmentManager.findFragmentById(R.id.navhost) as NavHostFragment?)!!.navController
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.exposure_notifications_settings_activity)
|
||||
appBarConfiguration = AppBarConfiguration.Builder(navController.graph).build()
|
||||
NavigationUI.setupActionBarWithNavController(this, navController, appBarConfiguration!!)
|
||||
}
|
||||
|
||||
override fun onSupportNavigateUp(): Boolean {
|
||||
return NavigationUI.navigateUp(navController, appBarConfiguration!!) || super.onSupportNavigateUp()
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2020, microG Project Team
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package org.microg.gms.nearby.exposurenotification.ui
|
||||
|
||||
import android.view.View
|
||||
import androidx.annotation.AttrRes
|
||||
import androidx.databinding.BindingAdapter
|
||||
import org.microg.gms.ui.resolveColor
|
||||
|
||||
@BindingAdapter("app:backgroundColorAttr")
|
||||
fun View.setBackgroundColorAttribute(@AttrRes resId: Int) = context.resolveColor(resId)?.let { setBackgroundColor(it) }
|
||||
|
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2020, Google
|
||||
* SPDX-FileCopyrightText: 2020, microG Project Team
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
* Notice: Portions of this file are derived from work created and shared by Google and used
|
||||
* according to the terms described in the Apache License, Version 2.0.
|
||||
* See https://developers.google.com/android/exposure-notifications/exposure-key-file-format
|
||||
*/
|
||||
|
||||
syntax = "proto2";
|
||||
package org.microg.gms.nearby.exposurenotification.proto;
|
||||
|
||||
message TemporaryExposureKeyExport {
|
||||
// Time window of keys in this batch based on arrival to server, in UTC seconds.
|
||||
optional fixed64 start_timestamp = 1;
|
||||
optional fixed64 end_timestamp = 2;
|
||||
// Region for which these keys came from, such as country.
|
||||
optional string region = 3;
|
||||
// For example, file 2 in batch size of 10. Ordinal, 1-based numbering.
|
||||
// Note: Not yet supported on iOS.
|
||||
optional int32 batch_num = 4;
|
||||
optional int32 batch_size = 5;
|
||||
// Information about associated signatures
|
||||
repeated SignatureInfo signature_infos = 6;
|
||||
// The TemporaryExposureKeys for initial release of keys.
|
||||
// Keys should be included in this list for initial release,
|
||||
// whereas revised or revoked keys should go in revised_keys.
|
||||
repeated TemporaryExposureKeyProto keys = 7;
|
||||
// TemporaryExposureKeys that have changed status.
|
||||
// Keys should be included in this list if they have changed status
|
||||
// or have been revoked.
|
||||
repeated TemporaryExposureKeyProto revised_keys = 8;
|
||||
}
|
||||
|
||||
message SignatureInfo {
|
||||
// The first two fields have been deprecated
|
||||
reserved 1, 2;
|
||||
reserved "app_bundle_id", "android_package";
|
||||
// Key version for rollovers
|
||||
// Must be in character class [a-zA-Z0-9_]. For example, 'v1'
|
||||
optional string verification_key_version = 3;
|
||||
// Alias with which to identify public key to be used for verification
|
||||
// Must be in character class [a-zA-Z0-9_.]
|
||||
// For cross-compatibility with Apple, you can use your region's three-digit
|
||||
// mobile country code (MCC). If your region has more than one MCC, choose the
|
||||
// one that Apple has configured.
|
||||
optional string verification_key_id = 4;
|
||||
// ASN.1 OID for Algorithm Identifier. For example, `1.2.840.10045.4.3.2'
|
||||
optional string signature_algorithm = 5;
|
||||
}
|
||||
|
||||
message TemporaryExposureKeyProto {
|
||||
// Key of infected user
|
||||
optional bytes key_data = 1;
|
||||
// Varying risk associated with a key depending on diagnosis method
|
||||
optional int32 transmission_risk_level = 2 [deprecated = true];
|
||||
// The interval number since epoch for which a key starts
|
||||
optional int32 rolling_start_interval_number = 3;
|
||||
// Increments of 10 minutes describing how long a key is valid
|
||||
optional int32 rolling_period = 4
|
||||
[default = 144]; // defaults to 24 hours
|
||||
// Data type representing why this key was published.
|
||||
enum ReportType {
|
||||
UNKNOWN = 0; // Never returned by the client API.
|
||||
CONFIRMED_TEST = 1;
|
||||
CONFIRMED_CLINICAL_DIAGNOSIS = 2;
|
||||
SELF_REPORT = 3;
|
||||
RECURSIVE = 4; // Reserved for future use.
|
||||
REVOKED = 5; // Used to revoke a key, never returned by client API.
|
||||
}
|
||||
|
||||
// Type of diagnosis associated with a key.
|
||||
optional ReportType report_type = 5;
|
||||
|
||||
// Number of days elapsed between symptom onset and the TEK being used.
|
||||
// E.g. 2 means TEK is 2 days after onset of symptoms.
|
||||
optional sint32 days_since_onset_of_symptoms = 6;
|
||||
}
|
||||
|
||||
message TEKSignatureList {
|
||||
repeated TEKSignature signatures = 1;
|
||||
}
|
||||
|
||||
message TEKSignature {
|
||||
// Info about the signing key, version, algorithm, etc. Only the
|
||||
// verification_key_id, verification_key_version, and
|
||||
// signature_algorithm fields within signature_info are read.
|
||||
optional SignatureInfo signature_info = 1;
|
||||
// E.g., Batch 2 of 10 - these fields are ignored on android in favor of the
|
||||
// batch fields within TemporaryExposureKeyExport
|
||||
optional int32 batch_num = 2;
|
||||
optional int32 batch_size = 3;
|
||||
// Signature in X9.62 format (ASN.1 SEQUENCE of two INTEGER fields)
|
||||
optional bytes signature = 4;
|
||||
}
|
||||
16
play-services-nearby/core/src/main/res/drawable/ic_alert.xml
Normal file
16
play-services-nearby/core/src/main/res/drawable/ic_alert.xml
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ SPDX-FileCopyrightText: 2019, The Android Open Source Project
|
||||
~ SPDX-FileCopyrightText: 2020, microG Project Team
|
||||
~ SPDX-License-Identifier: Apache-2.0
|
||||
-->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="?attr/colorAccent"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#000"
|
||||
android:pathData="M11,15H13V17H11V15M11,7H13V13H11V7M12,2C6.47,2 2,6.5 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2M12,20A8,8 0 0,1 4,12A8,8 0 0,1 12,4A8,8 0 0,1 20,12A8,8 0 0,1 12,20Z" />
|
||||
</vector>
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ SPDX-FileCopyrightText: 2019, The Android Open Source Project
|
||||
~ SPDX-FileCopyrightText: 2020, microG Project Team
|
||||
~ SPDX-License-Identifier: Apache-2.0
|
||||
-->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="?attr/colorAccent"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#000"
|
||||
android:pathData="M13,5.83L14.88,7.71L13.28,9.31L14.69,10.72L17.71,7.7L12,2H11V7.03L13,9.03M5.41,4L4,5.41L10.59,12L5,17.59L6.41,19L11,14.41V22H12L16.29,17.71L18.59,20L20,18.59M13,18.17V14.41L14.88,16.29" />
|
||||
</vector>
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ SPDX-FileCopyrightText: 2019, Austin Andrews
|
||||
~ SPDX-FileCopyrightText: 2020, microG Project Team
|
||||
~ SPDX-License-Identifier: Apache-2.0
|
||||
-->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="?attr/colorAccent"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#000"
|
||||
android:pathData="M16.37,16.1L11.75,11.47L11.64,11.36L3.27,3L2,4.27L5.18,7.45C5.06,7.95 5,8.46 5,9C5,14.25 12,22 12,22C12,22 13.67,20.15 15.37,17.65L18.73,21L20,19.72M12,6.5A2.5,2.5 0 0,1 14.5,9C14.5,9.73 14.17,10.39 13.67,10.85L17.3,14.5C18.28,12.62 19,10.68 19,9A7,7 0 0,0 12,2C10,2 8.24,2.82 6.96,4.14L10.15,7.33C10.61,6.82 11.26,6.5 12,6.5Z" />
|
||||
</vector>
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="?attr/colorAccent">
|
||||
<path
|
||||
android:fillColor="#000"
|
||||
android:pathData="M12,2C8.13,2 5,5.13 5,9c0,5.25 7,13 7,13s7,-7.75 7,-13c0,-3.87 -3.13,-7 -7,-7zM7,9c0,-2.76 2.24,-5 5,-5s5,2.24 5,5c0,2.88 -2.88,7.19 -5,9.88C9.92,16.21 7,11.85 7,9z"/>
|
||||
<path
|
||||
android:fillColor="#000"
|
||||
android:pathData="M12,9m-2.5,0a2.5,2.5 0,1 1,5 0a2.5,2.5 0,1 1,-5 0"/>
|
||||
</vector>
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ SPDX-FileCopyrightText: 2020, Michael Irigoyen
|
||||
~ SPDX-FileCopyrightText: 2020, microG Project Team
|
||||
~ SPDX-License-Identifier: Apache-2.0
|
||||
-->
|
||||
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="?attr/colorAccent"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#000"
|
||||
android:pathData="M12 0.5C11.03 0.5 10.25 1.28 10.25 2.25C10.25 2.84 10.55 3.37 11 3.68V5.08C10.1 5.21 9.26 5.5 8.5 5.94L7.39 4.35C7.58 3.83 7.53 3.23 7.19 2.75C6.84 2.26 6.3 2 5.75 2C5.4 2 5.05 2.1 4.75 2.32C3.96 2.87 3.76 3.96 4.32 4.75C4.66 5.24 5.2 5.5 5.75 5.5L6.93 7.18C6.5 7.61 6.16 8.09 5.87 8.62C5.67 8.54 5.46 8.5 5.25 8.5C4.8 8.5 4.35 8.67 4 9C3.33 9.7 3.33 10.8 4 11.5C4.29 11.77 4.64 11.92 5 12L5 12C5 12.54 5.07 13.06 5.18 13.56L3.87 13.91C3.56 13.65 3.16 13.5 2.75 13.5C2.6 13.5 2.44 13.5 2.29 13.56C1.36 13.81 0.809 14.77 1.06 15.71C1.27 16.5 2 17 2.75 17C2.9 17 3.05 17 3.21 16.94C3.78 16.78 4.21 16.36 4.39 15.84L5.9 15.43C6.35 16.22 6.95 16.92 7.65 17.5L6.55 19.5C6 19.58 5.5 19.89 5.21 20.42C4.75 21.27 5.07 22.33 5.92 22.79C6.18 22.93 6.47 23 6.75 23C7.37 23 7.97 22.67 8.29 22.08C8.57 21.56 8.56 20.96 8.31 20.47L9.38 18.5C10.19 18.82 11.07 19 12 19C12.06 19 12.12 19 12.18 19C12.05 19.26 12 19.56 12 19.88C12.08 20.8 12.84 21.5 13.75 21.5C13.79 21.5 13.84 21.5 13.88 21.5C14.85 21.42 15.57 20.58 15.5 19.62C15.46 19.12 15.21 18.68 14.85 18.39C15.32 18.18 15.77 17.91 16.19 17.6L18.53 19.94C18.43 20.5 18.59 21.07 19 21.5C19.35 21.83 19.8 22 20.25 22S21.15 21.83 21.5 21.5C22.17 20.8 22.17 19.7 21.5 19C21.15 18.67 20.7 18.5 20.25 18.5C20.15 18.5 20.05 18.5 19.94 18.53L17.6 16.19C18.09 15.54 18.47 14.8 18.71 14H19.82C20.13 14.45 20.66 14.75 21.25 14.75C22.22 14.75 23 13.97 23 13S22.22 11.25 21.25 11.25C20.66 11.25 20.13 11.55 19.82 12H19C19 10.43 18.5 9 17.6 7.81L18.94 6.47C19.05 6.5 19.15 6.5 19.25 6.5C19.7 6.5 20.15 6.33 20.5 6C21.17 5.31 21.17 4.2 20.5 3.5C20.15 3.17 19.7 3 19.25 3S18.35 3.17 18 3.5C17.59 3.93 17.43 4.5 17.53 5.06L16.19 6.4C15.27 5.71 14.19 5.25 13 5.08V3.68C13.45 3.37 13.75 2.84 13.75 2.25C13.75 1.28 12.97 0.5 12 0.5M12 17C9.24 17 7 14.76 7 12S9.24 7 12 7 17 9.24 17 12 14.76 17 12 17M10.5 9C9.67 9 9 9.67 9 10.5S9.67 12 10.5 12 12 11.33 12 10.5 11.33 9 10.5 9M14 13C13.45 13 13 13.45 13 14C13 14.55 13.45 15 14 15C14.55 15 15 14.55 15 14C15 13.45 14.55 13 14 13Z" />
|
||||
</vector>
|
||||
|
|
@ -0,0 +1,82 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ SPDX-FileCopyrightText: 2020, microG Project Team
|
||||
~ SPDX-License-Identifier: Apache-2.0
|
||||
-->
|
||||
|
||||
<layout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<data>
|
||||
|
||||
<variable
|
||||
name="appName"
|
||||
type="String" />
|
||||
|
||||
<variable
|
||||
name="appIcon"
|
||||
type="android.graphics.drawable.Drawable" />
|
||||
|
||||
<variable
|
||||
name="callbacks"
|
||||
type="org.microg.gms.nearby.exposurenotification.ui.ExposureNotificationsAppFragmentCallbacks" />
|
||||
</data>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?attr/colorPrimary"
|
||||
android:paddingStart="?attr/listPreferredItemPaddingStart"
|
||||
android:paddingLeft="?attr/listPreferredItemPaddingLeft"
|
||||
android:paddingTop="24dp"
|
||||
android:paddingEnd="?attr/listPreferredItemPaddingEnd"
|
||||
android:paddingRight="?attr/listPreferredItemPaddingRight"
|
||||
android:paddingBottom="16dp">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:gravity="center_horizontal"
|
||||
android:onClick='@{() -> callbacks.onAppClicked()}'
|
||||
android:orientation="vertical">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/icon"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:antialias="true"
|
||||
android:scaleType="fitCenter"
|
||||
android:src="@{appIcon}"
|
||||
tools:src="@android:mipmap/sym_def_app_icon" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:ellipsize="marquee"
|
||||
android:gravity="center"
|
||||
android:singleLine="false"
|
||||
android:text='@{appName}'
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Subhead"
|
||||
android:textColor="?android:attr/textColorPrimary"
|
||||
android:textSize="20sp"
|
||||
tools:text="@tools:sample/lorem" />
|
||||
</LinearLayout>
|
||||
</RelativeLayout>
|
||||
|
||||
<androidx.fragment.app.FragmentContainerView
|
||||
android:id="@+id/sub_preferences"
|
||||
android:name="org.microg.gms.nearby.exposurenotification.ui.ExposureNotificationsAppPreferencesFragment"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1"/>
|
||||
</LinearLayout>
|
||||
</layout>
|
||||
|
|
@ -0,0 +1,275 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ SPDX-FileCopyrightText: 2020, microG Project Team
|
||||
~ SPDX-License-Identifier: Apache-2.0
|
||||
-->
|
||||
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:animateLayoutChanges="true"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@android:id/title"
|
||||
style="@style/TextAppearance.AppCompat.Medium"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingLeft="16dp"
|
||||
android:paddingTop="24dp"
|
||||
android:paddingRight="16dp"
|
||||
android:paddingBottom="8dp"
|
||||
android:textColor="?android:attr/textColorPrimary"
|
||||
tools:text="@string/exposure_confirm_start_title" />
|
||||
|
||||
<ScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:animateLayoutChanges="true"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@android:id/summary"
|
||||
style="@style/TextAppearance.AppCompat.Small"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="16dp"
|
||||
tools:text="Your phone needs to use Bluetooth to securely collect and share IDs with other phones that are nearby.\n\nCorona Warn can notify you if you were exposed to someone who reported to be diagnosed positive.\n\nThe date, duration, and signal strength associated with an exposure will be shared with the app." />
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/grant_permission_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:background="?attr/colorAccent"
|
||||
android:clipToPadding="false"
|
||||
android:paddingLeft="16dp"
|
||||
android:paddingTop="16dp"
|
||||
android:paddingRight="16dp"
|
||||
android:paddingBottom="8dp"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/grant_permission_icon"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:layout_alignTop="@id/grant_permission_summary"
|
||||
android:layout_alignBottom="@id/grant_permission_summary"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_centerVertical="true"
|
||||
android:src="@drawable/ic_alert"
|
||||
app:tint="?attr/colorPrimary" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/grant_permission_summary"
|
||||
style="@style/TextAppearance.AppCompat.Small.Inverse"
|
||||
android:layout_width="0dip"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_marginLeft="16dp"
|
||||
android:layout_toRightOf="@id/grant_permission_icon"
|
||||
android:layout_weight="1"
|
||||
android:text="@string/exposure_confirm_permission_description" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/grant_permission_button"
|
||||
style="@style/Widget.AppCompat.Button.Borderless"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/grant_permission_summary"
|
||||
android:layout_alignLeft="@id/grant_permission_summary"
|
||||
android:layout_marginLeft="-16dp"
|
||||
android:text="@string/exposure_confirm_permission_button"
|
||||
android:textColor="?android:attr/textColorPrimaryInverse" />
|
||||
</RelativeLayout>
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/grant_background_location_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:background="?attr/colorAccent"
|
||||
android:clipToPadding="false"
|
||||
android:paddingLeft="16dp"
|
||||
android:paddingTop="16dp"
|
||||
android:paddingRight="16dp"
|
||||
android:paddingBottom="8dp"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/grant_background_location_icon"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:layout_alignTop="@id/grant_background_location_summary"
|
||||
android:layout_alignBottom="@id/grant_background_location_summary"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_centerVertical="true"
|
||||
android:src="@drawable/ic_outline_location_on"
|
||||
app:tint="?attr/colorPrimary" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/grant_background_location_summary"
|
||||
style="@style/TextAppearance.AppCompat.Small.Inverse"
|
||||
android:layout_width="0dip"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_marginLeft="16dp"
|
||||
android:layout_toRightOf="@id/grant_background_location_icon"
|
||||
android:layout_weight="1"
|
||||
android:text="@string/exposure_grant_background_location_description"/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/grant_background_location_button"
|
||||
style="@style/Widget.AppCompat.Button.Borderless"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/grant_background_location_summary"
|
||||
android:layout_alignLeft="@id/grant_background_location_summary"
|
||||
android:layout_marginLeft="-16dp"
|
||||
android:text="@string/exposure_grant_background_location_button"
|
||||
android:textColor="?android:attr/textColorPrimaryInverse" />
|
||||
</RelativeLayout>
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/enable_bluetooth_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:background="?attr/colorAccent"
|
||||
android:clipToPadding="false"
|
||||
android:paddingLeft="16dp"
|
||||
android:paddingTop="16dp"
|
||||
android:paddingRight="16dp"
|
||||
android:paddingBottom="8dp"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/enable_bluetooth_icon"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:layout_alignTop="@id/enable_bluetooth_summary"
|
||||
android:layout_alignBottom="@id/enable_bluetooth_summary"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_centerVertical="true"
|
||||
android:src="@drawable/ic_bluetooth_off"
|
||||
app:tint="?attr/colorPrimary" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/enable_bluetooth_summary"
|
||||
style="@style/TextAppearance.AppCompat.Small.Inverse"
|
||||
android:layout_width="0dip"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_marginLeft="16dp"
|
||||
android:layout_toRightOf="@id/enable_bluetooth_icon"
|
||||
android:layout_weight="1"
|
||||
android:text="@string/exposure_confirm_bluetooth_description" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/enable_bluetooth_button"
|
||||
style="@style/Widget.AppCompat.Button.Borderless"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/enable_bluetooth_summary"
|
||||
android:layout_alignLeft="@id/enable_bluetooth_summary"
|
||||
android:layout_marginLeft="-16dp"
|
||||
android:text="@string/exposure_confirm_button"
|
||||
android:textColor="?android:attr/textColorPrimaryInverse" />
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/enable_bluetooth_spinner"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignLeft="@id/enable_bluetooth_button"
|
||||
android:layout_alignTop="@id/enable_bluetooth_button"
|
||||
android:layout_alignRight="@id/enable_bluetooth_button"
|
||||
android:layout_alignBottom="@id/enable_bluetooth_button"
|
||||
android:indeterminate="true"
|
||||
android:indeterminateTint="?attr/colorPrimary"
|
||||
android:padding="8dp"
|
||||
android:visibility="invisible" />
|
||||
</RelativeLayout>
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/enable_location_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:background="?attr/colorAccent"
|
||||
android:clipToPadding="false"
|
||||
android:paddingLeft="16dp"
|
||||
android:paddingTop="16dp"
|
||||
android:paddingRight="16dp"
|
||||
android:paddingBottom="8dp"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/enable_location_icon"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:layout_alignTop="@id/enable_location_summary"
|
||||
android:layout_alignBottom="@id/enable_location_summary"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_centerVertical="true"
|
||||
android:src="@drawable/ic_location_off"
|
||||
app:tint="?attr/colorPrimary" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/enable_location_summary"
|
||||
style="@style/TextAppearance.AppCompat.Small.Inverse"
|
||||
android:layout_width="0dip"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_marginLeft="16dp"
|
||||
android:layout_toRightOf="@id/enable_location_icon"
|
||||
android:layout_weight="1"
|
||||
android:text="@string/exposure_confirm_location_description" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/enable_location_button"
|
||||
style="@style/Widget.AppCompat.Button.Borderless"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/enable_location_summary"
|
||||
android:layout_alignLeft="@id/enable_location_summary"
|
||||
android:layout_marginLeft="-16dp"
|
||||
android:text="@string/exposure_confirm_button"
|
||||
android:textColor="?android:attr/textColorPrimaryInverse" />
|
||||
</RelativeLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="end"
|
||||
android:paddingLeft="8dp"
|
||||
android:paddingTop="0dp"
|
||||
android:paddingRight="8dp"
|
||||
android:paddingBottom="8dp">
|
||||
|
||||
<Button
|
||||
android:id="@android:id/button2"
|
||||
style="@style/Widget.AppCompat.Button.Borderless.Colored"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@android:string/cancel" />
|
||||
|
||||
<Button
|
||||
android:id="@android:id/button1"
|
||||
style="@style/Widget.AppCompat.Button.Borderless.Colored"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@android:string/ok" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
</LinearLayout>
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ SPDX-FileCopyrightText: 2020, microG Project Team
|
||||
~ SPDX-License-Identifier: Apache-2.0
|
||||
-->
|
||||
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:padding="?attr/dialogPreferredPadding"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/pref_exposure_rpi_delete_all_warning" />
|
||||
</FrameLayout>
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ SPDX-FileCopyrightText: 2020, microG Project Team
|
||||
~ SPDX-License-Identifier: Apache-2.0
|
||||
-->
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<androidx.fragment.app.FragmentContainerView
|
||||
android:id="@+id/navhost"
|
||||
android:name="androidx.navigation.fragment.NavHostFragment"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:defaultNavHost="true"
|
||||
app:navGraph="@navigation/nav_nearby" />
|
||||
</LinearLayout>
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ SPDX-FileCopyrightText: 2020, microG Project Team
|
||||
~ SPDX-License-Identifier: Apache-2.0
|
||||
-->
|
||||
|
||||
<org.microg.gms.nearby.exposurenotification.ui.DotChartView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/dot_chart"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="230dp"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp" />
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/nav_nearby"
|
||||
app:startDestination="@id/exposureNotificationsFragment"
|
||||
tools:ignore="UnusedNavigation">
|
||||
|
||||
<fragment
|
||||
android:id="@+id/exposureNotificationsFragment"
|
||||
android:name="org.microg.gms.nearby.exposurenotification.ui.ExposureNotificationsFragment"
|
||||
android:label="@string/service_name_exposure"
|
||||
tools:layout="@layout/exposure_notifications_fragment">
|
||||
<deepLink
|
||||
app:action="com.google.android.gms.settings.EXPOSURE_NOTIFICATION_SETTINGS"
|
||||
app:uri="x-gms-settings://exposure-notifications" />
|
||||
|
||||
<action
|
||||
android:id="@+id/openExposureRpis"
|
||||
app:destination="@id/exposureNotificationsRpisFragment" />
|
||||
<action
|
||||
android:id="@+id/openExposureAppDetails"
|
||||
app:destination="@id/exposureNotificationsAppFragment" />
|
||||
</fragment>
|
||||
|
||||
<fragment
|
||||
android:id="@+id/exposureNotificationsRpisFragment"
|
||||
android:name="org.microg.gms.nearby.exposurenotification.ui.ExposureNotificationsRpisFragment"
|
||||
android:label="@string/pref_exposure_collected_rpis_title">
|
||||
<deepLink
|
||||
app:action="ACTION_VIEW"
|
||||
app:uri="x-gms-settings://exposure-notifications-rpis" />
|
||||
</fragment>
|
||||
|
||||
<fragment
|
||||
android:id="@+id/exposureNotificationsAppFragment"
|
||||
android:name="org.microg.gms.nearby.exposurenotification.ui.ExposureNotificationsAppFragment"
|
||||
android:label="@string/service_name_exposure"
|
||||
tools:layout="@layout/exposure_notifications_app_fragment">
|
||||
<argument
|
||||
android:name="package"
|
||||
app:argType="string" />
|
||||
</fragment>
|
||||
</navigation>
|
||||
28
play-services-nearby/core/src/main/res/values-ar/strings.xml
Normal file
28
play-services-nearby/core/src/main/res/values-ar/strings.xml
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="pref_exposure_collected_rpis_title">المعرفات المجمّعة</string>
|
||||
<string name="pref_exposure_error_bluetooth_no_advertise_summary">للأسف، جهازك متوافق جزئياً فقط مع إشعارات التعرض. يمكنك الحصول على إشعارات لجهات الاتصال المعرضة للخطر ولكن لن تتمكن من إشعار الآخرين.</string>
|
||||
<string name="prefcat_exposure_apps_title">التطبيقات التي تستخدم إشعارات التعرض</string>
|
||||
<string name="prefcat_exposure_app_report_title">حالات التعرض المبلغ عنها</string>
|
||||
<string name="pref_exposure_app_last_report_summary_diagnosis_keys">تمت معالجة <xliff:g example="121031">%1$d</xliff:g> مفاتيح تشخيص.</string>
|
||||
<string name="pref_exposure_error_bluetooth_off_title">تفعيل البلوتوث</string>
|
||||
<string name="pref_exposure_error_location_off_title">فتح إعدادات الموقع</string>
|
||||
<string name="pref_exposure_error_bluetooth_unsupported_summary">للأسف، جهازك غير متوافق مع إشعارات التعرض.</string>
|
||||
<string name="pref_exposure_collected_rpis_summary"><xliff:g example="63">(%1$d)</xliff:g> معرّف في الساعة اﻷخيرة</string>
|
||||
<string name="pref_exposure_advertising_id_title">المعرّف المستخدم حاليًا</string>
|
||||
<string name="pref_exposure_app_report_updated_title">تم التحديث: <xliff:g example="Today, 14:02">%1$s</xliff:g></string>
|
||||
<string name="pref_exposure_app_report_entry_time_short">أقل من 5 دقائق</string>
|
||||
<string name="pref_exposure_app_report_entry_time_about">حول <xliff:g example="13">%1$d</xliff:g> دقيقة</string>
|
||||
<string name="pref_exposure_app_report_entry_distance_far">التعرض البعيد</string>
|
||||
<string name="pref_exposure_app_report_entry_combined"><xliff:g example="About 12 minutes">%1$s</xliff:g> ،<xliff:g example="distant exposure">%2$s</xliff:g></string>
|
||||
<string name="pref_exposure_app_last_report_summary_encounters_no">لم يتم الإبلاغ عن أي لقاءات تعرض.</string>
|
||||
<string name="pref_exposure_app_last_report_summary_encounters_prefix">تم اﻹبلاغ عن <xliff:g example="3">%1$d</xliff:g> لقاءات تعرض:</string>
|
||||
<string name="pref_exposure_app_report_entry_distance_close">التعرض القريب</string>
|
||||
<string name="exposure_notify_off_title">إشعارات التعرض غير نشطة</string>
|
||||
<string name="exposure_notify_off_bluetooth">يجب تمكين البلوتوث لتلقي إشعارات التعرض.</string>
|
||||
<string name="exposure_notify_off_location">يلزم الوصول إلى الموقع لتلقي إشعارات التعرض.</string>
|
||||
<string name="exposure_notify_off_bluetooth_location">يجب تمكين Bluetooth والوصول إلى الموقع لتلقي إشعارات التعرض.</string>
|
||||
<string name="exposure_notify_off_nearby">متتطلب إشعارات التعرض أذونات إضافية للعمل</string>
|
||||
<string name="service_name_exposure">إشعارات التعرض</string>
|
||||
<string name="pref_exposure_enable_info_summary">لتمكين إشعارات التعرض، افتح أي تطبيق يدعمها.</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources></resources>
|
||||
49
play-services-nearby/core/src/main/res/values-az/strings.xml
Normal file
49
play-services-nearby/core/src/main/res/values-az/strings.xml
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="pref_exposure_error_bluetooth_off_title">Bluetooth-u Aktiv edin</string>
|
||||
<string name="pref_exposure_error_location_off_title">Məkan tənzimləmələrin açın</string>
|
||||
<string name="pref_exposure_collected_rpis_title">Toplanmış ID-lər</string>
|
||||
<string name="pref_exposure_collected_rpis_summary"><xliff:g example="63">%1$d</xliff:g> Son bir saatda ID-lər</string>
|
||||
<string name="exposure_notify_off_title">Təmas Bildirişləri Qeyri-aktivdir</string>
|
||||
<string name="exposure_notify_off_bluetooth">Təmas Bildirişlərini Qəbul Etmək Üçün Bluetooth Aktivləşdirilməlidir.</string>
|
||||
<string name="exposure_notify_off_location">Təmas Bildirişlərini almaq üçün məkan girişi tələb olunur.</string>
|
||||
<string name="exposure_notify_off_bluetooth_location">Təmas Bildirişlərin qəbul etmək üçün Bluetooth və Məkan girişi aktivləşdirilməlidir.</string>
|
||||
<string name="exposure_notify_off_nearby">Təmas Bildirişləri işləmək üçün əlavə icazələr tələb edir</string>
|
||||
<string name="service_name_exposure">Təmas Bildirişləri</string>
|
||||
<string name="pref_exposure_enable_info_summary">Təmas Bildirişlərin aktivləşdirmək üçün onu dəstəkləyən hansısa tətbiqi aç.</string>
|
||||
<string name="pref_exposure_error_bluetooth_unsupported_summary">Təəssüf ki, cihazınız Təmas Bildirişləri ilə uyğun gəlmir.</string>
|
||||
<string name="pref_exposure_error_bluetooth_no_advertise_summary">Təəssüf ki, cihazınız Təmas Bildirişləri ilə yalnız qismən uyğun gəlir. Siz təhlükəli kontaktlar barədə xəbərdar ola bilərsiniz, lakin başqalarını xəbərdar edə bilməyəcəksiniz.</string>
|
||||
<string name="prefcat_exposure_apps_title">Təmas Bildirişlərin istifadə edən tətbiqlər</string>
|
||||
<string name="pref_exposure_app_report_entry_time_short">5 dəqiqədən az</string>
|
||||
<string name="pref_exposure_app_report_entry_time_about">Haqqında <xliff:g example="13"> %1$d</xliff:g> dəqiqə</string>
|
||||
<string name="pref_exposure_app_last_report_summary_diagnosis_keys">Emal edilib <xliff:g example="121031"> %1$d</xliff:g> diaqnoz açarları.</string>
|
||||
<string name="pref_exposure_app_last_report_summary_encounters_suffix">Qeyd: Risk balı tətbiq tərəfindən təyin edilir. Yüksək rəqəmlər aşağı riskə və ya əksinə aid ola bilər.</string>
|
||||
<string name="pref_exposure_app_api_usage_title">Son 14 gündə API istifadəsi</string>
|
||||
<string name="pref_exposure_app_api_usage_summary_line"><xliff:g example="12">%1$d</xliff:g> -a səslənir <xliff:g example="provideDiagnosisKeys"> %2$s</xliff:g></string>
|
||||
<string name="prefcat_exposure_rpis_histogram_title"><xliff:g example="230">%1$d</xliff:g> ID toplandı</string>
|
||||
<string name="pref_exposure_rpis_histogram_legend_no_records">Qeydlər yoxdur</string>
|
||||
<string name="pref_exposure_rpi_delete_all_title">Sil</string>
|
||||
<string name="pref_exposure_rpi_delete_all_warning_confirm_button">Yenə də silin</string>
|
||||
<string name="pref_exposure_rpi_export_title">İxrac et</string>
|
||||
<string name="pref_exposure_info_summary">Təmas Bildirişləri API-si, müsbət diaqnoz qoyulduğunu bildirən birisi ilə təmasda olmusunuzsa, tətbiqlərə sizi xəbərdar etməyə icazə verir.
|
||||
\n
|
||||
\nTəmas ilə əlaqəli tarix, müddət və siqnal gücü müvafiq tətbiq ilə paylaşılacaq.</string>
|
||||
<string name="exposure_enable_switch">Təmas Bildirişlərin istifadə et</string>
|
||||
<string name="exposure_confirm_start_title">Təmas Bildirişləri aktiv edilsin?</string>
|
||||
<string name="pref_exposure_app_report_entry_distance_far">uzaq təmas</string>
|
||||
<string name="pref_exposure_app_last_report_summary_encounters_no">Təmas ilə bağlı məlumat verilməyib.</string>
|
||||
<string name="pref_exposure_app_last_report_summary_encounters_prefix">Məlumat verildi <xliff:g example="3"> %1$d</xliff:g> təmas qarşılaşmaları:</string>
|
||||
<string name="pref_exposure_app_report_entry_distance_close">yaxın təmas</string>
|
||||
<string name="prefcat_exposure_app_report_title">Bildirilən yoluxmalar</string>
|
||||
<string name="pref_exposure_advertising_id_title">Hazırda yayımlanan ID</string>
|
||||
<string name="pref_exposure_app_report_updated_title">Yenilənib: <xliff:g example="Bugün, 14:02"> %1$s</xliff:g></string>
|
||||
<string name="pref_exposure_app_report_entry_combined"><xliff:g example="About 12 dəqiqə">%1$s</xliff:g> ,<xliff:g example="uzaq təmas"> %2$s</xliff:g></string>
|
||||
<string name="pref_exposure_app_last_report_summary_encounters_line"><xliff:g example="Dünən, 12:00 - 14:00">%1$s</xliff:g> , risk hesabı<xliff:g example="99"> %2$d</xliff:g></string>
|
||||
<string name="pref_exposure_rpis_histogram_legend_records"><xliff:g example="0 - 50">%1$s</xliff:g> Saatda ID</string>
|
||||
<string name="pref_exposure_rpi_delete_all_summary">Bütün toplanmış ID-ləri silin</string>
|
||||
<string name="pref_exposure_rpi_delete_all_warning">Toplanmış ID-lərin silinməsi, son 14 gündə kontaktlarınızdan kiməsə diaqnoz qoyulduğu halda sizə məlumat verməyi qeyri-mümkün edəcək.</string>
|
||||
<string name="pref_exposure_rpi_export_summary">Başqa tətbiqlə uzadılmış təhlil üçün toplanmış ID-ləri ixrac edin.</string>
|
||||
<string name="pref_exposure_rpis_details_summary">Təmas Bildirişi API\'si aktiv olduqda, cihazınız yavaş şəkildə yaxınlıqdakı cihazlardan ID-ləri (Yüklənən Yaxınlıq İdentifikatorları və ya RPI adlanır) toplayır.
|
||||
\n
|
||||
\nCihaz sahibləri diaqnozun müsbət olduğunu bildirdikdə, onların ID-ləri paylaşıla bilər. Cihazınız məlum diaqnoz qoyulmuş ID-lərin, toplanmış ID-lərin hər hansı birinə uyğun olub-olmadığını yoxlayır və yoluxma riskinizi hesablayır.</string>
|
||||
</resources>
|
||||
75
play-services-nearby/core/src/main/res/values-be/strings.xml
Normal file
75
play-services-nearby/core/src/main/res/values-be/strings.xml
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ SPDX-FileCopyrightText: 2020, microG Project Team
|
||||
~ SPDX-License-Identifier: Apache-2.0
|
||||
--><resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="exposure_notify_off_title">Паведамленні аб рызыцы інфікавання не актыўныя</string>
|
||||
<string name="exposure_notify_off_bluetooth">Bluetooth павінен быць уключаны, каб прымаць паведамленні аб рызыцы інфікавання.</string>
|
||||
<string name="exposure_notify_off_location">Доступ да месцазнаходжання абавязковы, каб прымаць паведамленні аб рызыцы інфікавання.</string>
|
||||
<string name="exposure_notify_off_bluetooth_location">Bluetooth і вызначэнне месцазнаходжання павінны быць уключаны, каб прымаць паведамленні аб рызыцы інфікавання.</string>
|
||||
<string name="exposure_notify_off_nearby">Паведамленням аб рызыцы інфікавання для працы патрабуюцца дадатковыя дазволы</string>
|
||||
<string name="service_name_exposure">Паведамленні аб рызыцы інфікавання</string>
|
||||
<string name="pref_exposure_enable_info_summary">Каб уключыць паведамленні аб рызыцы інфікавання запусціце любое прыкладанне, якое іх падтрымлівае.</string>
|
||||
<string name="pref_exposure_error_bluetooth_off_title">Ўключыць Bluetooth</string>
|
||||
<string name="pref_exposure_error_location_off_title">Адкрыць налады месцазнаходжаньня</string>
|
||||
<string name="pref_exposure_error_bluetooth_unsupported_summary">На жаль ваша прылада несумяшчальна з паведамленнямі аб рызыцы інфікавання.</string>
|
||||
<string name="pref_exposure_error_bluetooth_no_advertise_summary">На жаль ваша прылада толькі часткова сумяшчальна з паведамленнямі аб рызыцы інфікавання. Вы можаце атрымліваць паведамленні аб небяспечных кантактах, але не зможаце апавяшчаць іншых.</string>
|
||||
<string name="prefcat_exposure_apps_title">Прыкладанні якія выкарыстоўваюць апавяшчэння аб рызыцы інфікавання</string>
|
||||
<string name="pref_exposure_collected_rpis_title">Сабраныя ідэнтыфікатары</string>
|
||||
<string name="pref_exposure_collected_rpis_summary"><xliff:g example="63">%1$d</xliff:g> олькасць ідэнтыфікатараў за апошнюю гадзіну</string>
|
||||
<string name="pref_exposure_advertising_id_title">Трансліруемы ў цяперашні час ідэнтыфікатар</string>
|
||||
<string name="prefcat_exposure_app_report_title">Паведамленні пра ўзаемадзеянні</string>
|
||||
<string name="pref_exposure_app_report_updated_title">Абноўлена: <xliff:g example="Today, 14:02">%1$s</xliff:g></string>
|
||||
<string name="pref_exposure_app_report_entry_time_short">Менш за пяць хвілін назад</string>
|
||||
<string name="pref_exposure_app_report_entry_time_about">Каля <xliff:g example="13">%1$d</xliff:g> хвілін</string>
|
||||
<string name="pref_exposure_app_report_entry_distance_close">ўзаемадзеянні побач</string>
|
||||
<string name="pref_exposure_app_report_entry_distance_far">ўзаемадзеянні далёка</string>
|
||||
<string name="pref_exposure_app_report_entry_combined"><xliff:g example="About 12 minutes">%1$s</xliff:g>, <xliff:g example="distant exposure">%2$s</xliff:g></string>
|
||||
<string name="pref_exposure_app_last_report_summary_diagnosis_keys">Апрацавана <xliff:g example="121031">%1$d</xliff:g> дыягнастычных ключоў.</string>
|
||||
<string name="pref_exposure_app_last_report_summary_encounters_no">Паведамленні аб небяспечных кантактах адсутнічаюць.</string>
|
||||
<string name="pref_exposure_app_last_report_summary_encounters_prefix">Паведамлена пра <xliff:g example="3">%1$d</xliff:g> небяспечных кантактах:</string>
|
||||
<string name="pref_exposure_app_last_report_summary_encounters_line"><xliff:g example="Yesterday, 12:00 - 14:00">%1$s</xliff:g>, ацэнка рызыкі <xliff:g example="99">%2$d</xliff:g></string>
|
||||
<string name="pref_exposure_app_last_report_summary_encounters_suffix">Увага: Ацэнка рызыкі вызначаецца прыкладаннем. Высокія лічбы могуць казаць, як аб нізкай рызыцы так і наадварот.</string>
|
||||
<string name="pref_exposure_app_api_usage_title">Выкарыстанне API за апошнія 14 дзён</string>
|
||||
<string name="pref_exposure_app_api_usage_summary_line"><xliff:g example="12">%1$d</xliff:g> запытаў да <xliff:g example="provideDiagnosisKeys">%2$s</xliff:g></string>
|
||||
<string name="prefcat_exposure_rpis_histogram_title"><xliff:g example="230">%1$d</xliff:g> ідэнтыфікатараў сабрана</string>
|
||||
<string name="pref_exposure_rpis_histogram_legend_no_records">Няма запісаў</string>
|
||||
<string name="pref_exposure_rpis_histogram_legend_records"><xliff:g example="0 - 50">%1$s</xliff:g> Ідэнтыфікатараў у гадзіну</string>
|
||||
<string name="pref_exposure_rpi_delete_all_title">Выдаліць</string>
|
||||
<string name="pref_exposure_rpi_delete_all_summary">Выдаліць усе сабраныя ідэнтыфікатары</string>
|
||||
<string name="pref_exposure_rpi_delete_all_warning">Выдаленне сабраных ідэнтыфікатараў прывядзе да немагчымасці інфармавання у выпадку, калі ў аднаго з вашых кантактаў за апошнія 14 дзён будзе пацверджаны дыягназ.</string>
|
||||
<string name="pref_exposure_rpi_delete_all_warning_confirm_button">Усё роўна выдаліць</string>
|
||||
<string name="pref_exposure_rpi_export_title">Экспартаваць</string>
|
||||
<string name="pref_exposure_rpi_export_summary">Экспартаваць сабраныя ідэнтыфікатары для пашыранага аналізу ў іншым прыкладанні.</string>
|
||||
<string name="pref_exposure_info_summary">"API паведамленняў аб рызыцы інфікавання (Exposure Notifications API) дазваляе прыкладанням апавяшчаць вас, калі вы сутыкнуліся з кімсьці, у каго быў пацверджаны дыягназ.
|
||||
|
||||
Дата, працягласць і магутнасць сігналу, звязаныя з уздзеяннем, будуць перададзены адпаведным прыкладанням."</string>
|
||||
<string name="pref_exposure_rpis_details_summary">"Пакуль API паведамленняў аб рызыцы інфікавання уключаны, ваша прылада пасіўна збірае ідэнтыфікатары (званыя слізгальнымі ідэнтыфікатарамі збліжэння або RPI) з суседніх прылад.
|
||||
|
||||
Калі ўладальнікі прылад паведамляюць аб пацверджаным дыягназе, іх ідэнтыфікатары могуць быць распаўсюджаныя. Ваша прылада правярае, ці адпавядае якой-небудзь з вядомых ідэнтыфікатараў з пацьвердзіць дыягназам любому з сабраных вамі ідэнтыфікатараў, і разлічвае рызыку заражэння."</string>
|
||||
<string name="exposure_enable_switch">Выкарыстоўваць паведамленні аб рызыцы інфікавання</string>
|
||||
<string name="exposure_confirm_start_title">Ўключыць паведамленні аб рызыцы інфікавання?</string>
|
||||
<string name="exposure_confirm_start_summary">"Ваш тэлефон павінен выкарыстоўваць Bluetooth для бяспечнага збору і распаўсюджвання ідэнтыфікатараў іншым тэлефонам, якія знаходзяцца паблізу.
|
||||
|
||||
<xliff:g example="Corona-Warn">%1$s</xliff:g> можа паведаміць вас, калі вы перасякаліся з кімсьці, у каго быў пацьверджаны дыягназ.
|
||||
|
||||
Дата, працягласць і магутнасць сігналу, звязаныя з кантактам, будуць перададзеныя прыкладанню."</string>
|
||||
<string name="exposure_confirm_start_button">Ўключыць</string>
|
||||
<string name="exposure_confirm_stop_title">Выключыць паведамленні аб рызыцы інфікавання?</string>
|
||||
<string name="exposure_confirm_stop_summary">Пасля адключэння паведамленняў вы больш не будзеце атрымліваць паведамленні аб кантактах з кімсьці, у каго быў пацьверджаны дыягназ.</string>
|
||||
<string name="exposure_confirm_stop_button">Выключыць</string>
|
||||
<string name="exposure_confirm_keys_title">Дзяліцца вашымі ідэнтыфікатарамі з <xliff:g example="Corona-Warn">%1$s</xliff:g>?</string>
|
||||
<string name="exposure_confirm_keys_summary">"Вашы ідэнтыфікатары за апошнія 14 дзён будуць выкарыстоўвацца для паведамлення іншых пра тое, што вы былі паблізу патэнцыйнай небяспекі.
|
||||
|
||||
Ваша асоба або вынік тэсту не будуць перададзены іншым людзям."</string>
|
||||
<string name="exposure_confirm_keys_button">Падзяліцца</string>
|
||||
<string name="exposure_confirm_permission_description">Для <xliff:g example="microG Services">%1$s</xliff:g> патрабуюцца дадатковыя дазволы.</string>
|
||||
<string name="exposure_confirm_permission_button">Даць дазвол</string>
|
||||
<string name="exposure_confirm_bluetooth_description">Bluetooth павінен быць уключаны.</string>
|
||||
<string name="exposure_confirm_location_description">патрабуецца доступ да месцазнаходжання.</string>
|
||||
<string name="exposure_confirm_button">Уключыць</string>
|
||||
<string name="pref_exposure_error_nearby_not_granted_title">Патрабуецца дадатковы дазвол</string>
|
||||
<string name="pref_exposure_error_nearby_not_granted_description">Націсніце, каб даць неабходныя дазволы апавяшчэнням аб рызыцы інфікавання</string>
|
||||
<string name="exposure_grant_background_location_description">Амаль гатова! Вам трэба будзе ўключыць фонавы доступ да месцазнаходжання, выбраўшы опцыю \'Дазволіць у любым рэжыме\' на наступным экране. Потым вярніцеся назад.</string>
|
||||
<string name="exposure_grant_background_location_button">Абнавіць налады</string>
|
||||
</resources>
|
||||
68
play-services-nearby/core/src/main/res/values-cs/strings.xml
Normal file
68
play-services-nearby/core/src/main/res/values-cs/strings.xml
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="exposure_notify_off_title">Oznámení o možném kontaktu nejsou aktivní</string>
|
||||
<string name="exposure_notify_off_bluetooth">Pro získávání oznámení o možném kontaktu musíte povolit Bluetooth.</string>
|
||||
<string name="exposure_notify_off_location">Pro získávání oznámení o možném kontaktu je vyžadován přístup k poloze.</string>
|
||||
<string name="exposure_notify_off_nearby">Oznámení o možném kontaktu vyžadují dodatečná oprávnění pro správnou funkčnost</string>
|
||||
<string name="service_name_exposure">Oznámení o možném kontaktu</string>
|
||||
<string name="pref_exposure_enable_info_summary">Pro zapnutí oznámení o možném kontaktu otevřete podporovanou aplikaci.</string>
|
||||
<string name="prefcat_exposure_apps_title">Aplikace používající oznámení o možném kontaktu</string>
|
||||
<string name="pref_exposure_collected_rpis_title">Nasbíraná ID</string>
|
||||
<string name="pref_exposure_collected_rpis_summary"><xliff:g example="63">%1$d</xliff:g> ID v poslední hodině</string>
|
||||
<string name="pref_exposure_advertising_id_title">Aktuálně vysílané ID</string>
|
||||
<string name="prefcat_exposure_app_report_title">Nahlášené kontakty</string>
|
||||
<string name="pref_exposure_app_report_updated_title">Aktualizováno: <xliff:g example="dnes, 14:02">%1$s</xliff:g></string>
|
||||
<string name="pref_exposure_app_report_entry_time_short">Méně než 5 minut</string>
|
||||
<string name="pref_exposure_app_report_entry_time_about">Asi <xliff:g example="13">%1$d</xliff:g> minut</string>
|
||||
<string name="pref_exposure_app_report_entry_distance_close">blízký kontakt</string>
|
||||
<string name="pref_exposure_app_report_entry_distance_far">vzdálený kontakt</string>
|
||||
<string name="pref_exposure_app_report_entry_combined"><xliff:g example="Asi 12 minut">%1$s</xliff:g>, <xliff:g example="vzdálený kontakt">%2$s</xliff:g></string>
|
||||
<string name="pref_exposure_app_last_report_summary_encounters_no">Nenahlášeny žádné kontakty.</string>
|
||||
<string name="pref_exposure_app_last_report_summary_encounters_prefix">Nahlášeno <xliff:g example="3">%1$d</xliff:g> kontaktů:</string>
|
||||
<string name="pref_exposure_app_last_report_summary_encounters_line"><xliff:g example="Včera, 12:00 - 14:00">%1$s</xliff:g>, rizikové skóre <xliff:g example="99">%2$d</xliff:g></string>
|
||||
<string name="pref_exposure_app_api_usage_summary_line"><xliff:g example="12">%1$d</xliff:g> volání na <xliff:g example="provideDiagnosisKeys">%2$s</xliff:g></string>
|
||||
<string name="prefcat_exposure_rpis_histogram_title"><xliff:g example="230">%1$d</xliff:g> nasbíraných ID</string>
|
||||
<string name="pref_exposure_rpis_histogram_legend_no_records">Žádné záznamy</string>
|
||||
<string name="pref_exposure_rpi_delete_all_title">Odstranit</string>
|
||||
<string name="pref_exposure_rpi_delete_all_summary">Odstranit všechna nasbíraná ID</string>
|
||||
<string name="pref_exposure_rpi_delete_all_warning">Odstraněním nasbíraných ID znemožníte upozornění v případě, že byl v posledních 14 dnech diagnostikován některý z vašich kontaktů.</string>
|
||||
<string name="pref_exposure_rpi_delete_all_warning_confirm_button">Přesto odstranit</string>
|
||||
<string name="pref_exposure_rpi_export_title">Exportovat</string>
|
||||
<string name="pref_exposure_rpi_export_summary">Exportovat nasbíraná ID pro rozšířenou analýzu v jiné aplikaci.</string>
|
||||
<string name="exposure_enable_switch">Používat oznámení o možném kontaktu</string>
|
||||
<string name="exposure_confirm_start_title">Zapnout oznámení o možném kontaktu?</string>
|
||||
<string name="exposure_confirm_start_summary">Váš telefon potřebuje používat Bluetooth pro bezpečné sbírání a sdílení ID s ostatními telefony, které jsou v okolí.\n\nAplikace <xliff:g example="eRouška">%1$s</xliff:g> vám může oznámit, zda jste se setkali s někým, kdo byl nahlášen jako pozitivní.\n\nDatum, doba trvání a síla signálu spojené s kontaktem budou sdíleny s touto aplikací.</string>
|
||||
<string name="exposure_confirm_start_button">Zapnout</string>
|
||||
<string name="exposure_confirm_stop_title">Vypnout oznámení o možném kontaktu?</string>
|
||||
<string name="exposure_confirm_stop_summary">Po vypnutí oznámení o možném kontaktu již nebudete upozorněni, zda jste se setkali s někým, kdo byl nahlášen jako pozitivní.</string>
|
||||
<string name="exposure_confirm_stop_button">Vypnout</string>
|
||||
<string name="exposure_confirm_keys_title">Chcete sdílet vaše ID s aplikací <xliff:g example="eRouška">%1$s</xliff:g>\?</string>
|
||||
<string name="exposure_confirm_keys_button">Sdílet</string>
|
||||
<string name="exposure_confirm_permission_description"><xliff:g example="Služby microG">%1$s</xliff:g> vyžadují dodatečná oprávnění.</string>
|
||||
<string name="exposure_confirm_permission_button">Udělit</string>
|
||||
<string name="exposure_confirm_bluetooth_description">Je třeba povolit Bluetooth.</string>
|
||||
<string name="exposure_confirm_location_description">Je vyžadován přístup k poloze.</string>
|
||||
<string name="exposure_confirm_button">Zapnout</string>
|
||||
<string name="pref_exposure_error_nearby_not_granted_description">Klepněte pro udělení požadovaných oprávnění službe oznámení o možném kontaktu</string>
|
||||
<string name="exposure_grant_background_location_description">Skoro hotovo! Povolte prosím přístup k poloze na pozadí klepnutím na možnost„Povolit vždy“ na další obrazovce. Poté se vraťte zpět.</string>
|
||||
<string name="exposure_notify_off_bluetooth_location">Pro získávání oznámení o možném kontaktu je vyžadován přístup k Bluetooth a k poloze.</string>
|
||||
<string name="pref_exposure_rpis_histogram_legend_records"><xliff:g example="0 - 50">%1$s</xliff:g> ID za hodinu</string>
|
||||
<string name="pref_exposure_error_bluetooth_off_title">Zapnout Bluetooth</string>
|
||||
<string name="pref_exposure_error_bluetooth_unsupported_summary">Vaše zařízení bohužel není kompatibilní s oznámeními o možném kontaktu.</string>
|
||||
<string name="pref_exposure_app_last_report_summary_encounters_suffix">Poznámka: rizikové skóre je definováno aplikací. Vysoká čísla mohou znamenat nízké riziko nebo naopak.</string>
|
||||
<string name="pref_exposure_error_location_off_title">Otevřít nastavení polohy</string>
|
||||
<string name="pref_exposure_app_api_usage_title">Využití API v posledních 14 dnech</string>
|
||||
<string name="pref_exposure_info_summary">Rozhraní API oznámení o možném kontaktu umožňuje aplikacím vás upozornit, pokud jste se setkali s někým, kdo byl nahlášen jako pozitivní.
|
||||
\n
|
||||
\nDatum, doba trvání a síla signálu spojené s kontaktem budou sdíleny s odpovídající aplikací.</string>
|
||||
<string name="pref_exposure_error_bluetooth_no_advertise_summary">Vaše zařízení je bohužel jen částečně kompatibilní s oznámeními o možném kontaktu. Budete upozorněni na rizikové kontakty, nebudete ale moci upozornit ostatní.</string>
|
||||
<string name="pref_exposure_rpis_details_summary">Při povoleném rozhraní API oznámení o možném kontaktu bude vaše zařízení pasivně získávat ID (nazývané Rolling Proximity Identifiers, neboli RPI) z okolních zařízení.
|
||||
\n
|
||||
\nJakmile bude majitel zařízení nahlášen jako pozitivní, může být sdíleno jeho ID. Vaše zařízení kontroluje, zda se některé ze známých ID shoduje s nasbíranými ID a vypočítá riziko vašeho nakažení.</string>
|
||||
<string name="pref_exposure_app_last_report_summary_diagnosis_keys">Zpracováno <xliff:g example="121031">%1$d</xliff:g> diagnostických klíčů.</string>
|
||||
<string name="exposure_confirm_keys_summary">Vaše ID z posledních 14 dnů budou použita pro pomoc s upozorněním lidí, poblíž kterých jste se nacházeli, o možném kontaktu.
|
||||
\n
|
||||
\nVaše identita nebo výsledek testu nebudou s ostatními lidmi sdíleny.</string>
|
||||
<string name="pref_exposure_error_nearby_not_granted_title">Vyžadována nová oprávnění</string>
|
||||
<string name="exposure_grant_background_location_button">Upravit nastavení</string>
|
||||
</resources>
|
||||
75
play-services-nearby/core/src/main/res/values-de/strings.xml
Normal file
75
play-services-nearby/core/src/main/res/values-de/strings.xml
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ SPDX-FileCopyrightText: 2020, microG Project Team
|
||||
~ SPDX-License-Identifier: Apache-2.0
|
||||
--><resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="exposure_notify_off_title">Expositionsbenachrichtigungen deaktiviert</string>
|
||||
<string name="exposure_notify_off_bluetooth">Bluetooth muss eingeschaltet sein, um Expositionsbenachrichtigungen zu nutzen.</string>
|
||||
<string name="exposure_notify_off_location">Standortzugriff muss eingeschaltet sein, um Expositionsbenachrichtigungen zu nutzen.</string>
|
||||
<string name="exposure_notify_off_bluetooth_location">Bluetooth und Standortzugriff müssen eingeschaltet sein, um Expositionsbenachrichtigungen zu nutzen.</string>
|
||||
<string name="service_name_exposure">Expositionsbenachrichtigungen</string>
|
||||
<string name="pref_exposure_enable_info_summary">Um Expositionsbenachrichtigungen zu aktivieren, öffne eine beliebige App, die diese unterstützt.</string>
|
||||
<string name="pref_exposure_error_bluetooth_off_title">Bluetooth einschalten</string>
|
||||
<string name="pref_exposure_error_location_off_title">Standortzugriff verwalten</string>
|
||||
<string name="pref_exposure_error_bluetooth_unsupported_summary">Leider ist dein Gerät nicht mit Expositionsbenachrichtigungen kompatibel.</string>
|
||||
<string name="pref_exposure_error_bluetooth_no_advertise_summary">Leider ist dein Gerät nicht vollständig mit Expositionsbenachrichtigungen kompatibel. Du wirst Warnungen über Risikokontakte erhalten, aber nicht andere benachrichtigen können.</string>
|
||||
<string name="prefcat_exposure_apps_title">Apps, die Expositionsbenachrichtigungen nutzen</string>
|
||||
<string name="pref_exposure_collected_rpis_title">Gesammelte IDs</string>
|
||||
<string name="pref_exposure_collected_rpis_summary"><xliff:g example="63">%1$d</xliff:g> IDs in den letzten 60 Minuten</string>
|
||||
<string name="pref_exposure_advertising_id_title">Aktuell verwendete ID</string>
|
||||
<string name="prefcat_exposure_app_report_title">Gemeldete Begegnungen</string>
|
||||
<string name="pref_exposure_app_report_updated_title">Aktualisiert: <xliff:g example="Today, 14:02">%1$s</xliff:g></string>
|
||||
<string name="pref_exposure_app_report_entry_time_short">Kürzer als 5 Minuten</string>
|
||||
<string name="pref_exposure_app_report_entry_time_about">Etwa <xliff:g example="13">%1$d</xliff:g> Minuten</string>
|
||||
<string name="pref_exposure_app_report_entry_distance_close">nahe Begegnung</string>
|
||||
<string name="pref_exposure_app_report_entry_distance_far">entfernte Begegnung</string>
|
||||
<string name="pref_exposure_app_report_entry_combined"><xliff:g example="About 12 minutes">%1$s</xliff:g>, <xliff:g example="distant exposure">%2$s</xliff:g></string>
|
||||
<string name="pref_exposure_app_last_report_summary_diagnosis_keys"><xliff:g example="121031">%1$d</xliff:g> Diagnoseschlüssel verarbeitet.</string>
|
||||
<string name="pref_exposure_app_last_report_summary_encounters_no">Keine Risiko-Begegnung erfasst.</string>
|
||||
<string name="pref_exposure_app_last_report_summary_encounters_prefix"><xliff:g example="3">%1$d</xliff:g> Risiko-Begegnungen:</string>
|
||||
<string name="pref_exposure_app_last_report_summary_encounters_line"><xliff:g example="Gestern, 12:00 - 12:30">%1$s</xliff:g>, Risiko-Level <xliff:g example="99">%2$d</xliff:g></string>
|
||||
<string name="pref_exposure_app_last_report_summary_encounters_suffix">Hinweis: Der Risiko-Level wird durch die App bestimmt. Hohe Werte können ein niedriges Risiko bedeuten oder andersherum.</string>
|
||||
<string name="pref_exposure_app_api_usage_title">Nutzung der API in den letzten 14 Tagen</string>
|
||||
<string name="pref_exposure_app_api_usage_summary_line"><xliff:g example="12">%1$d</xliff:g> Aufrufe von <xliff:g example="provideDiagnosisKeys">%2$s</xliff:g></string>
|
||||
<string name="prefcat_exposure_rpis_histogram_title"><xliff:g example="230">%1$d</xliff:g> gesammelte IDs</string>
|
||||
<string name="pref_exposure_rpis_histogram_legend_no_records">Keine Daten</string>
|
||||
<string name="pref_exposure_rpis_histogram_legend_records"><xliff:g example="0 - 50">%1$s</xliff:g> IDs pro Stunde</string>
|
||||
<string name="pref_exposure_rpi_delete_all_title">Löschen</string>
|
||||
<string name="pref_exposure_rpi_delete_all_summary">Alle gesammelten IDs löschen</string>
|
||||
<string name="pref_exposure_rpi_delete_all_warning">Nach dem Löschen der gesammelten IDs kannst du nicht mehr informiert werden, falls einer deiner Kontakte der letzten 14 Tage positiv getested wurde.</string>
|
||||
<string name="pref_exposure_rpi_delete_all_warning_confirm_button">Trotzdem löschen</string>
|
||||
<string name="pref_exposure_rpi_export_title">Exportieren</string>
|
||||
<string name="pref_exposure_rpi_export_summary">Exportiere gesammelte IDs zur weiteren Analyse mit einer anderen App.</string>
|
||||
<string name="pref_exposure_info_summary">Die API für Expositionsbenachrichtigungen ermöglicht es Apps, dich zu benachrichtigen, falls du Kontakt zu einer positiv getesteten Person hattest.
|
||||
\n
|
||||
\nDas Datum, die Zeitdauer und die Signalstärke, die dem Kontakt zugeordnet sind, werden mit der zugehörigen App geteilt.</string>
|
||||
<string name="pref_exposure_rpis_details_summary">"Während die Exposure Notification API aktiviert ist, sammelt das Gerät passiv IDs (Rolling Proximity Identifiers bzw. RPIs) von Geräten in der Nähe.
|
||||
|
||||
Sobald die Eigentümer von Geräten positiv getestet wurden, können ihre IDs geteilt werden. Dein Gerät prüft, ob eine gespeicherte ID zu einer positiv getesteten Person gehört und berechnet das Infektionsrisiko."</string>
|
||||
<string name="exposure_enable_switch">Expositionsbenachrichtigungen nutzen</string>
|
||||
<string name="exposure_confirm_start_title">Expositionsbenachrichtigungen einschalten?</string>
|
||||
<string name="exposure_confirm_start_summary">"Dein Smartphone benötigt Bluetooth, um IDs von anderen Personen sicher zu teilen und zu speichern.
|
||||
|
||||
<xliff:g example="Corona-Warn">%1$s</xliff:g> kann dich benachrichtigen, falls du Kontakt zu einer positiv getesteten Person hattest.
|
||||
|
||||
Das Datum, die Zeitdauer und die Signalstärke, die einem Kontakt zugeordnet wurden werden mit der App geteilt."</string>
|
||||
<string name="exposure_confirm_start_button">Einschalten</string>
|
||||
<string name="exposure_confirm_stop_title">Expositionsbenachrichtigungen ausschalten?</string>
|
||||
<string name="exposure_confirm_stop_summary">Nach dem Deaktivieren von Expositionsbenachrichtigungen wirst du nicht mehr benachrichtigt, falls du Kontakt mit einer positiv getesteten Person hattest.</string>
|
||||
<string name="exposure_confirm_stop_button">Deaktivieren</string>
|
||||
<string name="exposure_confirm_keys_title">IDs mit <xliff:g example="Corona-Warn">%1$s</xliff:g> teilen?</string>
|
||||
<string name="exposure_confirm_keys_summary">"Deine IDs der letzten Tage werden genutzt, um Nutzer, die in den letzten 14 Tagen mit dir Kontakt hatten, zu benachrichtigen.
|
||||
|
||||
Deine Identität oder das Testergebnis werden nicht geteilt."</string>
|
||||
<string name="exposure_confirm_keys_button">Teilen</string>
|
||||
<string name="exposure_confirm_permission_description"><xliff:g example="microG Services">%1$s</xliff:g> benötigt zusätzliche Berechtigungen.</string>
|
||||
<string name="exposure_confirm_permission_button">Erteilen</string>
|
||||
<string name="exposure_confirm_bluetooth_description">Bluetooth muss eingeschaltet sein.</string>
|
||||
<string name="exposure_confirm_location_description">Standortzugriff muss eingeschaltet sein.</string>
|
||||
<string name="exposure_confirm_button">Aktivieren</string>
|
||||
<string name="pref_exposure_error_nearby_not_granted_title">Neue Berechtigung benötigt</string>
|
||||
<string name="pref_exposure_error_nearby_not_granted_description">Tippe hier, um die erforderlichen Berechtigungen für Expositionsbenachrichtigungen zu erteilen</string>
|
||||
<string name="exposure_grant_background_location_description">Fast geschafft! Du musst den Zugriff auf den Standort im Hintergrund erlauben indem du auf dem nächsten Bildschirm \'Immer zulassen\' auswählst und dann hierher zurück kommst.</string>
|
||||
<string name="exposure_grant_background_location_button">Einstellungen Öffnen</string>
|
||||
<string name="exposure_notify_off_nearby">Expositionsbenachrichtigungen erfordern zusätzliche Berechtigungen, um zu funktionieren</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources></resources>
|
||||
65
play-services-nearby/core/src/main/res/values-es/strings.xml
Normal file
65
play-services-nearby/core/src/main/res/values-es/strings.xml
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ SPDX-FileCopyrightText: 2020, microG Project Team
|
||||
~ SPDX-License-Identifier: Apache-2.0
|
||||
--><resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="exposure_notify_off_title">Notificaciones de Exposición inactivas</string>
|
||||
<string name="exposure_notify_off_bluetooth">El Bluetooth debe estar activado para recibir notificaciones de exposición.</string>
|
||||
<string name="exposure_notify_off_location">El acceso a la ubicación es necesario para recibir las Notificaciones de Exposición.</string>
|
||||
<string name="exposure_notify_off_bluetooth_location">El acceso al Bluetooth y a la ubicación debe activarse para recibir notificaciones de exposición.</string>
|
||||
<string name="service_name_exposure">Notificaciones de Exposición</string>
|
||||
<string name="pref_exposure_enable_info_summary">Para activar las notificaciones de exposición, abra cualquier aplicación que las admita.</string>
|
||||
<string name="pref_exposure_error_bluetooth_off_title">Activar el Bluetooth</string>
|
||||
<string name="pref_exposure_error_location_off_title">Abrir Configuración de la ubicación</string>
|
||||
<string name="pref_exposure_error_bluetooth_unsupported_summary">Desafortunadamente, su dispositivo no es compatible con las Notificaciones de Exposición.</string>
|
||||
<string name="pref_exposure_error_bluetooth_no_advertise_summary">Desafortunadamente, su dispositivo solo es parcialmente compatible con las notificaciones de exposición. Puede recibir notificaciones de contactos de riesgo pero no podrá notificar a los demás.</string>
|
||||
<string name="prefcat_exposure_apps_title">Aplicaciones que utilizan Notificaciones de exposición</string>
|
||||
<string name="pref_exposure_collected_rpis_title">Identificaciones recogidas</string>
|
||||
<string name="pref_exposure_collected_rpis_summary"><xliff:g example="63">%1$d</xliff:g> identificaciones en la última hora</string>
|
||||
<string name="pref_exposure_advertising_id_title">Identificación actualmente emitida</string>
|
||||
<string name="prefcat_exposure_app_report_title">Exposiciones reportadas</string>
|
||||
<string name="pref_exposure_app_report_updated_title">Actualizado: <xliff:g example="Hoy, 14:02">%1$s</xliff:g></string>
|
||||
<string name="pref_exposure_app_report_entry_time_short">Menos de 5 minutos</string>
|
||||
<string name="pref_exposure_app_report_entry_distance_close">exposición cercana</string>
|
||||
<string name="pref_exposure_app_report_entry_distance_far">exposición lejana</string>
|
||||
<string name="pref_exposure_app_report_entry_combined"><xliff:g example="Alrededor de 12 minutes">%1$s</xliff:g>, <xliff:g example="de exposición a distancia">%2$s</xliff:g></string>
|
||||
<string name="pref_exposure_app_report_entry_time_about">Alrededor de <xliff:g example="13">%1$d</xliff:g> minutos</string>
|
||||
<string name="pref_exposure_app_last_report_summary_diagnosis_keys">Procesadas <xliff:g example="121031">%1$d</xliff:g> claves de diagnóstico.</string>
|
||||
<string name="pref_exposure_app_last_report_summary_encounters_no">No se ha informado de ningún encuentro de exposición.</string>
|
||||
<string name="pref_exposure_app_last_report_summary_encounters_prefix">Reportados <xliff:g example="3">%1$d</xliff:g> encuentros de exposición:</string>
|
||||
<string name="pref_exposure_app_last_report_summary_encounters_line"><xliff:g example="Ayer, 12:00 - 14:00">%1$s</xliff:g>, puntuación de riesgo <xliff:g example="99">%2$d</xliff:g></string>
|
||||
<string name="pref_exposure_app_last_report_summary_encounters_suffix">Nota: La puntuación de riesgo está definida por la aplicación. Los números altos pueden referirse a un riesgo bajo o viceversa.</string>
|
||||
<string name="pref_exposure_app_api_usage_title">El uso de la API en los últimos 14 días</string>
|
||||
<string name="pref_exposure_app_api_usage_summary_line"><xliff:g example="12">%1$d</xliff:g> peticiones a <xliff:g example="provideDiagnosisKeys">%2$s</xliff:g></string>
|
||||
<string name="prefcat_exposure_rpis_histogram_title"><xliff:g example="230">%1$d</xliff:g> identificaciones recogidas</string>
|
||||
<string name="pref_exposure_rpi_delete_all_title">Eliminar</string>
|
||||
<string name="pref_exposure_rpi_delete_all_summary">Eliminar todas las identificaciones recogidas</string>
|
||||
<string name="pref_exposure_rpi_delete_all_warning">Eliminar las identificaciones recogidas hará imposible notificarle en caso de que alguno de sus contactos de los últimos 14 días sea diagnosticado.</string>
|
||||
<string name="pref_exposure_rpi_delete_all_warning_confirm_button">Eliminar de todas formas</string>
|
||||
<string name="pref_exposure_rpi_export_title">Exportar</string>
|
||||
<string name="pref_exposure_rpi_export_summary">Exportar identificaciones recogidas para su análisis ampliado con otra aplicación.</string>
|
||||
<string name="pref_exposure_info_summary">La API de notificaciones de exposición permite que las aplicaciones le notifiquen si ha estado expuesto a alguien con diagnóstico positivo.\n\nLa fecha, la duración y la intensidad de la señal asociadas a una exposición se compartirán con la app correspondiente.</string>
|
||||
<string name="pref_exposure_rpis_details_summary">Mientras la API de notificación de exposición está activada, el dispositivo recopila de forma pasiva identificadores (denominados identificadores de proximidad móviles o RPI) de los dispositivos cercanos.\n\nCuando los propietarios de los dispositivos informan de un diagnóstico positivo, sus ID pueden compartirse. Su dispositivo comprueba si alguno de los ID diagnosticados conocidos coincide con alguno de los ID recopilados y calcula su riesgo de infección.</string>
|
||||
<string name="exposure_enable_switch">Usar notificaciones de exposición</string>
|
||||
<string name="exposure_confirm_start_title">¿Encender las Notificaciones de Exposición?</string>
|
||||
<string name="exposure_confirm_start_summary">El teléfono debe usar el Bluetooth para recopilar y compartir de manera segura las identificaciones con otros teléfonos que estén cerca.\n\n<xliff:g example="Corona-Warn">%1$s</xliff:g> puede notificarle si se ha expuesto a alguien que informó ser diagnosticado como positivo. La fecha, la duración y la intensidad de la señal asociadas a una exposición se compartirán con la aplicación.\"</string>
|
||||
<string name="exposure_confirm_start_button">Encender</string>
|
||||
<string name="exposure_confirm_stop_title">¿Apagar las notificaciones de exposición?</string>
|
||||
<string name="exposure_confirm_stop_summary">Después de desactivar las Notificaciones de Exposición, ya no se le notificará cuando haya estado expuesto a alguien que haya informado de que ha sido diagnosticado como positivo.</string>
|
||||
<string name="exposure_confirm_stop_button">Apagar</string>
|
||||
<string name="exposure_confirm_keys_title">¿Quiere compartir sus identificaciones con <xliff:g example="Corona-Warn">%1$s</xliff:g>\?</string>
|
||||
<string name="exposure_confirm_keys_summary">Sus identificaciones de los últimos 14 días se utilizarán para ayudar a notificar a otras personas que ha estado cerca de una posible exposición.\n\nSu identidad o el resultado de la prueba no se compartirán con otras personas.</string>
|
||||
<string name="exposure_confirm_keys_button">Compartir</string>
|
||||
<string name="exposure_confirm_permission_description"><xliff:g example="microG Services">%1$s</xliff:g> necesita permisos adicionales.</string>
|
||||
<string name="exposure_confirm_permission_button">Conceder</string>
|
||||
<string name="exposure_confirm_bluetooth_description">El Bluetooth debe estar activado.</string>
|
||||
<string name="exposure_confirm_location_description">Se requiere acceso a la ubicación.</string>
|
||||
<string name="exposure_confirm_button">Activar</string>
|
||||
<string name="exposure_grant_background_location_description">Ya casi termina. Debe activar el acceso a la ubicación en segundo plano seleccionando la opción «Permitir todo el tiempo» en la próxima pantalla. Luego vuelva aquí.</string>
|
||||
<string name="pref_exposure_rpis_histogram_legend_no_records">Sin registros</string>
|
||||
<string name="pref_exposure_rpis_histogram_legend_records"><xliff:g example="0 - 50">%1$s</xliff:g> IDs por hora</string>
|
||||
<string name="pref_exposure_error_nearby_not_granted_title">Se requieren nuevos permisos</string>
|
||||
<string name="pref_exposure_error_nearby_not_granted_description">Pulse para conceder los permisos necesarios para mostrar notificaciones</string>
|
||||
<string name="exposure_notify_off_nearby">Las notificaciones de exposición requieren permisos adicionales para funcionar</string>
|
||||
<string name="exposure_grant_background_location_button">Actualizar configuración</string>
|
||||
</resources>
|
||||
62
play-services-nearby/core/src/main/res/values-fa/strings.xml
Normal file
62
play-services-nearby/core/src/main/res/values-fa/strings.xml
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="pref_exposure_app_last_report_summary_diagnosis_keys">پردازش <xliff:g example="121031">%1$d</xliff:g> کلید تشخیص.</string>
|
||||
<string name="pref_exposure_app_last_report_summary_encounters_prefix">گزارش <xliff:g example="3">%1$d</xliff:g> مواجهه نزدیکی:</string>
|
||||
<string name="pref_exposure_app_last_report_summary_encounters_line"><xliff:g example="Yesterday, 12:00 - 14:00">%1$s</xliff:g>، امتیاز خطر <xliff:g example="99">%2$d</xliff:g></string>
|
||||
<string name="pref_exposure_app_last_report_summary_encounters_suffix">یادداشت: امتیاز خطر توسط برنامه تعریف میشود. اعداد بالا ممکن است به خطر کم یا وارون اشاره کنند.</string>
|
||||
<string name="pref_exposure_app_api_usage_title">استفاده از API در ۱۴ روز گذشته</string>
|
||||
<string name="prefcat_exposure_rpis_histogram_title"><xliff:g example="230">%1$d</xliff:g> شناسه گردآوریشده</string>
|
||||
<string name="pref_exposure_app_api_usage_summary_line"><xliff:g example="12">%1$d</xliff:g> فراخوانی به <xliff:g example="provideDiagnosisKeys">%2$s</xliff:g></string>
|
||||
<string name="pref_exposure_rpis_histogram_legend_no_records">بدون ثبت</string>
|
||||
<string name="pref_exposure_rpis_histogram_legend_records"><xliff:g example="0 - 50">%1$s</xliff:g> شناسه در ساعت</string>
|
||||
<string name="pref_exposure_rpi_delete_all_warning_confirm_button">بههرحال پاک کن</string>
|
||||
<string name="pref_exposure_rpi_export_title">برونریزی</string>
|
||||
<string name="pref_exposure_rpi_export_summary">برونریزی شناسههای گردآوریشده برای تحلیل پیشرفته با برنامه دیگر.</string>
|
||||
<string name="exposure_notify_off_nearby">آگاهسازهای نزدیکی برای کارکرد به دسترسیهای افزوده نیاز دارند</string>
|
||||
<string name="pref_exposure_advertising_id_title">شناسه در حال پخش</string>
|
||||
<string name="pref_exposure_app_last_report_summary_encounters_no">هیچ مواجهه نزدیکی گزارش نشده است.</string>
|
||||
<string name="pref_exposure_rpi_delete_all_title">پاک کردن</string>
|
||||
<string name="pref_exposure_rpi_delete_all_summary">پاک کردن همه شناسههای گردآوریشده</string>
|
||||
<string name="pref_exposure_rpi_delete_all_warning">پاک کردن شناسههای گردآوریشده، آگاهسازی شما را در صورت تشخیص مثبت یکی از تماسهای ۱۴ روز گذشته غیرممکن میکند.</string>
|
||||
<string name="exposure_enable_switch">استفاده از آگاهسازهای نزدیکی</string>
|
||||
<string name="pref_exposure_info_summary">API آگاهسازهای نزدیکی به برنامهها اجازه میدهد اگر با فردی که تشخیص مثبت گزارش کرده مواجه شدهاید، شما را آگاه کنند.\n\nتاریخ، مدت، و قدرت سیگنال مرتبط با مواجهه با برنامه مربوطه همرسانی خواهد شد.</string>
|
||||
<string name="exposure_confirm_stop_title">آگاهسازهای نزدیکی خاموش شوند؟</string>
|
||||
<string name="exposure_confirm_keys_button">همرسانی</string>
|
||||
<string name="exposure_confirm_location_description">دسترسی به مکان لازم است.</string>
|
||||
<string name="exposure_confirm_button">فعال کردن</string>
|
||||
<string name="exposure_notify_off_title">آگاهسازهای نزدیکی غیرفعال</string>
|
||||
<string name="exposure_notify_off_bluetooth">برای دریافت آگاهسازهای نزدیکی، بلوتوث باید فعال باشد.</string>
|
||||
<string name="exposure_notify_off_location">برای دریافت آگاهسازهای نزدیکی، دسترسی به مکان لازم است.</string>
|
||||
<string name="exposure_notify_off_bluetooth_location">برای دریافت آگاهسازهای نزدیکی، بلوتوث و دسترسی به مکان باید فعال باشند.</string>
|
||||
<string name="service_name_exposure">آگاهسازهای نزدیکی</string>
|
||||
<string name="pref_exposure_enable_info_summary">برای فعالسازی آگاهسازهای نزدیکی، هر برنامهای که از آن پشتیبانی میکند را باز کنید.</string>
|
||||
<string name="pref_exposure_error_bluetooth_off_title">فعالسازی بلوتوث</string>
|
||||
<string name="pref_exposure_error_location_off_title">باز کردن تنظیمات مکان</string>
|
||||
<string name="pref_exposure_error_bluetooth_unsupported_summary">متأسفانه، دستگاه شما با آگاهسازهای نزدیکی سازگار نیست.</string>
|
||||
<string name="pref_exposure_error_bluetooth_no_advertise_summary">متأسفانه، دستگاه شما تنها بهصورت جزئی با آگاهسازهای نزدیکی سازگار است. میتوانید برای تماسهای پرخطر آگاه شوید، اما نمیتوانید دیگران را آگاه کنید.</string>
|
||||
<string name="prefcat_exposure_apps_title">برنامههای استفادهکننده از آگاهسازهای نزدیکی</string>
|
||||
<string name="pref_exposure_collected_rpis_title">شناسههای گردآوریشده</string>
|
||||
<string name="pref_exposure_collected_rpis_summary"><xliff:g example="63">%1$d</xliff:g> شناسه در ساعت گذشته</string>
|
||||
<string name="prefcat_exposure_app_report_title">گزارشهای نزدیکی</string>
|
||||
<string name="pref_exposure_app_report_updated_title">بهروزرسانیشده: <xliff:g example="Today, 14:02">%1$s</xliff:g></string>
|
||||
<string name="pref_exposure_app_report_entry_time_short">کمتر از ۵ دقیقه</string>
|
||||
<string name="pref_exposure_app_report_entry_time_about">حدود <xliff:g example="13">%1$d</xliff:g> دقیقه</string>
|
||||
<string name="pref_exposure_app_report_entry_distance_close">نزدیکی نزدیک</string>
|
||||
<string name="pref_exposure_app_report_entry_distance_far">نزدیکی دور</string>
|
||||
<string name="pref_exposure_app_report_entry_combined"><xliff:g example="About 12 minutes">%1$s</xliff:g>، <xliff:g example="distant exposure">%2$s</xliff:g></string>
|
||||
<string name="exposure_confirm_start_title">آگاهسازهای نزدیکی روشن شوند؟</string>
|
||||
<string name="exposure_confirm_start_button">روشن کردن</string>
|
||||
<string name="exposure_confirm_stop_summary">پس از غیرفعال کردن آگاهسازهای نزدیکی، دیگر وقتی با فردی که تشخیص مثبت گزارش کرده مواجه شدهاید، آگاه نخواهید شد.</string>
|
||||
<string name="exposure_confirm_stop_button">خاموش کردن</string>
|
||||
<string name="exposure_confirm_keys_title">شناسههای شما با <xliff:g example="Corona-Warn">%1$s</xliff:g> همرسانی شوند؟</string>
|
||||
<string name="exposure_confirm_permission_description"><xliff:g example="microG Services">%1$s</xliff:g> به دسترسیهای افزوده نیاز دارد.</string>
|
||||
<string name="exposure_confirm_bluetooth_description">بلوتوث باید فعال باشد.</string>
|
||||
<string name="pref_exposure_error_nearby_not_granted_title">نیاز به دسترسیهای جدید</string>
|
||||
<string name="exposure_grant_background_location_description">تقریباً آماده است! باید دسترسی به مکان در پسزمینه را با انتخاب گزینه «همیشه اجازه بده» در صفحه بعدی فعال کنید. سپس بازگشت کنید.</string>
|
||||
<string name="exposure_grant_background_location_button">بهروزرسانی تنظیمات</string>
|
||||
<string name="pref_exposure_rpis_details_summary">هنگامی که API آگاهسازهای نزدیکی فعال است، دستگاه شما بهصورت غیرفعال شناسهها (بهنام شناسههای نزدیکی چرخشی یا RPIs) را از دستگاههای نزدیک گردآوری میکند\n\n وقتی صاحبان دستگاه تشخیص مثبت گزارش کنند، شناسههایشان میتوانند همرسانی شوند. دستگاه شما بررسی میکند که آیا شناسههای تشخیصشده با شناسههای گردآوریشده همخوانی دارند و خطر عفونت شما را محاسبه میکند.</string>
|
||||
<string name="exposure_confirm_start_summary">تلفن شما برای گردآوری و همرسانی امن شناسهها با تلفنهای نزدیک نیاز به استفاده از بلوتوث دارد.\n\n<xliff:g example="Corona-Warn">%1$s</xliff:g> میتواند اگر با فردی که تشخیص مثبت گزارش کرده مواجه شدهاید، شما را آگاه کند.\n\nتاریخ، مدت، و قدرت سیگنال مرتبط با مواجهه با برنامه همرسانی خواهد شد.</string>
|
||||
<string name="exposure_confirm_keys_summary">شناسههای شما از ۱۴ روز گذشته برای کمک به آگاهسازی دیگران که نزدیک شما بودهاند درباره مواجهه احتمالی استفاده خواهند شد.\n\nهویت یا نتیجه آزمایش شما با دیگران همرسانی نخواهد شد.</string>
|
||||
<string name="pref_exposure_error_nearby_not_granted_description">برای دادن دسترسیهای لازم به آگاهسازهای نزدیکی بزنید</string>
|
||||
<string name="exposure_confirm_permission_button">دادن</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources></resources>
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources></resources>
|
||||
68
play-services-nearby/core/src/main/res/values-fr/strings.xml
Normal file
68
play-services-nearby/core/src/main/res/values-fr/strings.xml
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="exposure_notify_off_title">Notifications d\'exposition inactives</string>
|
||||
<string name="pref_exposure_error_bluetooth_no_advertise_summary">Malheureusement, votre appareil est seulement partiellement compatible avec les notifications d\'exposition. Vous pouvez être notifié des contacts à risque mais vous ne pourrez pas notifier les autres.</string>
|
||||
<string name="pref_exposure_collected_rpis_summary"><xliff:g example="63">%1$d</xliff:g> IDs dans la dernière heure</string>
|
||||
<string name="exposure_notify_off_bluetooth">Le Bluetooth doit être activé pour recevoir les notifications d\'exposition.</string>
|
||||
<string name="exposure_notify_off_location">L\'accès à la localisation est nécessaire pour recevoir les notifications d\'exposition.</string>
|
||||
<string name="exposure_notify_off_bluetooth_location">Le Bluetooth et l\'accès à la localisation doivent être activés pour recevoir les notifications d\'exposition.</string>
|
||||
<string name="exposure_notify_off_nearby">Les notifications d\'exposition nécessitent des permissions additionnelles pour fonctionner</string>
|
||||
<string name="service_name_exposure">Notifications d\'exposition</string>
|
||||
<string name="pref_exposure_error_location_off_title">Ouvrir les paramètres de localisation</string>
|
||||
<string name="pref_exposure_error_bluetooth_off_title">Activer le Bluetooth</string>
|
||||
<string name="pref_exposure_enable_info_summary">Pour activer les notifications d\'exposition, ouvrez une appli les prenant en charge.</string>
|
||||
<string name="pref_exposure_error_bluetooth_unsupported_summary">Malheureusement, votre appareil n\'est pas compatible avec les notifications d\'exposition.</string>
|
||||
<string name="prefcat_exposure_apps_title">Applis utilisant les notifications d\'exposition</string>
|
||||
<string name="pref_exposure_collected_rpis_title">IDs collectés</string>
|
||||
<string name="pref_exposure_app_report_entry_time_about">Il y a <xliff:g example="13">%1$d</xliff:g> minutes environ</string>
|
||||
<string name="pref_exposure_app_last_report_summary_diagnosis_keys">Traité <xliff:g example="121031">%1$d</xliff:g> clés de diagnostic.</string>
|
||||
<string name="pref_exposure_app_last_report_summary_encounters_prefix"><xliff:g example="3">%1$d</xliff:g> expositions à risque rapportées :</string>
|
||||
<string name="exposure_confirm_keys_title">Partager vos IDs avec <xliff:g example="Corona-Warn">%1$s</xliff:g> ?</string>
|
||||
<string name="exposure_confirm_permission_description"><xliff:g example="microG Services">%1$s</xliff:g> nécessite des autorisations supplémentaires.</string>
|
||||
<string name="pref_exposure_app_report_updated_title">Mis à jour : <xliff:g example="Aujourd'hui, 14:02">%1$s</xliff:g></string>
|
||||
<string name="pref_exposure_app_report_entry_combined"><xliff:g example="Il y a 12 minutes environ">%1$s</xliff:g>, <xliff:g example="exposition distante">%2$s</xliff:g></string>
|
||||
<string name="pref_exposure_rpis_histogram_legend_records"><xliff:g example="0 - 50">%1$s</xliff:g> IDs par heure</string>
|
||||
<string name="pref_exposure_app_last_report_summary_encounters_line"><xliff:g example="Hier, 12:00 - 14:00">%1$s</xliff:g>, score de risque<xliff:g example="99">%2$d</xliff:g></string>
|
||||
<string name="pref_exposure_app_api_usage_summary_line"><xliff:g example="12">%1$d</xliff:g> appelle à <xliff:g example="provideDiagnosisKeys">%2$s</xliff:g></string>
|
||||
<string name="prefcat_exposure_rpis_histogram_title"><xliff:g example="230">%1$d</xliff:g> IDs collectés</string>
|
||||
<string name="exposure_confirm_start_summary">Votre téléphone a besoin d\'utiliser le Bluetooth pour collecter et partager de manière sécurisée les IDs avec les autres appareils à proximité.\n\n<xliff:g example="Corona-Warn">%1$s</xliff:g> peut vous notifier si vous avez été exposé à une personne ayant indiqué un diagnostic positif. \n\nLa date, la durée et la force du signal liées à une exposition seront partagées avec cette application.</string>
|
||||
<string name="exposure_confirm_stop_summary">En désactivant les Notifications d’exposition, vous ne serez plus informé si vous avez été exposé à une personne ayant indiqué un diagnostic positif.</string>
|
||||
<string name="exposure_confirm_button">Activer</string>
|
||||
<string name="pref_exposure_error_nearby_not_granted_title">Nouvelles autorisations nécessaires</string>
|
||||
<string name="pref_exposure_advertising_id_title">ID actuellement diffusé</string>
|
||||
<string name="pref_exposure_app_report_entry_time_short">Moins de 5 minutes</string>
|
||||
<string name="pref_exposure_app_report_entry_distance_far">Exposition distante</string>
|
||||
<string name="pref_exposure_app_report_entry_distance_close">Exposition proche</string>
|
||||
<string name="pref_exposure_error_nearby_not_granted_description">Appuyez pour accorder les autorisations nécessaires aux Notifications d\'exposition</string>
|
||||
<string name="prefcat_exposure_app_report_title">Expositions rapportées</string>
|
||||
<string name="pref_exposure_app_last_report_summary_encounters_no">Pas de rencontres à risque rapportées.</string>
|
||||
<string name="pref_exposure_app_api_usage_title">Usage de l\'API sur les 14 derniers jours</string>
|
||||
<string name="pref_exposure_app_last_report_summary_encounters_suffix">Note : Le score de risque est défini par l\'appli. Une valeur élevée peut faire référence à un risque faible et vice-versa.</string>
|
||||
<string name="pref_exposure_rpis_histogram_legend_no_records">Pas d\'enregistrements</string>
|
||||
<string name="pref_exposure_rpi_delete_all_title">Supprimer</string>
|
||||
<string name="pref_exposure_rpi_delete_all_summary">Supprimer tous les IDs collectés</string>
|
||||
<string name="pref_exposure_rpi_delete_all_warning">La suppression des IDs collectés rendra impossible de vous informer en cas de diagnostic positif d\'un contact sur les 14 derniers jours.</string>
|
||||
<string name="pref_exposure_rpi_delete_all_warning_confirm_button">Supprimer quand même</string>
|
||||
<string name="pref_exposure_rpi_export_title">Exporter</string>
|
||||
<string name="pref_exposure_rpi_export_summary">Exporter les IDs collectés pour analyse étendue via une autre appli.</string>
|
||||
<string name="pref_exposure_info_summary">L\'API Notifications d\'exposition permet aux applis de vous informer si vous avez été exposé à une personne ayant indiqué un diagnostique positif.
|
||||
\n
|
||||
\nLa date, la durée et la force du signal liées à une exposition seront partagées avec l\'appli correspondante.</string>
|
||||
<string name="pref_exposure_rpis_details_summary">Quand l\'API Notifications d\'exposition est activée, votre appareil collecte de manière passive les IDs (appelés identifiants roulants de proximité) des appareils à proximité.
|
||||
\n
|
||||
\nLorsque des utilisateurs indiquent un diagnostic positif, leur ID peut être partagé. Votre appareil compare les IDs collectés aux IDs diagnostiqués positifs connus et calcule votre risque d\'infection.</string>
|
||||
<string name="exposure_enable_switch">Utiliser les Notifications d\'exposition</string>
|
||||
<string name="exposure_confirm_start_title">Activer les Notifications d\'exposition ?</string>
|
||||
<string name="exposure_confirm_start_button">Activer</string>
|
||||
<string name="exposure_confirm_stop_title">Désactiver les Notifications d\'exposition ?</string>
|
||||
<string name="exposure_confirm_stop_button">Désactiver</string>
|
||||
<string name="exposure_confirm_keys_summary">Vos IDs des 14 derniers jours seront utilisés dans le but d\'informer les autres que vous avez été proche d\'une exposition potentielle.
|
||||
\n
|
||||
\nVotre identité ou vos résultats de test ne seront pas partagés avec d\'autres personnes.</string>
|
||||
<string name="exposure_confirm_keys_button">Partager</string>
|
||||
<string name="exposure_confirm_permission_button">Accorder</string>
|
||||
<string name="exposure_confirm_bluetooth_description">Le Bluetooth doit être activé.</string>
|
||||
<string name="exposure_confirm_location_description">L\'accès à la localisation est nécessaire.</string>
|
||||
<string name="exposure_grant_background_location_description">On y est presque ! Vous aurez besoin d\'activer la localisation en arrière-plan en sélectionnant \"Toujours autorisé\" sur l\'écran suivant. Puis revenez en arrière.</string>
|
||||
<string name="exposure_grant_background_location_button">Modifier les paramètres</string>
|
||||
</resources>
|
||||
68
play-services-nearby/core/src/main/res/values-ga/strings.xml
Normal file
68
play-services-nearby/core/src/main/res/values-ga/strings.xml
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="pref_exposure_error_bluetooth_unsupported_summary">Ar an drochuair, níl do ghléas comhoiriúnach le Fógraí Nochta.</string>
|
||||
<string name="pref_exposure_collected_rpis_title">Aitheantas bailithe</string>
|
||||
<string name="pref_exposure_app_report_entry_distance_close">nochtadh in aice láimhe</string>
|
||||
<string name="pref_exposure_app_report_entry_distance_far">nochtadh i bhfad i gcéin</string>
|
||||
<string name="pref_exposure_app_last_report_summary_diagnosis_keys">Próiseáladh <xliff:g example="121031">%1$d</xliff:g> eochracha diagnóis.</string>
|
||||
<string name="pref_exposure_app_last_report_summary_encounters_no">Níor tuairiscíodh aon teagmháil nochta.</string>
|
||||
<string name="prefcat_exposure_rpis_histogram_title"><xliff:g example="230">%1$d</xliff:g> IDs bailithe</string>
|
||||
<string name="pref_exposure_rpi_delete_all_summary">Scrios gach aitheantas bailithe</string>
|
||||
<string name="pref_exposure_rpi_delete_all_warning_confirm_button">Scrios mar sin féin</string>
|
||||
<string name="exposure_confirm_start_button">Cas ar</string>
|
||||
<string name="exposure_confirm_stop_title">An bhfuil fonn ort Fógraí Nochta a mhúchadh?</string>
|
||||
<string name="exposure_confirm_stop_summary">Tar éis Fógraí Nochta a dhíchumasú, ní thabharfar fógra duit a thuilleadh nuair a nochtaíodh tú do dhuine a thuairiscigh go raibh diagnóis deimhneach aige.</string>
|
||||
<string name="exposure_confirm_bluetooth_description">Ní mór Bluetooth a chumasú.</string>
|
||||
<string name="pref_exposure_error_nearby_not_granted_description">Tapáil chun na ceadanna riachtanacha d\'Fhógraí Nochta a dheonú</string>
|
||||
<string name="pref_exposure_info_summary">Ligeann API Fógraí Nochta aipeanna fógra a thabhairt duit má bhí tú nochta do dhuine a thuairiscigh go raibh diagnóis deimhneach aige.
|
||||
\n
|
||||
\nRoinnfear an dáta, an fad agus an neart comhartha a bhaineann le nochtadh leis an aip chomhfhreagrach.</string>
|
||||
<string name="exposure_notify_off_bluetooth">Ní mór Bluetooth a chumasú chun Fógraí Nochta a fháil.</string>
|
||||
<string name="exposure_notify_off_title">Fógraí Nochta neamhghníomhach</string>
|
||||
<string name="exposure_notify_off_location">Teastaíonn rochtain ar shuíomh chun Fógraí Nochta a fháil.</string>
|
||||
<string name="exposure_notify_off_bluetooth_location">Ní mór rochtain Bluetooth agus Suíomh a chumasú chun Fógraí Nochta a fháil.</string>
|
||||
<string name="service_name_exposure">Fógraí Nochta</string>
|
||||
<string name="exposure_notify_off_nearby">Teastaíonn ceadanna breise ó Fhógraí Nochta chun oibriú</string>
|
||||
<string name="pref_exposure_error_bluetooth_off_title">Cumasaigh Bluetooth</string>
|
||||
<string name="pref_exposure_enable_info_summary">Chun Fógraí Nochta a chumasú, oscail aon aip a thacaíonn leis.</string>
|
||||
<string name="pref_exposure_error_location_off_title">Oscail socruithe Suíomh</string>
|
||||
<string name="pref_exposure_app_api_usage_summary_line">Glaonn <xliff:g example="12">%1$d</xliff:g> chuig <xliff:g example="soláthraighEochrachaDiagnóisithe">%2$s</xliff:g></string>
|
||||
<string name="pref_exposure_error_bluetooth_no_advertise_summary">Ar an drochuair, níl do ghléas comhoiriúnach ach go páirteach le Fógraí Nochta. Is féidir tú a chur ar an eolas le haghaidh teagmhálaithe riosca ach ní bheidh tú in ann fógra a thabhairt do dhaoine eile.</string>
|
||||
<string name="prefcat_exposure_apps_title">Aipeanna a úsáideann Fógraí Nochta</string>
|
||||
<string name="pref_exposure_collected_rpis_summary"><xliff:g example="63">%1$d</xliff:g> aitheantais san uair dheireanach</string>
|
||||
<string name="pref_exposure_advertising_id_title">Aitheantas arna chraoladh faoi láthair</string>
|
||||
<string name="prefcat_exposure_app_report_title">Nochtuithe tuairiscithe</string>
|
||||
<string name="pref_exposure_app_report_updated_title">Nuashonraithe: <xliff:g example="Inniu, 14:02">%1$s</xliff:g></string>
|
||||
<string name="pref_exposure_app_report_entry_time_short">Níos lú ná 5 nóiméad</string>
|
||||
<string name="pref_exposure_app_report_entry_time_about">Timpeall <xliff:g example="13">%1$d</xliff:g> nóiméad</string>
|
||||
<string name="pref_exposure_app_report_entry_combined"><xliff:g example="Thart ar 12 nóiméad">%1$s</xliff:g>, <xliff:g example="nochtadh i bhfad i gcéin">%2$s</xliff:g></string>
|
||||
<string name="pref_exposure_app_last_report_summary_encounters_prefix">Tuairiscíodh gur tharla nochtadh <xliff:g example="3">%1$d</xliff:g>:</string>
|
||||
<string name="pref_exposure_app_last_report_summary_encounters_line"><xliff:g example="Inné, 12:00 - 14:00">%1$s</xliff:g>, scór riosca <xliff:g example="99">%2$d</xliff:g></string>
|
||||
<string name="pref_exposure_rpis_histogram_legend_no_records">Uimh taifid</string>
|
||||
<string name="pref_exposure_app_last_report_summary_encounters_suffix">Nóta: Tá an scór riosca sainmhínithe ag an app. Is féidir le huimhreacha arda tagairt do riosca íseal nó vice-versa.</string>
|
||||
<string name="pref_exposure_app_api_usage_title">Úsáid API le 14 lá anuas</string>
|
||||
<string name="exposure_confirm_start_title">Cuir Fógraí Nochta ar siúl?</string>
|
||||
<string name="exposure_confirm_keys_title">Comhroinn do chuid aitheantais le <xliff:g example="Corona-Warn">%1$s</xliff:g>\?</string>
|
||||
<string name="exposure_confirm_keys_button">Comhroinn</string>
|
||||
<string name="exposure_confirm_permission_description">Tá ceadanna breise ag teastáil ó <xliff:g example="MicroG Services">%1$s</xliff:g>.</string>
|
||||
<string name="exposure_confirm_permission_button">Deontas</string>
|
||||
<string name="pref_exposure_error_nearby_not_granted_title">Ceadanna Nua ag teastáil</string>
|
||||
<string name="pref_exposure_rpis_histogram_legend_records"><xliff:g example="0 - 50">%1$s</xliff:g> aitheantais in aghaidh na huaire</string>
|
||||
<string name="pref_exposure_rpi_delete_all_title">Scrios</string>
|
||||
<string name="pref_exposure_rpi_export_title">Easpórtáil</string>
|
||||
<string name="exposure_confirm_start_summary">Caithfidh do ghuthán Bluetooth a úsáid chun aitheantóirí a bhailiú agus a roinnt go slán le fóin eile atá in aice láimhe.\n\nIs féidir le <xliff:g example="Corona-Warn">%1$s</xliff:g> fógra a thabhairt duit má bhí tú nochtaithe do dhuine a thuairiscigh go raibh diagnóis dhearfach aige.\n\nRoinnfear an dáta, an fad agus neart an chomhartha a bhaineann le nochtadh leis an aip.</string>
|
||||
<string name="exposure_confirm_keys_summary">Úsáidfear d\'aitheantais le 14 lá anuas chun cabhrú le daoine eile a chur ar an eolas go raibh tú gar do nochtadh féideartha.
|
||||
\n
|
||||
\nNí roinnfear d\'aitheantas nó toradh tástála le daoine eile.</string>
|
||||
<string name="exposure_confirm_location_description">Tá rochtain suímh ag teastáil.</string>
|
||||
<string name="exposure_confirm_button">Cumasaigh</string>
|
||||
<string name="exposure_grant_background_location_description">Beagnach ann! Beidh ort rochtain ar shuíomh cúlra a chumasú tríd an rogha \'Ceadaigh an t-am ar fad\' a roghnú ar an gcéad scáileán eile. Ansin brúigh ar ais.</string>
|
||||
<string name="exposure_grant_background_location_button">Nuashonraigh Socruithe</string>
|
||||
<string name="pref_exposure_rpi_delete_all_warning">Má scriosann tú na haitheantais a bailíodh ní bheidh sé indéanta fógra a thabhairt duit i gcás go ndéanfar diagnóis ar aon duine de do theagmhálaithe le 14 lá anuas.</string>
|
||||
<string name="pref_exposure_rpi_export_summary">Easpórtáil aitheantais bailithe le haghaidh anailíse leathnaithe le haip eile.</string>
|
||||
<string name="pref_exposure_rpis_details_summary">Cé go bhfuil an API Fógra Nochtadh cumasaithe, bailíonn do ghléas aitheantais go héighníomhach (ar a dtugtar Aitheantóirí Cóngaracht Rollta, nó RPIanna) ó ghléasanna in aice láimhe.
|
||||
\n
|
||||
\nNuair a thuairiscíonn úinéirí gléasanna go bhfuil siad dearfach, is féidir a n-aitheantais a roinnt. Seiceálann do ghléas má mheaitseálann aon cheann de na haitheantais aitheanta aon cheann de na haitheantais a bailíodh agus ríomhann sé do riosca ionfhabhtaithe.</string>
|
||||
<string name="exposure_enable_switch">Úsáid Fógraí Nochta</string>
|
||||
<string name="exposure_confirm_stop_button">Múch</string>
|
||||
</resources>
|
||||
62
play-services-nearby/core/src/main/res/values-in/strings.xml
Normal file
62
play-services-nearby/core/src/main/res/values-in/strings.xml
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="exposure_notify_off_title">Notifikasi Paparan tidak aktif</string>
|
||||
<string name="exposure_notify_off_bluetooth">Bluetooth harus diaktifkan untuk menerima Notifikasi Paparan.</string>
|
||||
<string name="exposure_notify_off_location">Akses lokasi diperlukan untuk menerima Pemberitahuan Paparan.</string>
|
||||
<string name="exposure_notify_off_bluetooth_location">Bluetooth dan akses lokasi harus diaktifkan untuk menerima pemberitahuan paparan.</string>
|
||||
<string name="exposure_notify_off_nearby">Pemberitahuan Paparan memerlukan izin tambahan untuk berfungsi</string>
|
||||
<string name="service_name_exposure">Pemberitahuan Paparan</string>
|
||||
<string name="pref_exposure_enable_info_summary">Untuk mengaktifkan Pemberitahuan Paparan, buka aplikasi apa pun yang mendukung fitur ini.</string>
|
||||
<string name="pref_exposure_error_bluetooth_off_title">Aktifkan Bluetooth</string>
|
||||
<string name="pref_exposure_error_location_off_title">Buka Pengaturan Lokasi</string>
|
||||
<string name="pref_exposure_error_bluetooth_unsupported_summary">Sayangnya, perangkat Anda tidak kompatibel dengan Pemberitahuan Paparan.</string>
|
||||
<string name="pref_exposure_error_bluetooth_no_advertise_summary">Sayangnya, perangkat Anda hanya kompatibel sebagian dengan Pemberitahuan Paparan. Anda dapat menerima pemberitahuan untuk kontak berisiko, tetapi tidak dapat memberitahu orang lain.</string>
|
||||
<string name="prefcat_exposure_apps_title">Aplikasi yang menggunakan Pemberitahuan Paparan</string>
|
||||
<string name="pref_exposure_collected_rpis_title">ID yang dikumpulkan</string>
|
||||
<string name="pref_exposure_collected_rpis_summary"><xliff:g example="63">%1$d</xliff:g> ID dalam satu jam terakhir</string>
|
||||
<string name="pref_exposure_advertising_id_title">Saat ini ditayangkan ID</string>
|
||||
<string name="prefcat_exposure_app_report_title">Paparan yang dilaporkan</string>
|
||||
<string name="pref_exposure_app_report_updated_title">Diperbarui: <xliff:g example="Hari ini, 14:02">%1$s</xliff:g></string>
|
||||
<string name="pref_exposure_app_report_entry_time_short">Kurang dari 5 menit</string>
|
||||
<string name="pref_exposure_app_report_entry_time_about">Sekitar <xliff:g example="13">%1$d</xliff:g> menit</string>
|
||||
<string name="pref_exposure_app_report_entry_distance_close">paparan di sekitar</string>
|
||||
<string name="pref_exposure_app_report_entry_distance_far">paparan jarak jauh</string>
|
||||
<string name="pref_exposure_app_report_entry_combined"><xliff:g contoh="Sekitar 12 menit">%1$s</xliff:g>, <xliff:g contoh="paparan jarak jauh">%2$s</xliff:g></string>
|
||||
<string name="pref_exposure_app_last_report_summary_diagnosis_keys">Kunci diagnosis yang diproses <xliff:g example="121031">%1$d</xliff:g>.</string>
|
||||
<string name="pref_exposure_app_last_report_summary_encounters_no">Tidak ada laporan tentang paparan yang terjadi.</string>
|
||||
<string name="pref_exposure_app_last_report_summary_encounters_prefix">Dilaporkan <xliff:g example="3">%1$d</xliff:g> insiden paparan:</string>
|
||||
<string name="pref_exposure_app_last_report_summary_encounters_line"><xliff:g example="Kemarin, 12:00 - 14:00">%1$s</xliff:g>, skor risiko <xliff:g example="99">%2$d</xliff:g></string>
|
||||
<string name="pref_exposure_app_last_report_summary_encounters_suffix">Catatan: Skor risiko ditentukan oleh aplikasi. Angka yang tinggi dapat mengacu pada risiko rendah atau sebaliknya.</string>
|
||||
<string name="pref_exposure_app_api_usage_title">Penggunaan API dalam 14 hari terakhir</string>
|
||||
<string name="pref_exposure_app_api_usage_summary_line"><xliff:g example="12">%1$d</xliff:g> panggilan ke <xliff:g example="provideDiagnosisKeys">%2$s</xliff:g></string>
|
||||
<string name="prefcat_exposure_rpis_histogram_title"><xliff:g example="230">%1$d</xliff:g> ID yang dikumpulkan</string>
|
||||
<string name="pref_exposure_rpis_histogram_legend_no_records">Tidak ada catatan</string>
|
||||
<string name="pref_exposure_rpis_histogram_legend_records"><xliff:g example="0 - 50">%1$s</xliff:g> ID per jam</string>
|
||||
<string name="pref_exposure_rpi_delete_all_title">Hapus</string>
|
||||
<string name="pref_exposure_rpi_delete_all_summary">Hapus semua ID yang telah dikumpulkan</string>
|
||||
<string name="pref_exposure_rpi_delete_all_warning">Menghapus ID yang telah dikumpulkan akan membuat kami tidak dapat memberitahu Anda jika salah satu kontak Anda dalam 14 hari terakhir didiagnosis.</string>
|
||||
<string name="pref_exposure_rpi_delete_all_warning_confirm_button">Hapus saja</string>
|
||||
<string name="pref_exposure_rpi_export_title">Ekspor</string>
|
||||
<string name="pref_exposure_rpi_export_summary">Ekspor ID yang telah dikumpulkan untuk analisis lebih lanjut menggunakan aplikasi lain.</string>
|
||||
<string name="pref_exposure_info_summary">API Pemberitahuan Paparan memungkinkan aplikasi untuk memberi tahu Anda jika Anda terpapar dengan seseorang yang dilaporkan telah didiagnosis positif.\n\nTanggal, durasi, dan kekuatan sinyal yang terkait dengan paparan akan dibagikan dengan aplikasi yang bersangkutan.</string>
|
||||
<string name="pref_exposure_rpis_details_summary">Saat API Pemberitahuan Paparan diaktifkan, perangkat Anda secara pasif mengumpulkan ID (yang disebut Rolling Proximity Identifiers, atau RPIs) dari perangkat terdekat.\n\nKetika pemilik perangkat melaporkan bahwa mereka telah didiagnosis positif, ID mereka dapat dibagikan. Perangkat Anda memeriksa apakah ada ID yang telah didiagnosis positif yang cocok dengan ID yang dikumpulkan dan menghitung risiko infeksi Anda.</string>
|
||||
<string name="exposure_enable_switch">Gunakan Pemberitahuan Paparan</string>
|
||||
<string name="exposure_confirm_start_title">Aktifkan Pemberitahuan Paparan?</string>
|
||||
<string name="exposure_confirm_start_summary">Ponsel Anda perlu menggunakan Bluetooth untuk mengumpulkan dan berbagi ID secara aman dengan ponsel lain yang berada di dekatnya.\n\n<xliff:g example="Corona-Warn">%1$s</xliff:g> dapat memberi tahu Anda jika Anda terpapar dengan seseorang yang dilaporkan positif terinfeksi.\n\nTanggal, durasi, dan kekuatan sinyal yang terkait dengan paparan akan dibagikan dengan aplikasi.</string>
|
||||
<string name="exposure_confirm_start_button">Nyalakan</string>
|
||||
<string name="exposure_confirm_stop_title">Mematikan Pemberitahuan Paparan?</string>
|
||||
<string name="exposure_confirm_stop_summary">Setelah menonaktifkan Pemberitahuan Paparan, Anda tidak akan lagi menerima pemberitahuan ketika Anda terpapar dengan seseorang yang dilaporkan telah didiagnosis positif.</string>
|
||||
<string name="exposure_confirm_stop_button">Matikan</string>
|
||||
<string name="exposure_confirm_keys_title">Bagikan ID Anda dengan <xliff:g example="Corona-Warn">%1$s</xliff:g>\?</string>
|
||||
<string name="exposure_confirm_keys_summary">ID Anda dari 14 hari terakhir akan digunakan untuk membantu memberitahu orang lain bahwa Anda pernah berada di dekat mereka terkait potensi paparan.\n\nIdentitas atau hasil tes Anda tidak akan dibagikan kepada orang lain.</string>
|
||||
<string name="exposure_confirm_keys_button">Bagikan</string>
|
||||
<string name="exposure_confirm_permission_description"><xliff:g example="microG Services">%1$s</xliff:g> memerlukan izin tambahan.</string>
|
||||
<string name="exposure_confirm_permission_button">Berikan</string>
|
||||
<string name="exposure_confirm_bluetooth_description">Bluetooth harus diaktifkan.</string>
|
||||
<string name="exposure_confirm_location_description">Akses lokasi diperlukan.</string>
|
||||
<string name="exposure_confirm_button">Aktifkan</string>
|
||||
<string name="pref_exposure_error_nearby_not_granted_title">Izin baru diperlukan</string>
|
||||
<string name="pref_exposure_error_nearby_not_granted_description">Ketuk untuk memberikan izin yang diperlukan untuk Pemberitahuan Paparan</string>
|
||||
<string name="exposure_grant_background_location_description">Sudah hampir selesai! Anda perlu mengaktifkan akses lokasi latar belakang dengan memilih opsi ‘Izinkan sepanjang waktu’ pada layar berikutnya. Kemudian tekan tombol kembali.</string>
|
||||
<string name="exposure_grant_background_location_button">Perbarui Pengaturan</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources></resources>
|
||||
65
play-services-nearby/core/src/main/res/values-it/strings.xml
Normal file
65
play-services-nearby/core/src/main/res/values-it/strings.xml
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ SPDX-FileCopyrightText: 2020, microG Project Team
|
||||
~ SPDX-License-Identifier: Apache-2.0
|
||||
--><resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="exposure_notify_off_title">Notifiche di esposizione al virus non attive</string>
|
||||
<string name="exposure_notify_off_bluetooth">Il Bluetooth dev\'essere attivato per poter ricevere le notifiche di esposizione al virus.</string>
|
||||
<string name="exposure_notify_off_location">È necessario attivare la geolocalizzazione per poter ricevere le notifiche di esposizione al virus.</string>
|
||||
<string name="exposure_notify_off_bluetooth_location">È necessario attivare il Bluetooth e la geolocalizzazione per poter ricevere le notifiche di esposizione al virus.</string>
|
||||
<string name="exposure_notify_off_nearby">Le notifiche di esposizione al virus richiedono ulteriori permessi per funzionare</string>
|
||||
<string name="service_name_exposure">Notifiche di esposizione al virus</string>
|
||||
<string name="pref_exposure_enable_info_summary">Per abilitare le notifiche di esposizione al virus, apri qualsiasi applicazione che le supporti.</string>
|
||||
<string name="prefcat_exposure_apps_title">Applicazioni che utilizzano le notifiche di esposizione al virus</string>
|
||||
<string name="pref_exposure_collected_rpis_title">Identificativi univoci raccolti</string>
|
||||
<string name="pref_exposure_collected_rpis_summary"><xliff:g example="63">%1$d</xliff:g> identificativi univoci nell\'ultima ora</string>
|
||||
<string name="pref_exposure_advertising_id_title">Identificativi univoci attualmente trasmessi</string>
|
||||
<string name="pref_exposure_app_last_report_summary_diagnosis_keys">Processate <xliff:g example="121031">%1$d</xliff:g> chiavi di diagnosi.</string>
|
||||
<string name="pref_exposure_app_last_report_summary_encounters_no">Nessuna esposizione al virus riscontrata.</string>
|
||||
<string name="pref_exposure_app_last_report_summary_encounters_prefix">Riscontrate <xliff:g example="3">%1$d</xliff:g> esposizioni:</string>
|
||||
<string name="pref_exposure_app_last_report_summary_encounters_line"><xliff:g example="Yesterday, 12:00 - 14:00">%1$s</xliff:g>, punteggio di rischio <xliff:g example="99">%2$d</xliff:g></string>
|
||||
<string name="pref_exposure_app_last_report_summary_encounters_suffix">Nota: Il punteggio di rischio è definito dall\'applicazione. Punteggi elevati possono riferirsi a un rischio basso o viceversa.</string>
|
||||
<string name="pref_exposure_app_api_usage_title">Utilizzo della API negli ultimi 14 giorni</string>
|
||||
<string name="pref_exposure_app_api_usage_summary_line"><xliff:g example="12">%1$d</xliff:g> chiamate a <xliff:g example="provideDiagnosisKeys">%2$s</xliff:g></string>
|
||||
<string name="prefcat_exposure_rpis_histogram_title"><xliff:g example="230">%1$d</xliff:g> identificativi univoci raccolti</string>
|
||||
<string name="pref_exposure_rpi_delete_all_warning">Eliminando tutti gli identificativi univoci raccolti non sarà possibile notificarti nel caso in cui uno dei tuoi contatti degli ultimi 14 giorni sia stato diagnosticato positivo al virus.</string>
|
||||
<string name="pref_exposure_rpi_delete_all_warning_confirm_button">Elimina comunque</string>
|
||||
<string name="pref_exposure_info_summary">L\'API per le notifiche di esposizione al virus permette alle applicazioni di notificarti nel caso in cui tu sia stato esposto a qualcuno che ha riportato di essere stato diagnosticato positivo al virus.\n\nData, durata e potenza del segnale associati a una esposizione verranno condivisi con l\'applicazione relativa.</string>
|
||||
<string name="pref_exposure_rpis_details_summary">Quando l\'API per le notifiche di esposizione al virus è abilitata, il tuo dispositivo raccoglie passivamente degli identificativi univoci (chiamati Identificatori di Prossimità a Rotazione, o RPI) dai dispositivi vicini.\n\nQuando i possessori dei dispositivi riportano di essere stati diagnosticati positivi al virus, i loro identificativi univoci possono essere condivisi. Il tuo dispositivo verifica se tra gli identificativi univoci diagnosticati positivi al virus vi sono corrispondenze con quelli raccolti e calcola il tuo punteggio di rischio.</string>
|
||||
<string name="exposure_enable_switch">Utilizza le notifiche di esposizione al virus</string>
|
||||
<string name="exposure_confirm_start_title">Abilitare le notifiche di esposizione al virus?</string>
|
||||
<string name="exposure_confirm_start_summary">Il tuo dispositivo richiede l\'utilizzo del Bluetooth per raccogliere e condividere in modo sicuro gli identificativi univoci con altri dispositivi vicini.\n\n<xliff:g example="Corona-Warn">%1$s</xliff:g> può notificarti nel caso in cui tu sia stato esposto a qualcuno che ha riportato di essere stato diagnosticato positivo al virus.\n\nData, durata e potenza del segnale associati a una esposizione al virus verranno condivisi con l\'applicazione.</string>
|
||||
<string name="exposure_confirm_start_button">Abilita</string>
|
||||
<string name="exposure_confirm_stop_title">Disabilitare le notifiche di esposizione al virus?</string>
|
||||
<string name="exposure_confirm_stop_summary">Dopo aver disabilitato le notifiche di esposizione al virus, non verrai più notificato nel caso in cui tu sia stato esposto a qualcuno che ha riportato di essere stato diagnosticato positivo.</string>
|
||||
<string name="exposure_confirm_stop_button">Disabilita</string>
|
||||
<string name="exposure_confirm_keys_title">Vuoi condividere i tuoi identificativi univoci con <xliff:g example="Corona-Warn">%1$s</xliff:g>?</string>
|
||||
<string name="exposure_confirm_keys_summary">I tuoi identificativi univoci degli ultimi 14 giorni saranno utilizzati per aiutare a notificare altri se sei stato potenzialmente esposto al virus.\n\nLa tua identità o il risultato del test non saranno condivisi con altre persone.</string>
|
||||
<string name="exposure_confirm_keys_button">Condividi</string>
|
||||
<string name="exposure_confirm_permission_description"><xliff:g example="microG Services">%1$s</xliff:g> richiede ulteriori permessi.</string>
|
||||
<string name="exposure_confirm_permission_button">Consenti</string>
|
||||
<string name="pref_exposure_rpi_delete_all_summary">Elimina tutti gli identificativi univoci raccolti</string>
|
||||
<string name="pref_exposure_rpi_delete_all_title">Elimina</string>
|
||||
<string name="pref_exposure_rpi_export_title">Esporta</string>
|
||||
<string name="exposure_confirm_button">Attiva</string>
|
||||
<string name="pref_exposure_error_bluetooth_off_title">Attiva il Bluetooth</string>
|
||||
<string name="exposure_confirm_bluetooth_description">Il Bluetooth dev\'essere attivato.</string>
|
||||
<string name="pref_exposure_app_report_entry_time_short">Meno di 5 minuti</string>
|
||||
<string name="pref_exposure_app_report_entry_time_about">Circa <xliff:g example="13">%1$d</xliff:g> minuti</string>
|
||||
<string name="pref_exposure_app_report_entry_distance_close">esposizione ravvicinata</string>
|
||||
<string name="pref_exposure_app_report_entry_distance_far">esposizione a distanza</string>
|
||||
<string name="pref_exposure_app_report_entry_combined"><xliff:g example="About 12 minutes">%1$s</xliff:g>, <xliff:g example="distant exposure">%2$s</xliff:g></string>
|
||||
<string name="pref_exposure_app_report_updated_title">Ultimo aggiornamento: <xliff:g example="Today, 14:02">%1$s</xliff:g></string>
|
||||
<string name="pref_exposure_rpi_export_summary">Esporta gli identificativi univoci raccolti per analizzarli con un\'altra app.</string>
|
||||
<string name="exposure_confirm_location_description">È necessario attivare la geolocalizzazione.</string>
|
||||
<string name="pref_exposure_error_bluetooth_unsupported_summary">Il tuo dispositivo non è compatibile con le notifiche di esposizione al virus.</string>
|
||||
<string name="pref_exposure_error_bluetooth_no_advertise_summary">Il tuo dispositivo è compatibile soltanto parzialmente con le notifiche di esposizione al virus. Potrai essere notificato in caso di contatti a rischio, ma non sarai in grado di notificare gli altri.</string>
|
||||
<string name="pref_exposure_rpis_histogram_legend_no_records">Nessun dato</string>
|
||||
<string name="pref_exposure_rpis_histogram_legend_records"><xliff:g example="0 - 50">%1$s</xliff:g> identificativi in un\'ora</string>
|
||||
<string name="prefcat_exposure_app_report_title">Esposizioni riscontrate</string>
|
||||
<string name="pref_exposure_error_location_off_title">Apri le impostazioni di geolocalizzazione</string>
|
||||
<string name="pref_exposure_error_nearby_not_granted_title">Sono richiesti nuovi permessi</string>
|
||||
<string name="pref_exposure_error_nearby_not_granted_description">Tocca per consentire i permessi richiesti per le notifiche di esposizione al virus</string>
|
||||
<string name="exposure_grant_background_location_description">Ci sei quasi! Ora dovrai abilitare l\'accesso alla posizione in background selezionando l\'opzione \"Consenti sempre\" nella prossima schermata. Una volta fatto, premi il tasto Indietro.</string>
|
||||
<string name="exposure_grant_background_location_button">Aggiorna impostazioni</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="pref_exposure_error_bluetooth_off_title">Bluetooth を有効にする</string>
|
||||
<string name="pref_exposure_error_location_off_title">位置情報の設定を開く</string>
|
||||
<string name="pref_exposure_collected_rpis_title">収集されたID</string>
|
||||
<string name="pref_exposure_advertising_id_title">現在のブロードキャストID</string>
|
||||
</resources>
|
||||
30
play-services-nearby/core/src/main/res/values-ko/strings.xml
Normal file
30
play-services-nearby/core/src/main/res/values-ko/strings.xml
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="exposure_notify_off_title">노출 알림 비활성화됨</string>
|
||||
<string name="exposure_notify_off_bluetooth">노출 알림을 수신하려면 블루투스가 활성화되어야 합니다.</string>
|
||||
<string name="exposure_notify_off_location">노출 알림을 수신하려면 위치 접근이 필요합니다.</string>
|
||||
<string name="exposure_notify_off_bluetooth_location">노출 알림을 수신하려면 블루투스와 위치 접근이 활성화되어야 합니다.</string>
|
||||
<string name="exposure_notify_off_nearby">노출 알림의 작동에 추가적인 권한이 필요합니다</string>
|
||||
<string name="service_name_exposure">노출 알림</string>
|
||||
<string name="pref_exposure_enable_info_summary">노출 알림을 활성화하려면, 지원하는 앱을 열어주세요.</string>
|
||||
<string name="pref_exposure_error_bluetooth_off_title">블루투스 활성화</string>
|
||||
<string name="pref_exposure_error_location_off_title">위치 설정 열기</string>
|
||||
<string name="pref_exposure_collected_rpis_title">수집한 ID</string>
|
||||
<string name="pref_exposure_rpi_delete_all_title">삭제</string>
|
||||
<string name="pref_exposure_rpi_export_title">내보내기</string>
|
||||
<string name="exposure_confirm_keys_button">공유</string>
|
||||
<string name="exposure_confirm_permission_button">승인</string>
|
||||
<string name="exposure_confirm_button">활성화</string>
|
||||
<string name="exposure_confirm_start_button">켜기</string>
|
||||
<string name="exposure_confirm_stop_button">끄기</string>
|
||||
<string name="pref_exposure_error_bluetooth_unsupported_summary">안타깝게도, 이 기기는 노출 알림과 호환되지 않습니다.</string>
|
||||
<string name="pref_exposure_error_bluetooth_no_advertise_summary">안타깝게도, 이 기기는 노출 알림과 부분적으로만 호환됩니다. 노출되었을 때 알림을 받을 수 있지만, 다른 사람에게는 알림을 보낼 수 없습니다.</string>
|
||||
<string name="prefcat_exposure_apps_title">노출 알림을 사용하는 앱</string>
|
||||
<string name="pref_exposure_collected_rpis_summary">지난 1시간 동안 <xliff:g example="63">%1$d</xliff:g>번의 ID</string>
|
||||
<string name="pref_exposure_advertising_id_title">현재 방송 중인 ID</string>
|
||||
<string name="prefcat_exposure_app_report_title">보고된 노출</string>
|
||||
<string name="pref_exposure_app_report_updated_title"><xliff:g example="Today, 14:02">%1$s</xliff:g>에 갱신됨</string>
|
||||
<string name="pref_exposure_app_report_entry_time_short">5분 미만</string>
|
||||
<string name="pref_exposure_app_report_entry_time_about">약 <xliff:g example="13">%1$d</xliff:g>분</string>
|
||||
<string name="pref_exposure_app_report_entry_distance_close">근처 노출</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources></resources>
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources></resources>
|
||||
12
play-services-nearby/core/src/main/res/values-ml/strings.xml
Normal file
12
play-services-nearby/core/src/main/res/values-ml/strings.xml
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="exposure_notify_off_title">എക്സ്പോഷർ അറിയിപ്പുകൾ നിഷ്ക്രിയമാണ്</string>
|
||||
<string name="exposure_notify_off_bluetooth">എക്സ്പോഷർ അറിയിപ്പുകൾ ലഭിക്കാൻ ബ്ലൂടൂത്ത് പ്രവർത്തനക്ഷമമാക്കേണ്ടതുണ്ട്.</string>
|
||||
<string name="exposure_notify_off_location">എക്സ്പോഷർ അറിയിപ്പുകൾ ലഭിക്കാൻ ലൊക്കേഷൻ ആക്സസ് ആവശ്യമാണ്.</string>
|
||||
<string name="exposure_notify_off_bluetooth_location">എക്സ്പോഷർ അറിയിപ്പുകൾ ലഭിക്കാൻ ബ്ലൂടൂത്തും ലൊക്കേഷൻ ആക്സസും പ്രവർത്തനക്ഷമമാക്കേണ്ടതുണ്ട്.</string>
|
||||
<string name="exposure_notify_off_nearby">എക്സ്പോഷർ അറിയിപ്പുകൾ പ്രവർത്തിക്കാൻ അധിക അനുമതികൾ ആവശ്യമാണ്</string>
|
||||
<string name="service_name_exposure">എക്സ്പോഷർ അറിയിപ്പുകൾ</string>
|
||||
<string name="pref_exposure_enable_info_summary">എക്സ്പോഷർ അറിയിപ്പുകൾ പ്രവർത്തനക്ഷമമാക്കാൻ, അതിനെ പിന്തുണയ്ക്കുന്ന ഏതെങ്കിലും ആപ്പ് തുറക്കുക.</string>
|
||||
<string name="pref_exposure_error_bluetooth_off_title">ബ്ലൂടൂത്ത് പ്രവർത്തനക്ഷമമാക്കുക</string>
|
||||
<string name="pref_exposure_error_location_off_title">ലൊക്കേഷൻ ക്രമീകരണങ്ങൾ തുറക്കുക</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="pref_exposure_error_bluetooth_off_title">Aktiver Bluetooth</string>
|
||||
<string name="pref_exposure_error_location_off_title">Åpne lokasjonsinnstillinger</string>
|
||||
<string name="pref_exposure_app_report_entry_time_short">Mindre enn 5 minutter</string>
|
||||
<string name="pref_exposure_app_report_entry_time_about">Rundt <xliff:g example="13">%1$d</xliff:g> minutter</string>
|
||||
<string name="pref_exposure_app_report_updated_title">Oppdatert: <xliff:g example="Today, 14:02">%1$s</xliff:g></string>
|
||||
<string name="pref_exposure_app_api_usage_title">API-bruk i løpet av de siste 14 dager</string>
|
||||
<string name="exposure_confirm_start_button">Skru på</string>
|
||||
<string name="pref_exposure_rpi_delete_all_title">Slett</string>
|
||||
<string name="pref_exposure_rpi_delete_all_summary">Slett alle innsamlede ID-er</string>
|
||||
<string name="pref_exposure_rpi_delete_all_warning_confirm_button">Slett alikevel</string>
|
||||
<string name="pref_exposure_rpi_export_title">Eksporter</string>
|
||||
<string name="pref_exposure_rpi_export_summary">Eksporter innsamlede ID-er for analyse i en annen app.</string>
|
||||
<string name="exposure_confirm_stop_button">Skru av</string>
|
||||
<string name="exposure_confirm_keys_title">Del ID-ene dine med <xliff:g example="Corona-Warn">%1$s</xliff:g>\?</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="exposure_notify_off_nearby">Meldingen vereisen extra machtigingen om te werken</string>
|
||||
<string name="exposure_confirm_permission_button">Toestaan</string>
|
||||
<string name="pref_exposure_error_nearby_not_granted_description">Tik op om de vereiste machtigingen te verlenen voor Meldingen weergeven</string>
|
||||
<string name="pref_exposure_rpis_details_summary">Als Exposure Notification API is ingeschakeld, verzamelt je apparaat passief ID\'s (Rolling Proximity Identifiers of RPI\'s genoemd) van apparaten in de buurt.\n\nWanneer eigenaars van apparaten melden dat ze positief gediagnosticeerd zijn, kunnen hun ID\'s gedeeld worden. Uw apparaat controleert of een van de bekende gediagnosticeerde ID\'s overeenkomt met een van de verzamelde ID\'s en berekent uw infectierisico.</string>
|
||||
</resources>
|
||||
68
play-services-nearby/core/src/main/res/values-pl/strings.xml
Normal file
68
play-services-nearby/core/src/main/res/values-pl/strings.xml
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="pref_exposure_app_last_report_summary_encounters_prefix">Wykryto <xliff:g example="3">%1$d</xliff:g> narażeń na kontakt:</string>
|
||||
<string name="pref_exposure_app_report_entry_combined"><xliff:g example="About 12 minutes">%1$s</xliff:g>, <xliff:g example="distant exposure">%2$s</xliff:g></string>
|
||||
<string name="pref_exposure_app_api_usage_title">Użycie API w ciągu ostatnich 14 dni</string>
|
||||
<string name="pref_exposure_rpi_export_summary">Eksportuje zebrane ID dla rozszerzonej analizy przez inną aplikację.</string>
|
||||
<string name="exposure_notify_off_bluetooth_location">Bluetooth i dostęp do lokalizacji muszą być włączone, aby otrzymywać powiadomienia o narażaniu na kontakt.</string>
|
||||
<string name="exposure_confirm_stop_button">Wyłącz</string>
|
||||
<string name="pref_exposure_advertising_id_title">Obecnie nadawany ID</string>
|
||||
<string name="exposure_confirm_start_title">Włączyć powiadomienia o narażaniu na kontakt\?</string>
|
||||
<string name="pref_exposure_error_bluetooth_unsupported_summary">Niestety twoje urządzenie nie jest kompatybilne z powiadomieniami o narażaniu na kontakt.</string>
|
||||
<string name="pref_exposure_collected_rpis_title">Zebrane ID</string>
|
||||
<string name="pref_exposure_error_nearby_not_granted_description">Dotknij, aby udzielić wymaganych uprawnień dla powiadomień o narażaniu na kontakt</string>
|
||||
<string name="pref_exposure_app_report_entry_time_short">Poniżej 5 minut temu</string>
|
||||
<string name="pref_exposure_app_last_report_summary_encounters_no">Nie wykryto żadnych narażeń na kontakt.</string>
|
||||
<string name="pref_exposure_app_report_entry_distance_far">daleki kontakt</string>
|
||||
<string name="exposure_confirm_keys_title">Udostępniać Twoje ID aplikacji <xliff:g example="Corona-Warn">%1$s</xliff:g>\?</string>
|
||||
<string name="exposure_enable_switch">Używaj powiadomień o narażaniu na kontakt</string>
|
||||
<string name="pref_exposure_app_last_report_summary_diagnosis_keys">Przetworzono <xliff:g example="121031">%1$d</xliff:g> kluczy diagnostycznych.</string>
|
||||
<string name="pref_exposure_rpi_export_title">Eksportuj</string>
|
||||
<string name="pref_exposure_rpis_histogram_legend_records"><xliff:g example="0 - 50">%1$s</xliff:g> ID na godzinę</string>
|
||||
<string name="exposure_notify_off_title">Powiadomienia o narażaniu na kontakt są nieaktywne</string>
|
||||
<string name="pref_exposure_app_report_updated_title">Aktualizacja: <xliff:g example="Today, 14:02">%1$s</xliff:g></string>
|
||||
<string name="exposure_grant_background_location_button">Aktualizacja ustawień</string>
|
||||
<string name="pref_exposure_error_location_off_title">Otwórz ustawienia lokalizacji</string>
|
||||
<string name="pref_exposure_rpis_details_summary">W czasie, gdy API powiadomień o narażaniu na kontakt z COVID-19 jest aktywne, twoje urządzenie stale gromadzi identyfikatory (nazywane RPI, ang. „Rolling Proximity Identifiers”) z pobliskich urządzeń.
|
||||
\n
|
||||
\nJeżeli właściciele urządzeń zgłoszą pozytywną diagnozę testu, ich ID mogą być udostępniane. Twoje urządzenie sprawdza, czy żaden z znanych ID z pozytywną diagnozą testu nie znajduje się w zebranych ID i wylicza twoje ryzyko zakażenia.</string>
|
||||
<string name="pref_exposure_info_summary">API powiadomień o narażaniu na kontakt z COVID-19 pozwalają aplikacjom na powiadamianie cię o kontakcie z osobami z pozytywną diagnozą testu na obecność wirusa.
|
||||
\n
|
||||
\nData, okres i siła sygnału związana z narażeniem na kontakt będzie udostępniona odpowiedniej aplikacji.</string>
|
||||
<string name="pref_exposure_app_api_usage_summary_line"><xliff:g example="12">%1$d</xliff:g> rozgłoszeń do <xliff:g example="provideDiagnosisKeys">%2$s</xliff:g></string>
|
||||
<string name="pref_exposure_enable_info_summary">Aby włączyć funkcję powiadomień o narażaniu na kontakt, otwórz dowolną aplikację wspierającą ją.</string>
|
||||
<string name="pref_exposure_rpi_delete_all_summary">Usuń wszystkie zebrane ID</string>
|
||||
<string name="exposure_confirm_permission_description"><xliff:g example="microG Services">%1$s</xliff:g> potrzebuje dodatkowych uprawnień.</string>
|
||||
<string name="service_name_exposure">Powiadomienia o narażaniu na kontakt</string>
|
||||
<string name="pref_exposure_app_report_entry_distance_close">bliski kontakt</string>
|
||||
<string name="exposure_confirm_permission_button">Udziel</string>
|
||||
<string name="exposure_notify_off_bluetooth">Bluetooth musi być włączony, aby otrzymywać powiadomienia o narażaniu na kontakt.</string>
|
||||
<string name="pref_exposure_rpi_delete_all_warning_confirm_button">Usuń mimo tego</string>
|
||||
<string name="pref_exposure_app_last_report_summary_encounters_suffix">Informacja: Poziom ryzyka jest ustalany przez aplikację. Wysokie liczby mogą oznaczać niskie ryzyko i vice versa.</string>
|
||||
<string name="exposure_confirm_location_description">Dostęp do lokalizacji jest wymagany.</string>
|
||||
<string name="pref_exposure_error_bluetooth_no_advertise_summary">Niestety twoje urządzenie jest tylko częściowo kompatybilne z powiadomieniami o narażaniu na kontakt. Możesz otrzymywać powiadomienia o ryzyku kontaktu, ale nie będziesz w stanie powiadomić innych.</string>
|
||||
<string name="exposure_confirm_bluetooth_description">Bluetooth musi być włączony.</string>
|
||||
<string name="exposure_confirm_start_button">Włącz</string>
|
||||
<string name="prefcat_exposure_rpis_histogram_title"><xliff:g example="230">%1$d</xliff:g> zebranych ID</string>
|
||||
<string name="pref_exposure_collected_rpis_summary"><xliff:g example="63">%1$d</xliff:g> ID w ciągu ostatniej godziny</string>
|
||||
<string name="exposure_notify_off_location">Dostęp do lokalizacji jest wymagany, aby otrzymywać powiadomienia o narażaniu na kontakt.</string>
|
||||
<string name="prefcat_exposure_apps_title">Aplikacje korzystające z powiadomień o narażaniu na kontakt</string>
|
||||
<string name="exposure_confirm_stop_summary">Po wyłączeniu powiadomień o narażeniu, przestaniesz być powiadamiany gdy zostałeś narażony na kontakt z osobą o pozytywnej diagnozie.</string>
|
||||
<string name="pref_exposure_app_last_report_summary_encounters_line"><xliff:g example="Yesterday, 12:00 - 14:00">%1$s</xliff:g>, poziom ryzyka: <xliff:g example="99">%2$d</xliff:g></string>
|
||||
<string name="exposure_confirm_stop_title">Wyłączyć powiadomienia o narażaniu na kontakt?</string>
|
||||
<string name="exposure_confirm_keys_summary">Twoje identyfikatory w ciągu ostatnich 14 dni zostaną wykorzystane, aby pomóc powiadamiać innych o możliwym wystąpieniu narażenia na kontakt z wirusem.
|
||||
\n
|
||||
\nZarówno Twoja tożsamość jak i wynik testu nie zostanie udostępniona innym osobom.</string>
|
||||
<string name="exposure_confirm_start_summary">Telefon musi korzystać z Bluetooth, aby bezpiecznie gromadzić i udostępniać identyfikatory innym telefonom znajdującym się w pobliżu.\n\n<xliff:g example="Corona-Warn">%1$s</xliff:g> może powiadomić użytkownika, jeśli był narażony na kontakt z osobą, u której zdiagnozowano pozytywny wynik.\n\nData, czas trwania i siła sygnału związane z ekspozycją zostaną udostępnione aplikacji.</string>
|
||||
<string name="pref_exposure_rpis_histogram_legend_no_records">Brak wpisów</string>
|
||||
<string name="pref_exposure_rpi_delete_all_title">Usuń</string>
|
||||
<string name="pref_exposure_error_nearby_not_granted_title">Wymagane nowe uprawnienia</string>
|
||||
<string name="prefcat_exposure_app_report_title">Wykryte narażenia</string>
|
||||
<string name="exposure_notify_off_nearby">Powiadomienia o narażaniu na kontakt wymagają dodatkowych uprawnień, aby działać prawidłowo</string>
|
||||
<string name="pref_exposure_rpi_delete_all_warning">Usunięcie wszystkich zebranych identyfikatorów sprawi, że niemożliwe stanie się powiadomienie cię w przypadku gdy któryś z twoich kontaktów z ostatnich 14 dni był z osobą o pozytywnej diagnozie.</string>
|
||||
<string name="exposure_confirm_keys_button">Udostępnij</string>
|
||||
<string name="exposure_grant_background_location_description">Prawie gotowe! Musisz teraz udzielić dostępu do lokalizacji w tle poprzez wybranie opcji „Zawsze zezwalaj” na następnym ekranie. Następnie dotknij Wstecz.</string>
|
||||
<string name="exposure_confirm_button">Włącz</string>
|
||||
<string name="pref_exposure_error_bluetooth_off_title">Włącz Bluetooth</string>
|
||||
<string name="pref_exposure_app_report_entry_time_about">Około <xliff:g example="13">%1$d</xliff:g> minut temu</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="pref_exposure_app_last_report_summary_encounters_prefix"><xliff:g example="3">%1$d</xliff:g> exposições relatadas:</string>
|
||||
<string name="pref_exposure_app_api_usage_summary_line"><xliff:g example="12">%1$d</xliff:g> solicitações para <xliff:g example="provideDiagnosisKeys">%2$s</xliff:g></string>
|
||||
<string name="prefcat_exposure_rpis_histogram_title"><xliff:g example="230">%1$d</xliff:g> IDs coletados</string>
|
||||
<string name="exposure_confirm_keys_title">Compartilhar seus IDs com <xliff:g example="Corona-Warn">%1$s</xliff:g>\?</string>
|
||||
<string name="pref_exposure_error_bluetooth_unsupported_summary">Infelizmente, seu dispositivo não é compatível com as notificações de exposição.</string>
|
||||
<string name="pref_exposure_error_bluetooth_no_advertise_summary">Infelizmente, seu dispositivo é somente parcialmente compatível com as notificações de exposição. Você poderá ser notificado por contatos de risco, mas não será possível notificar outros.</string>
|
||||
<string name="prefcat_exposure_apps_title">Apps usando as notificações de exposição</string>
|
||||
<string name="pref_exposure_collected_rpis_title">IDs coletados</string>
|
||||
<string name="pref_exposure_collected_rpis_summary"><xliff:g example="63">%1$d</xliff:g> IDs na última hora</string>
|
||||
<string name="pref_exposure_advertising_id_title">ID atualmente transmitido</string>
|
||||
<string name="prefcat_exposure_app_report_title">Exposições reportadas</string>
|
||||
<string name="pref_exposure_app_report_updated_title">Atualizado: <xliff:g example="Today, 14:02">%1$s</xliff:g></string>
|
||||
<string name="pref_exposure_app_report_entry_time_short">Menos que 5 minutos</string>
|
||||
<string name="pref_exposure_app_report_entry_time_about">Em volta de <xliff:g example="13">%1$d</xliff:g> minutos</string>
|
||||
<string name="pref_exposure_app_report_entry_combined"><xliff:g example="About 12 minutes">%1$s</xliff:g>, <xliff:g example="distant exposure">%2$s</xliff:g></string>
|
||||
<string name="pref_exposure_app_last_report_summary_diagnosis_keys"><xliff:g example="121031">%1$d</xliff:g> chaves de diagnóstico processadas.</string>
|
||||
<string name="pref_exposure_app_last_report_summary_encounters_line"><xliff:g example="Yesterday, 12:00 - 14:00">%1$s</xliff:g>, chance de risco <xliff:g example="99">%2$d</xliff:g></string>
|
||||
<string name="pref_exposure_rpis_histogram_legend_records"><xliff:g example="0 - 50">%1$s</xliff:g> IDs por hora</string>
|
||||
<string name="exposure_confirm_start_summary">Seu dispositivo precisa utilizar o Bluetooth para coletar e compartilhar IDs com segurança para dispositivos por perto.\n\n<xliff:g example="Corona-Warn">%1$s</xliff:g> pode te notificar se você foi exposto à alguém que teve um diagnóstico positivo.\n\nA data, duração, e força do sinal associada com uma exposição será compartilhada com o app.</string>
|
||||
<string name="exposure_notify_off_title">Notificações de exposição inativas</string>
|
||||
<string name="exposure_notify_off_bluetooth">O Bluetooth precisa ser ativado para receber notificações de exposição.</string>
|
||||
<string name="exposure_notify_off_location">O acesso à localização é necessário para receber notificações de exposição.</string>
|
||||
<string name="exposure_notify_off_bluetooth_location">O Bluetooth e o acesso à localização precisam estar ativados para receber notificações de exposição.</string>
|
||||
<string name="exposure_notify_off_nearby">As notificações de exposição precisam de permissões adicionais para funcionar</string>
|
||||
<string name="service_name_exposure">Notificações de exposição</string>
|
||||
<string name="pref_exposure_enable_info_summary">Para ativar as notificações de exposição, abra qualquer app que suporte elas.</string>
|
||||
<string name="pref_exposure_error_bluetooth_off_title">Ativar Bluetooth</string>
|
||||
<string name="pref_exposure_error_location_off_title">Abrir as configurações de localização</string>
|
||||
<string name="pref_exposure_app_report_entry_distance_close">exposição próxima</string>
|
||||
<string name="pref_exposure_app_report_entry_distance_far">exposição distante</string>
|
||||
<string name="pref_exposure_app_last_report_summary_encounters_no">Nenhuma exposição relatada.</string>
|
||||
<string name="pref_exposure_app_last_report_summary_encounters_suffix">Observação: A chance de risco é definida pelo app. Números altos podem se referir a pouca chance de risco, ou vice versa.</string>
|
||||
<string name="pref_exposure_app_api_usage_title">Uso da API nos últimos 14 dias</string>
|
||||
<string name="pref_exposure_rpis_histogram_legend_no_records">Não há registros</string>
|
||||
<string name="pref_exposure_rpi_delete_all_title">Apagar</string>
|
||||
<string name="pref_exposure_rpi_delete_all_summary">Apagar todos os IDs coletados</string>
|
||||
<string name="pref_exposure_rpi_delete_all_warning">Apagar os IDs coletados fará com que seja impossível te notificar no caso de algum contato dos últimos 14 dias seja diagnosticado.</string>
|
||||
<string name="pref_exposure_rpi_delete_all_warning_confirm_button">Apagar mesmo assim</string>
|
||||
<string name="pref_exposure_rpi_export_title">Exportar</string>
|
||||
<string name="pref_exposure_rpi_export_summary">Exportar IDs coletados para análise extensa com outro app.</string>
|
||||
<string name="pref_exposure_info_summary">A API de notificações de exposição permite que apps te notifiquem se você ficou exposto a alguém que foi relatado tendo um diagnóstico positivo.\n\nA data, duração, e força do sinal associada com uma exposição será compartilhada com o app correspondente.</string>
|
||||
<string name="pref_exposure_rpis_details_summary">Ao ativar a API de notificações de exposição, seu dispositivo coleta IDs passivamente (chamados de Rolling Proximity Identifiers, ou RPIs) de dispositivos próximos.\n\nQuando o dono de um dispositivo relata um diagnóstico positivo, seus IDs podem serem compartilhados. Seu dispositivo verifica que qualquer um dos IDs conhecidos como positivos conferem com IDs coletados e calcula seu risco de infecção.</string>
|
||||
<string name="exposure_enable_switch">Usar notificações de exposição</string>
|
||||
<string name="exposure_confirm_start_title">Ativar as notificações de exposição?</string>
|
||||
<string name="exposure_confirm_start_button">Ativar</string>
|
||||
<string name="exposure_confirm_stop_title">Desativar as notificações de exposição?</string>
|
||||
<string name="exposure_confirm_stop_summary">Após desativar as notificações de exposição, você não será mais notificado caso foi exposto a alguém com o diagnóstico positivo.</string>
|
||||
<string name="exposure_confirm_stop_button">Desativar</string>
|
||||
<string name="exposure_confirm_keys_summary">Seus IDs dos últimos 14 dias serão utilizados para notificar outros que você esteve perto de uma potencial exposição.\n\nSua identidade ou resultado de exames não serão compartilhados com outras pessoas.</string>
|
||||
<string name="exposure_confirm_keys_button">Compartilhar</string>
|
||||
<string name="exposure_confirm_permission_description"><xliff:g example="microG Services">%1$s</xliff:g> precisa de permissões adicionais.</string>
|
||||
<string name="exposure_confirm_permission_button">Permitir</string>
|
||||
<string name="exposure_confirm_bluetooth_description">O Bluetooth precisa ser ativado.</string>
|
||||
<string name="exposure_confirm_location_description">O acesso à localização é necessário.</string>
|
||||
<string name="exposure_confirm_button">Ativar</string>
|
||||
<string name="pref_exposure_error_nearby_not_granted_title">Novas permissões necessárias</string>
|
||||
<string name="pref_exposure_error_nearby_not_granted_description">Toque para permitir permissões necessárias para as notificações de exposição</string>
|
||||
<string name="exposure_grant_background_location_description">Quase lá! Você precisará ativar acesso à localização em segundo plano selecionando a opção \"Permitir o tempo todo\" na próxima tela. E então volte.</string>
|
||||
<string name="exposure_grant_background_location_button">Atualizar configurações</string>
|
||||
</resources>
|
||||
62
play-services-nearby/core/src/main/res/values-pt/strings.xml
Normal file
62
play-services-nearby/core/src/main/res/values-pt/strings.xml
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="exposure_notify_off_title">Notificações de exposição inativas</string>
|
||||
<string name="exposure_notify_off_bluetooth">O Bluetooth precisa ser ativado para receber notificações de exposição.</string>
|
||||
<string name="exposure_notify_off_location">O acesso à localização é necessário para receber notificações de exposição.</string>
|
||||
<string name="exposure_notify_off_bluetooth_location">O Bluetooth e o acesso à localização precisam estar ativados para receber notificações de exposição.</string>
|
||||
<string name="exposure_notify_off_nearby">As notificações de exposição precisam de permissões adicionais para funcionar</string>
|
||||
<string name="service_name_exposure">Notificações de exposição</string>
|
||||
<string name="pref_exposure_enable_info_summary">Para ativar as notificações de exposição, abra qualquer app que apoio elas.</string>
|
||||
<string name="pref_exposure_error_bluetooth_off_title">Ativar Bluetooth</string>
|
||||
<string name="pref_exposure_error_location_off_title">Abrir as configurações de localização</string>
|
||||
<string name="pref_exposure_error_bluetooth_unsupported_summary">Infelizmente, o seu dispositivo não é compatível com as notificações de exposição.</string>
|
||||
<string name="pref_exposure_error_bluetooth_no_advertise_summary">Infelizmente, o seu dispositivo é somente parcialmente compatível com as notificações de exposição. Poderá ser notificado por contactos de risco, mas não será possível notificar outros.</string>
|
||||
<string name="prefcat_exposure_apps_title">Apps usando as notificações de exposição</string>
|
||||
<string name="pref_exposure_collected_rpis_title">IDs coletados</string>
|
||||
<string name="pref_exposure_collected_rpis_summary"><xliff:g example="63">%1$d</xliff:g> IDs na última hora</string>
|
||||
<string name="pref_exposure_advertising_id_title">ID atualmente transmitido</string>
|
||||
<string name="prefcat_exposure_app_report_title">Exposições reportadas</string>
|
||||
<string name="pref_exposure_app_report_updated_title">Atualizado: <xliff:g example="Today, 14:02">%1$s</xliff:g></string>
|
||||
<string name="pref_exposure_app_report_entry_time_short">Menos que 5 minutos</string>
|
||||
<string name="pref_exposure_app_report_entry_time_about">Em volta de <xliff:g example="13">%1$d</xliff:g> minutos</string>
|
||||
<string name="pref_exposure_app_report_entry_distance_close">exposição próxima</string>
|
||||
<string name="pref_exposure_app_report_entry_distance_far">exposição distante</string>
|
||||
<string name="pref_exposure_app_report_entry_combined"><xliff:g example="About 12 minutes">%1$s</xliff:g>, <xliff:g example="distant exposure">%2$s</xliff:g></string>
|
||||
<string name="pref_exposure_app_last_report_summary_diagnosis_keys"><xliff:g example="121031">%1$d</xliff:g> chaves de diagnóstico processadas.</string>
|
||||
<string name="pref_exposure_app_last_report_summary_encounters_no">Nenhuma exposição relatada.</string>
|
||||
<string name="pref_exposure_app_last_report_summary_encounters_prefix"><xliff:g example="3">%1$d</xliff:g> exposições relatadas:</string>
|
||||
<string name="pref_exposure_app_last_report_summary_encounters_line"><xliff:g example="Yesterday, 12:00 - 14:00">%1$s</xliff:g>, chance de risco <xliff:g example="99">%2$d</xliff:g></string>
|
||||
<string name="pref_exposure_app_last_report_summary_encounters_suffix">Observação: A chance de risco é definida pela app. Números altos podem referir-se a pouca chance de risco, ou vice versa.</string>
|
||||
<string name="pref_exposure_app_api_usage_title">Uso da API nos últimos 14 dias</string>
|
||||
<string name="pref_exposure_app_api_usage_summary_line"><xliff:g example="12">%1$d</xliff:g> solicitações para <xliff:g example="provideDiagnosisKeys">%2$s</xliff:g></string>
|
||||
<string name="prefcat_exposure_rpis_histogram_title"><xliff:g example="230">%1$d</xliff:g> IDs coletados</string>
|
||||
<string name="pref_exposure_rpis_histogram_legend_no_records">Não há registos</string>
|
||||
<string name="pref_exposure_rpis_histogram_legend_records"><xliff:g example="0 - 50">%1$s</xliff:g> IDs por hora</string>
|
||||
<string name="pref_exposure_rpi_delete_all_title">Apagar</string>
|
||||
<string name="pref_exposure_rpi_delete_all_summary">Apagar todos os IDs coletados</string>
|
||||
<string name="pref_exposure_rpi_delete_all_warning">Apagar os IDs coletados fará com que seja impossível notificar-lo no caso de algum contacto dos últimos 14 dias seja diagnosticado.</string>
|
||||
<string name="pref_exposure_rpi_delete_all_warning_confirm_button">Apagar mesmo assim</string>
|
||||
<string name="pref_exposure_rpi_export_title">Exportar</string>
|
||||
<string name="pref_exposure_rpi_export_summary">Exportar IDs coletados para análise extensa com outra app.</string>
|
||||
<string name="pref_exposure_info_summary">A API de notificações de exposição permite que apps notifiquem-lo se ficou exposto a alguém que foi relatado a ter um diagnóstico positivo.\n\nA data, duração e força do sinal associada com uma exposição será partilhada com a app correspondente.</string>
|
||||
<string name="pref_exposure_rpis_details_summary">Ao ativar a API de notificações de exposição, o seu dispositivo coleta IDs passivamente (chamados de Rolling Proximity Identifiers, ou RPIs) de dispositivos próximos.\n\nQuando o dono de um dispositivo relata um diagnóstico positivo, os seus IDs podem serem partilhados. O seu dispositivo verifica que qualquer um dos IDs conhecidos como positivos conferem com IDs coletados e calcula o seu risco de infecção.</string>
|
||||
<string name="exposure_enable_switch">Usar notificações de exposição</string>
|
||||
<string name="exposure_confirm_start_title">Ativar as notificações de exposição?</string>
|
||||
<string name="exposure_confirm_start_summary">O seu dispositivo precisa utilizar o Bluetooth para coletar e partilhar IDs com segurança para dispositivos por perto.\n\n<xliff:g example="Corona-Warn">%1$s</xliff:g> pode notificar-lo se foi exposto a alguém que teve um diagnóstico positivo.\n\nA data, duração e força do sinal associada com uma exposição será partilhada com a app.</string>
|
||||
<string name="exposure_confirm_start_button">Ligar</string>
|
||||
<string name="exposure_confirm_stop_title">Desativar as notificações de exposição?</string>
|
||||
<string name="exposure_confirm_stop_summary">Após desativar as notificações de exposição, já não será notificado caso foi exposto a alguém com o diagnóstico positivo.</string>
|
||||
<string name="exposure_confirm_stop_button">Desativar</string>
|
||||
<string name="exposure_confirm_keys_title">Partilhar os seus IDs com <xliff:g example="Corona-Warn">%1$s</xliff:g>\?</string>
|
||||
<string name="exposure_confirm_keys_summary">Os seus IDs dos últimos 14 dias serão utilizados para notificar outros que esteve perto de uma potencial exposição.\n\nSua identidade ou resultado de exames não serão partilhados com outras pessoas.</string>
|
||||
<string name="exposure_confirm_keys_button">Partilhar</string>
|
||||
<string name="exposure_confirm_permission_description"><xliff:g example="microG Services">%1$s</xliff:g> precisa de permissões adicionais.</string>
|
||||
<string name="exposure_confirm_permission_button">Conceder</string>
|
||||
<string name="exposure_confirm_bluetooth_description">O Bluetooth precisa ser ativado.</string>
|
||||
<string name="exposure_confirm_location_description">O acesso à localização é necessário.</string>
|
||||
<string name="exposure_confirm_button">Ativar</string>
|
||||
<string name="pref_exposure_error_nearby_not_granted_title">Novas permissões necessárias</string>
|
||||
<string name="pref_exposure_error_nearby_not_granted_description">Toque para permitir permissões necessárias para as notificações de exposição</string>
|
||||
<string name="exposure_grant_background_location_description">Quase chegou! Precisará ativar acesso à localização em segundo plano selecionando a opção \"Permitir o tempo todo\" no próximo ecrã. E depois volte.</string>
|
||||
<string name="exposure_grant_background_location_button">Atualizar configurações</string>
|
||||
</resources>
|
||||
68
play-services-nearby/core/src/main/res/values-ro/strings.xml
Normal file
68
play-services-nearby/core/src/main/res/values-ro/strings.xml
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="pref_exposure_app_report_entry_combined"><xliff:g example="About 12 minutes">%1$s</xliff:g>, <xliff:g example="distant exposure">%2$s</xliff:g></string>
|
||||
<string name="exposure_notify_off_bluetooth_location">Accesul la Bluetooth și la locație trebuie să fie activat pentru a primi notificări de expunere.</string>
|
||||
<string name="pref_exposure_advertising_id_title">ID difuzat în prezent</string>
|
||||
<string name="pref_exposure_error_bluetooth_unsupported_summary">Din păcate, dispozitivul nu este compatibil cu notificări de expunere.</string>
|
||||
<string name="pref_exposure_collected_rpis_title">ID-uri colectate</string>
|
||||
<string name="pref_exposure_app_report_entry_time_short">Mai puțin de 5 minute</string>
|
||||
<string name="pref_exposure_app_last_report_summary_encounters_no">Nu au fost raportate întâlniri de expunere.</string>
|
||||
<string name="pref_exposure_app_report_entry_distance_far">expunere la distanță</string>
|
||||
<string name="pref_exposure_app_last_report_summary_diagnosis_keys">Au fost procesate <xliff:g example="121031">%1$d</xliff:g> chei de diagnosticare.</string>
|
||||
<string name="exposure_notify_off_title">Notificări de expunere dezactivate</string>
|
||||
<string name="pref_exposure_app_report_updated_title">Actualizat: <xliff:g example="Today, 14:02">%1$s</xliff:g></string>
|
||||
<string name="pref_exposure_error_location_off_title">Deschide setările pentru locație</string>
|
||||
<string name="pref_exposure_enable_info_summary">Pentru a activa notificările de expunere, deschide orice aplicație care o acceptă.</string>
|
||||
<string name="service_name_exposure">Notificări de expunere</string>
|
||||
<string name="pref_exposure_app_report_entry_distance_close">expunere în apropiere</string>
|
||||
<string name="exposure_notify_off_bluetooth">Bluetooth trebuie să fie activat pentru a primi notificări de expunere.</string>
|
||||
<string name="pref_exposure_error_bluetooth_no_advertise_summary">Din păcate, dispozitivul este doar parțial compatibil cu notificările de expunere. Poți fi notificat pentru contacte cu risc, dar nu vei putea notifica pe alții.</string>
|
||||
<string name="pref_exposure_collected_rpis_summary"><xliff:g example="63">%1$d</xliff:g> ID-uri în ultima oră</string>
|
||||
<string name="exposure_notify_off_location">Accesul la locație este necesar pentru a primi notificări de expunere.</string>
|
||||
<string name="prefcat_exposure_apps_title">Aplicații care utilizează notificări de expunere</string>
|
||||
<string name="prefcat_exposure_app_report_title">Expunerile raportate</string>
|
||||
<string name="exposure_notify_off_nearby">Notificările de expunere necesită permisiuni suplimentare pentru a funcționa</string>
|
||||
<string name="pref_exposure_error_bluetooth_off_title">Activează Bluetooth</string>
|
||||
<string name="pref_exposure_app_report_entry_time_about">Aproximativ <xliff:g example="13">%1$d</xliff:g> minute</string>
|
||||
<string name="pref_exposure_app_last_report_summary_encounters_prefix">Au fost raportate <xliff:g example="3">%1$d</xliff:g> întâlniri de expunere:</string>
|
||||
<string name="pref_exposure_app_api_usage_title">Utilizarea API-ului în ultimele 14 zile</string>
|
||||
<string name="pref_exposure_rpi_export_summary">Exportă ID-urile colectate pentru o analiză extinsă cu o altă aplicație.</string>
|
||||
<string name="pref_exposure_rpi_export_title">Export</string>
|
||||
<string name="pref_exposure_rpis_histogram_legend_records"><xliff:g example="0 - 50">%1$s</xliff:g> ID-uri pe oră</string>
|
||||
<string name="pref_exposure_info_summary">Exposure Notifications API permite aplicațiilor să te anunțe dacă ai fost expus la cineva care a raportat că a fost diagnosticat pozitiv.
|
||||
\n
|
||||
\nData, durata și puterea semnalului asociate cu o expunere vor fi partajate cu aplicația corespunzătoare.</string>
|
||||
<string name="pref_exposure_app_api_usage_summary_line"><xliff:g example="12">%1$d</xliff:g> apeluri la <xliff:g example="provideDiagnosisKeys">%2$s</xliff:g></string>
|
||||
<string name="pref_exposure_rpi_delete_all_summary">Șterge toate ID-urile colectate</string>
|
||||
<string name="pref_exposure_rpi_delete_all_warning_confirm_button">Șterge oricum</string>
|
||||
<string name="pref_exposure_app_last_report_summary_encounters_suffix">Notă: scorul de risc este definit de aplicație. Cifrele mari se pot referi la un risc scăzut sau invers.</string>
|
||||
<string name="prefcat_exposure_rpis_histogram_title"><xliff:g example="230">%1$d</xliff:g> ID-uri colectate</string>
|
||||
<string name="pref_exposure_app_last_report_summary_encounters_line"><xliff:g example="Yesterday, 12:00 - 14:00">%1$s</xliff:g>, scor de risc <xliff:g example="99">%2$d</xliff:g></string>
|
||||
<string name="pref_exposure_rpis_histogram_legend_no_records">Nicio înregistrare</string>
|
||||
<string name="pref_exposure_rpi_delete_all_title">Șterge</string>
|
||||
<string name="pref_exposure_rpi_delete_all_warning">Ștergerea ID-urilor colectate va face imposibilă anunțarea în cazul în care vreunul dintre contacte din ultimele 14 zile este diagnosticat.</string>
|
||||
<string name="exposure_confirm_start_title">Activezi notificările de expunere\?</string>
|
||||
<string name="exposure_enable_switch">Utilizează notificări de expunere</string>
|
||||
<string name="pref_exposure_rpis_details_summary">În timp ce API-ul Exposure Notification este activat, dispozitivul colectează pasiv ID-uri (numite Rolling Proximity Identifiers sau RPI) de la dispozitivele din apropiere.
|
||||
\n
|
||||
\nCând proprietarii de dispozitive raportează că sunt diagnosticați pozitivi, ID-urile lor pot fi partajate. Dispozitivul verifică dacă vreunul dintre ID-urile diagnosticate cunoscute se potrivește cu oricare dintre ID-urile colectate și calculează riscul de infecție.</string>
|
||||
<string name="exposure_confirm_start_summary">Telefonul trebuie să utilizeze Bluetooth pentru a colecta și a partaja ID-uri în siguranță cu alte telefoane din apropiere.\n\n<xliff:g example="Corona-Warn">%1$s</xliff:g> poate anunța dacă ai fost expus la cineva care a raportat că a fost diagnosticat pozitiv.\n\nData, durata și puterea semnalului asociate cu o expunere vor fi partajate cu aplicația.</string>
|
||||
<string name="exposure_confirm_stop_title">Dezactivezi notificările de expunere?</string>
|
||||
<string name="exposure_confirm_stop_button">Oprire</string>
|
||||
<string name="exposure_confirm_stop_summary">După dezactivarea notificărilor de expunere, nu vei mai fi notificat când ai fost expus la cineva care a raportat că a fost diagnosticat pozitiv.</string>
|
||||
<string name="exposure_confirm_start_button">Pornește</string>
|
||||
<string name="exposure_confirm_keys_button">Distribuie</string>
|
||||
<string name="exposure_confirm_permission_button">Acordă</string>
|
||||
<string name="exposure_confirm_button">Activează</string>
|
||||
<string name="exposure_confirm_keys_title">Partajezi ID-urile cu <xliff:g example="Corona-Warn">%1$s</xliff:g>\?</string>
|
||||
<string name="exposure_confirm_keys_summary">ID-urile tale din ultimele 14 zile vor fi folosite pentru a-i anunța pe alții că ai fost aproape despre o potențială expunere.
|
||||
\n
|
||||
\nIdentitatea sau rezultatul testului nu vor fi partajate altor persoane.</string>
|
||||
<string name="exposure_grant_background_location_description">Aproape gata! Va trebui să activezi accesul la locația de fundal selectând opțiunea „Permite tot timpul” pe ecranul următor. Apoi apasă înapoi.</string>
|
||||
<string name="exposure_confirm_permission_description"><xliff:g example="microG Services">%1$s</xliff:g> necesită permisiuni suplimentare.</string>
|
||||
<string name="exposure_confirm_bluetooth_description">Bluetooth trebuie să fie activat.</string>
|
||||
<string name="exposure_confirm_location_description">Este necesar accesul la locație.</string>
|
||||
<string name="pref_exposure_error_nearby_not_granted_title">Sunt necesare permisiuni noi</string>
|
||||
<string name="pref_exposure_error_nearby_not_granted_description">Atinge pentru a acorda permisiunile necesare notificărilor de expunere</string>
|
||||
<string name="exposure_grant_background_location_button">Actualizare setări</string>
|
||||
</resources>
|
||||
75
play-services-nearby/core/src/main/res/values-ru/strings.xml
Normal file
75
play-services-nearby/core/src/main/res/values-ru/strings.xml
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ SPDX-FileCopyrightText: 2020, microG Project Team
|
||||
~ SPDX-License-Identifier: Apache-2.0
|
||||
--><resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="exposure_notify_off_title">Уведомления о риске инфицирования не активны</string>
|
||||
<string name="exposure_notify_off_bluetooth">Bluetooth должен быть включён, чтобы принимать уведомления о риске инфицирования.</string>
|
||||
<string name="exposure_notify_off_location">Доступ к местоположению обязателен, чтобы принимать уведомления о риске инфицирования.</string>
|
||||
<string name="exposure_notify_off_bluetooth_location">Bluetooth и определение местоположения должны быть включены, чтобы принимать уведомления о риске инфицирования.</string>
|
||||
<string name="exposure_notify_off_nearby">Уведомлениям о риске инфицирования для работы требуются дополнительные разрешения</string>
|
||||
<string name="service_name_exposure">Уведомления о риске инфицирования</string>
|
||||
<string name="pref_exposure_enable_info_summary">Чтобы включить уведомления о риске инфицирования запустите любое приложение, которое их поддерживает.</string>
|
||||
<string name="pref_exposure_error_bluetooth_off_title">Включить Bluetooth</string>
|
||||
<string name="pref_exposure_error_location_off_title">Открыть настройки местоположения</string>
|
||||
<string name="pref_exposure_error_bluetooth_unsupported_summary">К сожалению ваше устройство несовместимо с уведомлениями о риске инфицирования.</string>
|
||||
<string name="pref_exposure_error_bluetooth_no_advertise_summary">К сожалению ваше устройство лишь частично совместимо с уведомлениями о риске инфицирования. Вы можете получать уведомления об опасных контактах, но не сможете уведомлять других.</string>
|
||||
<string name="prefcat_exposure_apps_title">Приложения использующие уведомления о риске инфицирования</string>
|
||||
<string name="pref_exposure_collected_rpis_title">Собранные идентификаторы</string>
|
||||
<string name="pref_exposure_collected_rpis_summary"><xliff:g example="63">%1$d</xliff:g> Количество идентификаторов за последний час</string>
|
||||
<string name="pref_exposure_advertising_id_title">Транслируемый в настоящее время идентификатор</string>
|
||||
<string name="prefcat_exposure_app_report_title">Сообщения о взаимодействиях</string>
|
||||
<string name="pref_exposure_app_report_updated_title">Обновлено: <xliff:g example="Today, 14:02">%1$s</xliff:g></string>
|
||||
<string name="pref_exposure_app_report_entry_time_short">Менее пяти минут назад</string>
|
||||
<string name="pref_exposure_app_report_entry_time_about">Около <xliff:g example="13">%1$d</xliff:g> минут</string>
|
||||
<string name="pref_exposure_app_report_entry_distance_close">взаимодействия рядом</string>
|
||||
<string name="pref_exposure_app_report_entry_distance_far">взаимодействия далеко</string>
|
||||
<string name="pref_exposure_app_report_entry_combined"><xliff:g example="About 12 minutes">%1$s</xliff:g>, <xliff:g example="distant exposure">%2$s</xliff:g></string>
|
||||
<string name="pref_exposure_app_last_report_summary_diagnosis_keys">Обработано <xliff:g example="121031">%1$d</xliff:g> диагностических ключей.</string>
|
||||
<string name="pref_exposure_app_last_report_summary_encounters_no">Сообщения об опасных контактах отсутствуют.</string>
|
||||
<string name="pref_exposure_app_last_report_summary_encounters_prefix">Сообщено о <xliff:g example="3">%1$d</xliff:g> опасных контактах:</string>
|
||||
<string name="pref_exposure_app_last_report_summary_encounters_line"><xliff:g example="Yesterday, 12:00 - 14:00">%1$s</xliff:g>, оценка риска <xliff:g example="99">%2$d</xliff:g></string>
|
||||
<string name="pref_exposure_app_last_report_summary_encounters_suffix">Примечание: Оценка риска определяется приложением. Высокие числа могут говорить, как о низком риске так и наоборот.</string>
|
||||
<string name="pref_exposure_app_api_usage_title">Использование API за последние 14 дней</string>
|
||||
<string name="pref_exposure_app_api_usage_summary_line"><xliff:g example="12">%1$d</xliff:g> запросов к <xliff:g example="provideDiagnosisKeys">%2$s</xliff:g></string>
|
||||
<string name="prefcat_exposure_rpis_histogram_title"><xliff:g example="230">%1$d</xliff:g> идентификаторов собрано</string>
|
||||
<string name="pref_exposure_rpis_histogram_legend_no_records">Нет записей</string>
|
||||
<string name="pref_exposure_rpis_histogram_legend_records"><xliff:g example="0 - 50">%1$s</xliff:g> Идентификаторов в час</string>
|
||||
<string name="pref_exposure_rpi_delete_all_title">Удалить</string>
|
||||
<string name="pref_exposure_rpi_delete_all_summary">Удалить все собранные идентификаторы</string>
|
||||
<string name="pref_exposure_rpi_delete_all_warning">Удаление собранных идентификаторов приведёт к невозможности информирования в случае, если у одного из ваших контактов за последние 14 дней окажется положительный диагноз.</string>
|
||||
<string name="pref_exposure_rpi_delete_all_warning_confirm_button">Всё равно удалить</string>
|
||||
<string name="pref_exposure_rpi_export_title">Экспортировать</string>
|
||||
<string name="pref_exposure_rpi_export_summary">Экспортировать собранные идентификаторы для расширенного анализа в стороннем приложении.</string>
|
||||
<string name="pref_exposure_info_summary">"API Уведомлений о риске инфицирования (Exposure Notifications API) позволяет приложениям уведомлять вас, если вы столкнулись с кем-то, у кого был положительный диагноз.
|
||||
|
||||
Дата, продолжительность и мощность сигнала, связанные с воздействием, будут переданы соответствующему приложению."</string>
|
||||
<string name="pref_exposure_rpis_details_summary">"Пока API уведомлений о риске инфицирования включен, ваше устройство пассивно собирает идентификаторы (называемые скользящими идентификаторами сближения или RPI) с соседних устройств.
|
||||
|
||||
Когда владельцы устройств сообщают о положительном диагнозе, их идентификаторы могут быть распространены. Ваше устройство проверяет, соответствует ли какой-либо из известных идентификаторов с подтверждённым диагнозом любому из собранных вами идентификаторов, и рассчитывает риск заражения."</string>
|
||||
<string name="exposure_enable_switch">Использовать уведомления о риске инфицирования</string>
|
||||
<string name="exposure_confirm_start_title">Включить уведомлений о риске инфицирования?</string>
|
||||
<string name="exposure_confirm_start_summary">"Ваш телефон должен использовать Bluetooth для безопасного сбора и распространения идентификаторов другим телефонам, находящимся поблизости.
|
||||
|
||||
<xliff:g example="Corona-Warn">%1$s</xliff:g> может уведомить вас, если вы пересекались с кем-то, у кого был подтверждён положительный диагноз.
|
||||
|
||||
Дата, продолжительность и мощность сигнала, связанные с контактом, будут переданы приложению."</string>
|
||||
<string name="exposure_confirm_start_button">Включить</string>
|
||||
<string name="exposure_confirm_stop_title">Выключить уведомления о риске инфицирования?</string>
|
||||
<string name="exposure_confirm_stop_summary">После отключения уведомлений вы больше не будете получать уведомления о контактах с кем-то, у кого был положительный диагноз.</string>
|
||||
<string name="exposure_confirm_stop_button">Выключить</string>
|
||||
<string name="exposure_confirm_keys_title">Делиться вашими идентификаторами с <xliff:g example="Corona-Warn">%1$s</xliff:g>?</string>
|
||||
<string name="exposure_confirm_keys_summary">"Ваши идентификаторы за последние 14 дней будут использоваться для уведомления других о том, что вы были вблизи потенциальной опасности.
|
||||
|
||||
Ваша личность или результат теста не будут переданы другим людям."</string>
|
||||
<string name="exposure_confirm_keys_button">Поделиться</string>
|
||||
<string name="exposure_confirm_permission_description">Для <xliff:g example="microG Services">%1$s</xliff:g> требуются дополнительные разрешения.</string>
|
||||
<string name="exposure_confirm_permission_button">Предоставить</string>
|
||||
<string name="exposure_confirm_bluetooth_description">Bluetooth должен быть включён.</string>
|
||||
<string name="exposure_confirm_location_description">требуется доступ к местоположению.</string>
|
||||
<string name="exposure_confirm_button">Включить</string>
|
||||
<string name="pref_exposure_error_nearby_not_granted_title">Требуется дополнительное разрешение</string>
|
||||
<string name="pref_exposure_error_nearby_not_granted_description">Нажмите, чтобы предоставить необходимые разрешения уведомлениям о риске инфицирования</string>
|
||||
<string name="exposure_grant_background_location_description">Почти готово! Вам нужно будет включить фоновый доступ к местоположению, выбрав опцию \'Разрешить в любом режиме\' на следующем экране. Затем вернитесь назад.</string>
|
||||
<string name="exposure_grant_background_location_button">Обновить настройки</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
</resources>
|
||||
68
play-services-nearby/core/src/main/res/values-sr/strings.xml
Normal file
68
play-services-nearby/core/src/main/res/values-sr/strings.xml
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="pref_exposure_app_last_report_summary_encounters_prefix">Пријављено <xliff:g example="3"> %1$d</xliff:g> случајева изложености:</string>
|
||||
<string name="pref_exposure_app_report_entry_combined"><xliff:g example="About 12 minutes">%1$s</xliff:g>, <xliff:g example="distant exposure">%2$s</xliff:g></string>
|
||||
<string name="pref_exposure_app_api_usage_title">Употреба API-ја у последњих 14 дана</string>
|
||||
<string name="pref_exposure_rpi_export_summary">Извезите прикупљене ID-ове за проширену анализу помоћу друге апликације.</string>
|
||||
<string name="exposure_notify_off_bluetooth_location">Bluetooth и приступ локацији морају бити омогућени да бисте примали обавештења о изложености.</string>
|
||||
<string name="exposure_confirm_stop_button">Искључи</string>
|
||||
<string name="pref_exposure_advertising_id_title">Тренутно емитовани ID</string>
|
||||
<string name="exposure_confirm_start_title">Укључити обавештења о изложености\?</string>
|
||||
<string name="pref_exposure_error_bluetooth_unsupported_summary">Нажалост, ваш уређај није компатибилан са обавештењима о изложености.</string>
|
||||
<string name="pref_exposure_collected_rpis_title">Прикупљени ID-ови</string>
|
||||
<string name="pref_exposure_error_nearby_not_granted_description">Додирните да бисте дали потребне дозволе за обавештења о изложености</string>
|
||||
<string name="pref_exposure_app_report_entry_time_short">Мање од 5 минута</string>
|
||||
<string name="pref_exposure_app_last_report_summary_encounters_no">Нема пријављених случајева изложености.</string>
|
||||
<string name="pref_exposure_app_report_entry_distance_far">удаљена изложеност</string>
|
||||
<string name="exposure_confirm_keys_title">Делити ваш ID са <xliff:g example="Corona-Warn"> %1$s</xliff:g>\?</string>
|
||||
<string name="exposure_enable_switch">Користи обавештења о изложености</string>
|
||||
<string name="pref_exposure_app_last_report_summary_diagnosis_keys">Обрађено <xliff:g example="121031"> %1$d</xliff:g> кључева за дијагнозу.</string>
|
||||
<string name="pref_exposure_rpi_export_title">Извоз</string>
|
||||
<string name="pref_exposure_rpis_histogram_legend_records"><xliff:g example="0 - 50">%1$s</xliff:g> ID-ова по сату</string>
|
||||
<string name="exposure_notify_off_title">Обавештења о изложености су неактивна</string>
|
||||
<string name="pref_exposure_app_report_updated_title">Ажурирано: <xliff:g example="Today, 14:02"> %1$s</xliff:g></string>
|
||||
<string name="exposure_grant_background_location_button">Ажурирај подешавања</string>
|
||||
<string name="pref_exposure_error_location_off_title">Отвори подешавања локације</string>
|
||||
<string name="pref_exposure_rpis_details_summary">Док је API за обавештења о изложености омогућен, ваш уређај пасивно прикупља ID-ове (који се називају Rolling Proximity Identifiers или RPI) са оближњих уређаја.
|
||||
\n
|
||||
\nКада власници уређаја пријаве да су позитивни, њихови ID-ови могу да се деле. Ваш уређај проверава да ли се неки од познатих дијагностикованих ID-ова поклапа са било којим од прикупљених ID-ова и израчунава ризик од инфекције.</string>
|
||||
<string name="pref_exposure_info_summary">API за обавештења о изложености (Exposure Notifications API) омогућава апликацијама да вас обавесте ако сте били изложени некоме ко је пријавио да је позитиван.
|
||||
\n
|
||||
\nДатум, трајање и јачина сигнала повезани са изложеношћу ће се делити са одговарајућом апликацијом.</string>
|
||||
<string name="pref_exposure_app_api_usage_summary_line"><xliff:g example="12">%1$d</xliff:g> позива на <xliff:g example="provideDiagnosisKeys">%2$s</xliff:g></string>
|
||||
<string name="pref_exposure_enable_info_summary">Да бисте омогућили обавештења о изложености, отворите било коју апликацију која то подржава.</string>
|
||||
<string name="pref_exposure_rpi_delete_all_summary">Избришите све прикупљене ID-ове</string>
|
||||
<string name="exposure_confirm_permission_description"><xliff:g example="microG Services">%1$s</xliff:g> треба додатне дозволе.</string>
|
||||
<string name="service_name_exposure">Обавештења о изложености</string>
|
||||
<string name="pref_exposure_app_report_entry_distance_close">оближња изложеност</string>
|
||||
<string name="exposure_confirm_permission_button">Дај</string>
|
||||
<string name="exposure_notify_off_bluetooth">Bluetooth треба да буде омогућен да бисте примали обавештења о изложености.</string>
|
||||
<string name="pref_exposure_rpi_delete_all_warning_confirm_button">Избриши свакако</string>
|
||||
<string name="pref_exposure_app_last_report_summary_encounters_suffix">Напомена: Оцену ризика дефинише апликација. Високи бројеви могу се односити на низак ризик или обрнуто.</string>
|
||||
<string name="exposure_confirm_location_description">Приступ локацији је неопходан.</string>
|
||||
<string name="pref_exposure_error_bluetooth_no_advertise_summary">Нажалост, ваш уређај је само делимично компатибилан са обавештењима о изложености. Можете бити обавештени за ризичне контакте, али нећете моћи да обавестите друге.</string>
|
||||
<string name="exposure_confirm_bluetooth_description">Bluetooth треба да буде омогућен.</string>
|
||||
<string name="exposure_confirm_start_button">Укључи</string>
|
||||
<string name="prefcat_exposure_rpis_histogram_title"><xliff:g example="230">%1$d</xliff:g> ID-ова прикупљено</string>
|
||||
<string name="pref_exposure_collected_rpis_summary"><xliff:g example="63">%1$d</xliff:g> ID-ова у последњем сату</string>
|
||||
<string name="exposure_notify_off_location">Приступ локацији је неопходан да бисте примали обавештења о изложености.</string>
|
||||
<string name="prefcat_exposure_apps_title">Апликације које користе обавештења о изложености</string>
|
||||
<string name="exposure_confirm_stop_summary">Након што онемогућите обавештења о изложености, више нећете бити обавештени када сте били изложени некоме ко је пријавио да је позитиван.</string>
|
||||
<string name="pref_exposure_app_last_report_summary_encounters_line"><xliff:g example="Yesterday, 12:00 - 14:00">%1$s</xliff:g>, оцена ризика <xliff:g example="99">%2$d</xliff:g></string>
|
||||
<string name="exposure_confirm_stop_title">Искључити обавештења о изложености\?</string>
|
||||
<string name="exposure_confirm_keys_summary">Ваши ID-ови из последњих 14 дана ће се користити за обавештавање других да сте били у близини о потенцијалној изложености.
|
||||
\n
|
||||
\nВаш идентитет или резултат теста се неће делити са другим људима.</string>
|
||||
<string name="exposure_confirm_start_summary">Ваш телефон мора да користи Bluetooth за безбедно прикупљање и дељење ID-ова са другим телефонима који су у близини.\n\n<xliff:g example="Corona-Warn"> %1$s</xliff:g> може да вас обавести ако сте били изложени некоме ко је пријавио да је позитиван.\n\nДатум, трајање и јачина сигнала повезани са изложеношћу ће се делити са апликацијом.</string>
|
||||
<string name="pref_exposure_rpis_histogram_legend_no_records">Нема записа</string>
|
||||
<string name="pref_exposure_rpi_delete_all_title">Избриши</string>
|
||||
<string name="pref_exposure_error_nearby_not_granted_title">Нове дозволе су неопходне</string>
|
||||
<string name="prefcat_exposure_app_report_title">Пријављене изложености</string>
|
||||
<string name="exposure_notify_off_nearby">Обавештења о изложености захтевају додатне дозволе за рад</string>
|
||||
<string name="pref_exposure_rpi_delete_all_warning">Брисањем прикупљених ID-ова биће немогуће да вас обавестимо у случају да се дијагностикује било који од ваших контаката у последњих 14 дана.</string>
|
||||
<string name="exposure_confirm_keys_button">Дели</string>
|
||||
<string name="exposure_grant_background_location_description">Скоро готово! Мораћете да омогућите приступ локацији у позадини тако што ћете на следећем екрану изабрати опцију „Дозволи све време“. Затим притисните назад.</string>
|
||||
<string name="exposure_confirm_button">Омогући</string>
|
||||
<string name="pref_exposure_error_bluetooth_off_title">Омогући Bluetooth</string>
|
||||
<string name="pref_exposure_app_report_entry_time_about">Око <xliff:g example="13"> %1$d</xliff:g> минута</string>
|
||||
</resources>
|
||||
68
play-services-nearby/core/src/main/res/values-sv/strings.xml
Normal file
68
play-services-nearby/core/src/main/res/values-sv/strings.xml
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="pref_exposure_app_last_report_summary_encounters_prefix">Rapporterade <xliff:g example="3">%1$d</xliff:g> exponeringsmöten:</string>
|
||||
<string name="pref_exposure_app_report_entry_combined"><xliff:g example="About 12 minutes">%1$s</xliff:g>, <xliff:g example="distant exposure">%2$s</xliff:g></string>
|
||||
<string name="pref_exposure_app_api_usage_title">API-användning senaste 14 dagarna</string>
|
||||
<string name="pref_exposure_rpi_export_summary">Exportera insamlade ID:n för utökad analys med en annan app.</string>
|
||||
<string name="exposure_notify_off_bluetooth_location">Bluetooth och platsåtkomst måste vara aktiverat för att ta emot exponeringsmeddelanden.</string>
|
||||
<string name="exposure_confirm_stop_button">Stäng av</string>
|
||||
<string name="pref_exposure_advertising_id_title">För närvarande sänt ID</string>
|
||||
<string name="exposure_confirm_start_title">Vill du slå på exponeringsmeddelanden?</string>
|
||||
<string name="pref_exposure_error_bluetooth_unsupported_summary">Din enhet är inte kompatibel med exponeringsmeddelanden.</string>
|
||||
<string name="pref_exposure_collected_rpis_title">Insamlade ID:n</string>
|
||||
<string name="pref_exposure_error_nearby_not_granted_description">Tryck för att bevilja nödvändiga behörigheter för exponeringsmeddelanden</string>
|
||||
<string name="pref_exposure_app_report_entry_time_short">Mindre än 5 minuter</string>
|
||||
<string name="pref_exposure_app_last_report_summary_encounters_no">Inga exponeringsmöten rapporterade.</string>
|
||||
<string name="pref_exposure_app_report_entry_distance_far">avlägsen exponering</string>
|
||||
<string name="exposure_confirm_keys_title">Dela dina ID:n med <xliff:g example="Corona-Warn">%1$s</xliff:g>\?</string>
|
||||
<string name="exposure_enable_switch">Använd exponeringsmeddelanden</string>
|
||||
<string name="pref_exposure_app_last_report_summary_diagnosis_keys">Bearbetade <xliff:g example="121031">%1$d</xliff:g> diagnosnycklar.</string>
|
||||
<string name="pref_exposure_rpi_export_title">Exportera</string>
|
||||
<string name="pref_exposure_rpis_histogram_legend_records"><xliff:g example="0 - 50">%1$s</xliff:g> ID:n per timma</string>
|
||||
<string name="exposure_notify_off_title">Exponeringsmeddelanden inaktiv</string>
|
||||
<string name="pref_exposure_app_report_updated_title">Uppdaterat: <xliff:g example="Today, 14:02">%1$s</xliff:g></string>
|
||||
<string name="exposure_grant_background_location_button">Uppdatera inställningar</string>
|
||||
<string name="pref_exposure_error_location_off_title">Öppna platsinställningar</string>
|
||||
<string name="pref_exposure_rpis_details_summary">När API:et för exponeringsmeddelanden är aktiverat samlar enheten passivt in ID:n (kallas RPI:er (Rolling Proximity Identifiers) från enheter i din närhet.
|
||||
\n
|
||||
\nNär enhetsägare rapporterar att de har diagnostiserats positivt kan deras ID:n delas. Enheten kontrollerar om något av de kända diagnostiserade ID:na matchar något av de insamlade ID:na och beräknar infektionsrisken.</string>
|
||||
<string name="pref_exposure_info_summary">Med API:et för avisering om exponering kan appar meddela dig om du har exponerats för någon som har rapporterats positivt diagnostiserad.
|
||||
\n
|
||||
\nDatum, varaktighet och signalstyrka i samband med en exponering kommer att delas med motsvarande app.</string>
|
||||
<string name="pref_exposure_app_api_usage_summary_line"><xliff:g example="12">%1$d</xliff:g> anrop till <xliff:g example="provideDiagnosisKeys">%2$s</xliff:g></string>
|
||||
<string name="pref_exposure_enable_info_summary">För att aktivera exponeringsmeddelanden öppnar du någon app som stödjer det.</string>
|
||||
<string name="pref_exposure_rpi_delete_all_summary">Ta bort alla insamlade ID:n</string>
|
||||
<string name="exposure_confirm_permission_description"><xliff:g example="microG Services">%1$s</xliff:g> behöver ytterligare behörigheter.</string>
|
||||
<string name="service_name_exposure">Exponeringsmeddelanden</string>
|
||||
<string name="pref_exposure_app_report_entry_distance_close">närliggande exponering</string>
|
||||
<string name="exposure_confirm_permission_button">Bevilja</string>
|
||||
<string name="exposure_notify_off_bluetooth">Bluetooth måste vara aktivt för att ta emot exponeringsmeddelanden.</string>
|
||||
<string name="pref_exposure_rpi_delete_all_warning_confirm_button">Ta bort ändå</string>
|
||||
<string name="pref_exposure_app_last_report_summary_encounters_suffix">Notis: Riskpoängen definieras av appen. Höga siffror kan referera till låg risk och vice versa.</string>
|
||||
<string name="exposure_confirm_location_description">Platsåtkomst krävs.</string>
|
||||
<string name="pref_exposure_error_bluetooth_no_advertise_summary">Din enhet är endast delvis kompatibel med exponeringsmeddelanden. Du kan aviseras för riskkontakter men kommer inte att kunna meddela andra.</string>
|
||||
<string name="exposure_confirm_bluetooth_description">Bluetooth måste aktiveras.</string>
|
||||
<string name="exposure_confirm_start_button">Slå på</string>
|
||||
<string name="prefcat_exposure_rpis_histogram_title"><xliff:g example="230">%1$d</xliff:g> ID:n insamlade</string>
|
||||
<string name="pref_exposure_collected_rpis_summary"><xliff:g example="63">%1$d</xliff:g> ID:n senaste timman</string>
|
||||
<string name="exposure_notify_off_location">Platsåtkomst krävs för att ta emot exponeringsmeddelanden.</string>
|
||||
<string name="prefcat_exposure_apps_title">Appar som använder exponeringsmeddelanden</string>
|
||||
<string name="exposure_confirm_stop_summary">Efter inaktivering av exponeringsmeddelanden kommer du inte längre att meddelas när du exponerats för någon som rapporterats positivt diagnostiserad.</string>
|
||||
<string name="pref_exposure_app_last_report_summary_encounters_line"><xliff:g example="Yesterday, 12:00 - 14:00">%1$s</xliff:g>, riskpoäng <xliff:g example="99">%2$d</xliff:g></string>
|
||||
<string name="exposure_confirm_stop_title">Vill du slå av exponeringsmeddelanden?</string>
|
||||
<string name="exposure_confirm_keys_summary">Dina ID:n från de senaste 14 dagarna kommer att användas för att informera andra i din närhet, om potentiell exponering.
|
||||
\n
|
||||
\nDin identitet eller testresultat kommer inte att delas med andra människor.</string>
|
||||
<string name="exposure_confirm_start_summary">Din telefon behöver använda blåtand för att säkert identifiera och dela ID:n med andra närliggande telefoner.\n\n<xliff:g example="Corona-Warn">%1$s</xliff:g> kan meddela dig om du exponerats för någon som rapporterats positivt diagnostiserad. \n\nDatum, varaktighet och signalstyrka i samband med en exponering kommer att delas med appen.</string>
|
||||
<string name="pref_exposure_rpis_histogram_legend_no_records">Inga poster</string>
|
||||
<string name="pref_exposure_rpi_delete_all_title">Ta bort</string>
|
||||
<string name="pref_exposure_error_nearby_not_granted_title">Nya behörigheter krävs</string>
|
||||
<string name="prefcat_exposure_app_report_title">Rapporterade exponeringar</string>
|
||||
<string name="exposure_notify_off_nearby">Exponeringsmeddelanden kräver ytterligare behörigheter för att fungera</string>
|
||||
<string name="pref_exposure_rpi_delete_all_warning">Borttagning av insamlade ID:n kommer att göra det omöjligt att meddela dig om någon av dina kontakter de senaste 14 dagarna diagnostiseras.</string>
|
||||
<string name="exposure_confirm_keys_button">Dela</string>
|
||||
<string name="exposure_grant_background_location_description">Nästan där! Du måste aktivera bakgrundsåtkomst till platsinformation genom att välja alternativet \"Tillåt hela tiden\" på nästa sida. Tryck sedan tillbaka.</string>
|
||||
<string name="exposure_confirm_button">Aktivera</string>
|
||||
<string name="pref_exposure_error_bluetooth_off_title">Aktivera Bluetooth</string>
|
||||
<string name="pref_exposure_app_report_entry_time_about">Ungefär <xliff:g example="13">%1$d</xliff:g> minuter</string>
|
||||
</resources>
|
||||
62
play-services-nearby/core/src/main/res/values-ta/strings.xml
Normal file
62
play-services-nearby/core/src/main/res/values-ta/strings.xml
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="exposure_notify_off_title">வெளிப்பாடு அறிவிப்புகள் செயலற்றவை</string>
|
||||
<string name="exposure_notify_off_bluetooth">வெளிப்பாடு அறிவிப்புகளைப் பெற ஊடலை இயக்கப்பட வேண்டும்.</string>
|
||||
<string name="exposure_notify_off_location">வெளிப்பாடு அறிவிப்புகளைப் பெற இருப்பிட அணுகல் தேவை.</string>
|
||||
<string name="service_name_exposure">வெளிப்பாடு அறிவிப்புகள்</string>
|
||||
<string name="exposure_confirm_start_button">இயக்கவும்</string>
|
||||
<string name="exposure_confirm_stop_title">வெளிப்பாடு அறிவிப்புகளை அணைக்கவா?</string>
|
||||
<string name="exposure_confirm_stop_button">அணைக்கவும்</string>
|
||||
<string name="exposure_confirm_keys_button">பங்கு</string>
|
||||
<string name="exposure_confirm_permission_button">மானியம்</string>
|
||||
<string name="pref_exposure_app_report_entry_distance_close">அருகிலுள்ள வெளிப்பாடு</string>
|
||||
<string name="pref_exposure_app_report_entry_distance_far">தொலைதூர வெளிப்பாடு</string>
|
||||
<string name="exposure_notify_off_bluetooth_location">வெளிப்பாடு அறிவிப்புகளைப் பெற ஊடலை மற்றும் இருப்பிட அணுகல் இயக்கப்பட வேண்டும்.</string>
|
||||
<string name="exposure_notify_off_nearby">வெளிப்பாடு அறிவிப்புகளுக்கு வேலை செய்ய கூடுதல் அனுமதிகள் தேவை</string>
|
||||
<string name="pref_exposure_enable_info_summary">வெளிப்பாடு அறிவிப்புகளை இயக்க, அதை ஆதரிக்கும் எந்த பயன்பாட்டையும் திறக்கவும்.</string>
|
||||
<string name="pref_exposure_error_bluetooth_off_title">புளூடூத்தை இயக்கவும்</string>
|
||||
<string name="pref_exposure_error_location_off_title">இருப்பிட அமைப்புகளைத் திறக்கவும்</string>
|
||||
<string name="pref_exposure_error_bluetooth_unsupported_summary">துரதிர்ச்டவசமாக, உங்கள் சாதனம் வெளிப்பாடு அறிவிப்புகளுடன் பொருந்தாது.</string>
|
||||
<string name="pref_exposure_error_bluetooth_no_advertise_summary">துரதிர்ச்டவசமாக, உங்கள் சாதனம் வெளிப்பாடு அறிவிப்புகளுடன் ஓரளவு மட்டுமே இணக்கமானது. இடர் தொடர்புகளுக்கு உங்களுக்கு அறிவிக்கப்படலாம், ஆனால் மற்றவர்களுக்கு அறிவிக்க முடியாது.</string>
|
||||
<string name="prefcat_exposure_apps_title">வெளிப்பாடு அறிவிப்புகளைப் பயன்படுத்தும் பயன்பாடுகள்</string>
|
||||
<string name="pref_exposure_collected_rpis_title">சேகரிக்கப்பட்ட ஐடிஎச்</string>
|
||||
<string name="pref_exposure_advertising_id_title">தற்போது ஒளிபரப்பப்பட்ட ஐடி</string>
|
||||
<string name="prefcat_exposure_app_report_title">அறிவிக்கப்பட்ட வெளிப்பாடுகள்</string>
|
||||
<string name="pref_exposure_app_report_entry_time_short">5 நிமிடங்களுக்கும் குறைவாக</string>
|
||||
<string name="pref_exposure_app_last_report_summary_encounters_no">வெளிப்பாடு சந்திப்புகள் எதுவும் தெரிவிக்கப்படவில்லை.</string>
|
||||
<string name="pref_exposure_app_last_report_summary_encounters_suffix">குறிப்பு: இடர் மதிப்பெண் பயன்பாட்டால் வரையறுக்கப்படுகிறது. அதிக எண்கள் குறைந்த ஆபத்தை குறிக்கலாம் அல்லது நேர்மாறாக இருக்கலாம்.</string>
|
||||
<string name="pref_exposure_app_api_usage_title">கடந்த 14 நாட்களில் பநிஇ பயன்பாடு</string>
|
||||
<string name="pref_exposure_rpis_histogram_legend_no_records">பதிவுகள் இல்லை</string>
|
||||
<string name="pref_exposure_rpi_delete_all_title">நீக்கு</string>
|
||||
<string name="pref_exposure_rpi_delete_all_summary">சேகரிக்கப்பட்ட அனைத்து ஐடிகளையும் நீக்கு</string>
|
||||
<string name="pref_exposure_rpi_delete_all_warning">சேகரிக்கப்பட்ட ஐடிகளை நீக்குவது கடந்த 14 நாட்களில் உங்கள் தொடர்புகள் ஏதேனும் கண்டறியப்பட்டால் உங்களுக்குத் தெரிவிக்க இயலாது.</string>
|
||||
<string name="pref_exposure_rpi_delete_all_warning_confirm_button">எப்படியும் நீக்கு</string>
|
||||
<string name="pref_exposure_rpi_export_title">ஏற்றுமதி</string>
|
||||
<string name="pref_exposure_rpi_export_summary">மற்றொரு பயன்பாட்டுடன் நீட்டிக்கப்பட்ட பகுப்பாய்விற்கு சேகரிக்கப்பட்ட ஐடிகளை ஏற்றுமதி செய்யுங்கள்.</string>
|
||||
<string name="pref_exposure_info_summary">வெளிப்பாடு அறிவிப்புகள் பநிஇ நேர்மறையாக கண்டறியப்பட்டதாகக் கூறப்படும் ஒருவரை நீங்கள் வெளிப்படுத்தியிருந்தால் பயன்பாடுகள் உங்களுக்குத் தெரிவிக்க அனுமதிக்கிறது.\n\n வெளிப்பாட்டுடன் தொடர்புடைய தேதி, காலம் மற்றும் சமிக்ஞை வலிமை ஆகியவை தொடர்புடைய பயன்பாட்டுடன் பகிரப்படும்.</string>
|
||||
<string name="pref_exposure_rpis_details_summary">வெளிப்பாடு அறிவிப்பு பநிஇ இயக்கப்பட்டிருந்தாலும், அருகிலுள்ள சாதனங்களிலிருந்து உங்கள் சாதனம் செயலற்ற முறையில் ஐடிஎச் (ரோலிங் ப்ராக்சிமிட்டி அடையாளங்காட்டிகள் அல்லது ஆர்.பி.ஐ.எச்) சேகரிக்கிறது.\n\n சாதன உரிமையாளர்கள் நேர்மறையாக கண்டறியப்படுவதாக புகாரளிக்கும் போது, அவர்களின் ஐடிகளை பகிரலாம். அறியப்பட்ட கண்டறியப்பட்ட ஐடிஎச் ஏதேனும் சேகரிக்கப்பட்ட ஐடிகளுடன் பொருந்தக்கூடியது மற்றும் உங்கள் தொற்று அபாயத்தை கணக்கிடுகிறது என்றால் உங்கள் சாதனம் சரிபார்க்கிறது.</string>
|
||||
<string name="exposure_enable_switch">வெளிப்பாடு அறிவிப்புகளைப் பயன்படுத்துங்கள்</string>
|
||||
<string name="exposure_confirm_start_title">வெளிப்பாடு அறிவிப்புகளை இயக்கவா?</string>
|
||||
<string name="exposure_confirm_stop_summary">வெளிப்பாடு அறிவிப்புகளை முடக்கிய பிறகு, நேர்மறையானதாகக் கண்டறியப்பட்டதாகக் கூறப்படும் ஒருவருக்கு நீங்கள் வெளிப்படும் போது உங்களுக்கு இனி அறிவிக்கப்படாது.</string>
|
||||
<string name="exposure_confirm_keys_summary">கடந்த 14 நாட்களிலிருந்து உங்கள் ஐடிகள் சாத்தியமான வெளிப்பாடு குறித்து நீங்கள் இருந்ததாக மற்றவர்களுக்கு அறிவிக்க உதவும்.\n\n உங்கள் அடையாளம் அல்லது சோதனை முடிவு மற்றவர்களுடன் பகிரப்படாது.</string>
|
||||
<string name="exposure_confirm_bluetooth_description">ஊடலை இயக்கப்பட வேண்டும்.</string>
|
||||
<string name="exposure_confirm_location_description">இருப்பிட அணுகல் தேவை.</string>
|
||||
<string name="exposure_confirm_button">இயக்கு</string>
|
||||
<string name="pref_exposure_error_nearby_not_granted_title">புதிய அனுமதிகள் தேவை</string>
|
||||
<string name="pref_exposure_error_nearby_not_granted_description">வெளிப்பாடு அறிவிப்புகளுக்கு தேவையான அனுமதிகளை வழங்க தட்டவும்</string>
|
||||
<string name="exposure_grant_background_location_description">கிட்டத்தட்ட அங்கே! அடுத்த திரையில் \'எல்லா நேரத்தையும் அனுமதிக்கவும்\' விருப்பத்தைத் தேர்ந்தெடுப்பதன் மூலம் பின்னணி இருப்பிட அணுகலை நீங்கள் இயக்க வேண்டும். பின்னர் மீண்டும் அழுத்தவும்.</string>
|
||||
<string name="exposure_grant_background_location_button">அமைப்புகளை புதுப்பிக்கவும்</string>
|
||||
<string name="pref_exposure_app_api_usage_summary_line"><XLIFF: g எடுத்துக்காட்டு = \"12\">%1$d </xliff: g> <xliff: g எடுத்துக்காட்டு = \"pandiagnosiskeys\">%2$s </xliff: g></string>
|
||||
<string name="prefcat_exposure_rpis_histogram_title"><xliff: g எடுத்துக்காட்டு = \"230\">%1$d </xliff: g> ஐடிகள் சேகரிக்கப்பட்டன</string>
|
||||
<string name="pref_exposure_rpis_histogram_legend_records"><xliff: g எடுத்துக்காட்டு = \"0 - 50\">%1$s </xliff: g> ஒரு மணி நேரத்திற்கு ஐடிஎச்</string>
|
||||
<string name="exposure_confirm_start_summary">உங்கள் தொலைபேசி புளூடூத்தை பாதுகாப்பாக சேகரிக்கவும், அருகிலுள்ள பிற தொலைபேசிகளுடன் ஐடிகளைப் பகிரவும் வேண்டும்.\n\n <xliff: g எடுத்துக்காட்டு = \"கொரோனா-வார்ன்\">%1$s </xliff: g> நேர்மறை கண்டறியப்பட்டதாக அறிவித்த ஒருவருக்கு நீங்கள் வெளிப்பட்டால் உங்களுக்கு அறிவிக்க முடியும். வெளிப்பாட்டுடன் தொடர்புடைய தேதி, காலம் மற்றும் சமிக்ஞை வலிமை பயன்பாட்டுடன் பகிரப்படும்.</string>
|
||||
<string name="exposure_confirm_permission_description"><xliff: g எடுத்துக்காட்டு = \"மைக்ரோக் சேவைகள்\">%1$s </xliff: g> கூடுதல் அனுமதிகள் தேவை.</string>
|
||||
<string name="pref_exposure_app_report_updated_title">புதுப்பிக்கப்பட்டது: <xliff: g எடுத்துக்காட்டு = \"இன்று, 14:02\">%1$s </xliff: g></string>
|
||||
<string name="pref_exposure_app_report_entry_time_about"><Xliff: g எடுத்துக்காட்டு = \"13\">%1$d </xliff: g> நிமிடங்கள்</string>
|
||||
<string name="pref_exposure_app_report_entry_combined"><xliff: g எடுத்துக்காட்டு = \"சுமார் 12 நிமிடங்கள்\">%1$s </xliff: g>, <xliff: g எடுத்துக்காட்டு = \"தொலைதூர வெளிப்பாடு\">%2$s </xliff: g></string>
|
||||
<string name="pref_exposure_app_last_report_summary_encounters_line"><xliff: g எடுத்துக்காட்டு = \"நேற்று, 12:00 - 14:00\">%1$s </xliff: g>, இடர் மதிப்பெண் <xliff: g எடுத்துக்காட்டு = \"99\">%2$d </xliff: g></string>
|
||||
<string name="pref_exposure_app_last_report_summary_diagnosis_keys">செயலாக்கப்பட்ட <xliff: g எடுத்துக்காட்டு = \"121031\">%1$d </xliff: g> நோயறிதல் விசைகள்.</string>
|
||||
<string name="pref_exposure_collected_rpis_summary"><xliff: g எடுத்துக்காட்டு = \"63\">%1$d </xliff: g> ஐடிஎச் கடைசி மணி நேரத்தில்</string>
|
||||
<string name="pref_exposure_app_last_report_summary_encounters_prefix">அறிவிக்கப்பட்ட <xliff: g எடுத்துக்காட்டு = \"3\">%1$d </xliff: g> வெளிப்பாடு சந்திப்புகள்:</string>
|
||||
<string name="exposure_confirm_keys_title">உங்கள் ஐடிகளை <xliff: g எடுத்துக்காட்டு = \"கொரோனா-வார்ன்\">%1$s </xliff: g> உடன் பகிர்ந்து கொள்ளுங்கள்?</string>
|
||||
</resources>
|
||||
62
play-services-nearby/core/src/main/res/values-th/strings.xml
Normal file
62
play-services-nearby/core/src/main/res/values-th/strings.xml
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="exposure_notify_off_title">ระบบแจ้งเตือนเมื่อใกล้ชิดผู้ติดเชื้อ ถูกปิดการใช้งาน</string>
|
||||
<string name="exposure_notify_off_bluetooth">จำเป็นต้องเปิดใช้งาน Bluetooth เพื่อรับข้อมูลจากระบบแจ้งเตือนเมื่อใกล้ชิดผู้ติดเชื้อ</string>
|
||||
<string name="exposure_notify_off_location">จำเป็นต้องเข้าถึงตำแหน่งเพื่อรับข้อมูลจากระบบแจ้งเตือนเมื่อใกล้ชิดผู้ติดเชื้อ</string>
|
||||
<string name="exposure_notify_off_bluetooth_location">จำเป็นต้องเปิดใช้งานบลูทูธและการเข้าถึงตำแหน่งเพื่อรับข้อมูลจากระบบแจ้งเตือนเมื่อใกล้ชิดผู้ติดเชื้อ</string>
|
||||
<string name="service_name_exposure">ระบบแจ้งเตือนเมื่อใกล้ชิดผู้ติดเชื้อ</string>
|
||||
<string name="pref_exposure_enable_info_summary">เพื่อเปิดการใช้งานระบบแจ้งเตือนเมื่อใกล้ชิดผู้ติดเชื้อ ให้เปิดแอปใด ๆ ที่รองรับ</string>
|
||||
<string name="pref_exposure_error_bluetooth_off_title">เปิดใช้งาน Bluetooth</string>
|
||||
<string name="pref_exposure_error_bluetooth_no_advertise_summary">ขออภัย อุปกรณ์ของคุณเข้ากันได้กับการแจ้งเตือนข้อมูลจากระบบแจ้งเตือนเมื่อใกล้ชิดผู้ติดเชื้อเพียงบางส่วนเท่านั้น คุณสามารถรับการแจ้งเตือนเกี่ยวกับผู้ติดต่อที่มีความเสี่ยงได้ แต่จะไม่สามารถแจ้งเตือนผู้อื่นได้</string>
|
||||
<string name="pref_exposure_error_bluetooth_unsupported_summary">ขออภัย อุปกรณ์ของคุณไม่รองรับข้อมูลจากระบบแจ้งเตือนเมื่อใกล้ชิดผู้ติดเชื้อ</string>
|
||||
<string name="prefcat_exposure_apps_title">แอปกำลังใช้ข้อมูลจากระบบแจ้งเตือนเมื่อใกล้ชิดผู้ติดเชื้อ</string>
|
||||
<string name="pref_exposure_collected_rpis_title">เก็บรวบรวมรหัสประจำตัว</string>
|
||||
<string name="pref_exposure_advertising_id_title">รหัสที่กำลังกระจายสัญญาณในปัจจุบัน</string>
|
||||
<string name="prefcat_exposure_app_report_title">การรายงานความเสี่ยงเข้าใกล้ผู้ป่วยติดเชื้อ</string>
|
||||
<string name="pref_exposure_app_report_updated_title">อัปเดต: <xliff:g example="วันนี้, 14:02">%1$s</xliff:g></string>
|
||||
<string name="pref_exposure_app_report_entry_time_short">น้อยกว่า 5 นาที</string>
|
||||
<string name="pref_exposure_app_report_entry_time_about">เกี่ยวกับ <xliff:g example="13">%1$d</xliff:g> นาที</string>
|
||||
<string name="pref_exposure_app_report_entry_distance_close">ความเสี่ยงในบริเวณใกล้เคียง</string>
|
||||
<string name="pref_exposure_app_report_entry_distance_far">ระยะความเสี่ยง</string>
|
||||
<string name="pref_exposure_app_report_entry_combined"><xliff:g example="ประมาณ 12 นาที">%1$s</xliff:g>, <xliff:g example="ระยะของความเสี่ยง">%2$s</xliff:g></string>
|
||||
<string name="pref_exposure_app_last_report_summary_diagnosis_keys">ประมวลผล <xliff:g example="121031">%1$d</xliff:g>กุญแจสำหรับการวินิจฉัยแล้ว</string>
|
||||
<string name="pref_exposure_app_last_report_summary_encounters_prefix">รายงาน <xliff:g example="3">%1$d</xliff:g> การเข้าปะทะกับผู้ที่มีความเสี่ยงติดเชื้อ:</string>
|
||||
<string name="pref_exposure_app_api_usage_title">การใช้งาน API ในช่วง 14 วันที่ผ่านมา</string>
|
||||
<string name="pref_exposure_app_api_usage_summary_line"><xliff:g example="12">%1$d</xliff:g> เรียกไปยัง <xliff:g example="provideDiagnosisKeys">%2$s</xliff:g></string>
|
||||
<string name="pref_exposure_rpis_histogram_legend_records"><xliff:g example="0 - 50">%1$s</xliff:g> รหัสประจำตัวต่อชั่วโมง</string>
|
||||
<string name="pref_exposure_rpi_delete_all_summary">ลบรหัสประจำตัวทั้งหมด</string>
|
||||
<string name="pref_exposure_rpi_delete_all_warning_confirm_button">ลบต่อไป</string>
|
||||
<string name="pref_exposure_rpi_export_title">ส่งออก</string>
|
||||
<string name="pref_exposure_rpi_export_summary">ส่งออก รหัสประจำตัว ที่เก็บรวบรวมไว้เพื่อการวิเคราะห์เพิ่มเติมด้วยแอปอื่น</string>
|
||||
<string name="exposure_enable_switch">ใช้ระบบแจ้งเตือนเมื่อใกล้ชิดผู้ติดเชื้อ</string>
|
||||
<string name="exposure_confirm_start_title">เปิดใช้งานระบบแจ้งเตือนเมื่อใกล้ชิดผู้ติดเชื้อ?</string>
|
||||
<string name="exposure_confirm_start_button">เปิด</string>
|
||||
<string name="exposure_confirm_stop_title">ปิดระบบแจ้งเตือนเมื่อใกล้ชิดผู้ติดเชื้อ?</string>
|
||||
<string name="exposure_confirm_stop_summary">หลังจากปิดระบบแจ้งเตือนเมื่อใกล้ชิดผู้ติดเชื้อแล้ว คุณจะไม่ได้รับการแจ้งเตือนอีกต่อไปเมื่อคุณสัมผัสกับบุคคลที่รายงานว่าได้รับการวินิจฉัยว่าติดเชื้อ</string>
|
||||
<string name="exposure_confirm_stop_button">ปิด</string>
|
||||
<string name="exposure_confirm_keys_title">แบ่งปัน รหัสประจำตัว ของคุณกับ <xliff:g example="เตือนโควิด">%1$s</xliff:g> ?</string>
|
||||
<string name="exposure_confirm_keys_summary">ข้อมูลประจำตัวของคุณในช่วง 14 วันที่ผ่านมาจะถูกใช้เพื่อแจ้งให้ผู้อื่นทราบว่าคุณอยู่ใกล้ๆ และมีความเสี่ยงต่อการติดเชื้อ\n\nข้อมูลประจำตัวหรือผลการทดสอบของคุณจะไม่ถูกเปิดเผยให้ผู้อื่นทราบ</string>
|
||||
<string name="exposure_confirm_keys_button">แบ่งปัน</string>
|
||||
<string name="exposure_confirm_permission_button">อนุญาต</string>
|
||||
<string name="exposure_confirm_bluetooth_description">จำเป็นต้องเปิดใช้งาน Bluetooth</string>
|
||||
<string name="exposure_confirm_button">เปิดใช้งาน</string>
|
||||
<string name="pref_exposure_error_nearby_not_granted_title">ต้องมีการอนุญาตใหม่</string>
|
||||
<string name="pref_exposure_error_nearby_not_granted_description">แตะเพื่อให้สิทธิ์ที่จำเป็นในการใช้ข้อมูลจากระบบแจ้งเตือนเมื่อใกล้ชิดผู้ติดเชื้อ</string>
|
||||
<string name="pref_exposure_error_location_off_title">เปิดการตั้งค่าตำแหน่ง</string>
|
||||
<string name="pref_exposure_app_last_report_summary_encounters_no">ไม่มีการรายงานความเสี่ยงเข้าใกล้ผู้ติดเชื้อ</string>
|
||||
<string name="exposure_notify_off_nearby">ระบบแจ้งเตือนเมื่อใกล้ชิดผู้ติดเชื้อต้องได้รับอนุญาตเพิ่มเติมจึงจะทำงานได้</string>
|
||||
<string name="pref_exposure_collected_rpis_summary"><xliff:g example="63">%1$d</xliff:g> รหัสประจำตัว ในชั่วโมงที่ผ่านมา</string>
|
||||
<string name="pref_exposure_app_last_report_summary_encounters_line"><xliff:g example="เมื่อวานนี้ 12:00 - 14:00">%1$s</xliff:g> คะแนนความเสี่ยง <xliff:g example="99">%2$d</xliff:g></string>
|
||||
<string name="pref_exposure_app_last_report_summary_encounters_suffix">หมายเหตุ: คะแนนความเสี่ยงถูกกำหนดโดยแอป ตัวเลขสูงอาจหมายถึงความเสี่ยงต่ำหรือในทางกลับกัน</string>
|
||||
<string name="prefcat_exposure_rpis_histogram_title"><xliff:g example="230">%1$d</xliff:g> รวบรวม รหัสประจำตัวแล้ว</string>
|
||||
<string name="pref_exposure_rpi_delete_all_title">ลบ</string>
|
||||
<string name="pref_exposure_rpis_histogram_legend_no_records">ไม่มีข้อมูลบันทึกไว้</string>
|
||||
<string name="pref_exposure_rpi_delete_all_warning">การลบ รหัสประจำตัว ที่เก็บรวบรวมไว้จะทำให้ไม่สามารถแจ้งให้คุณทราบได้ในกรณีที่ผู้ติดต่อของคุณในช่วง 14 วันล่าสุดได้รับการวินิจฉัย</string>
|
||||
<string name="pref_exposure_info_summary">ส่วนเชื่อมต่อกับระบบแจ้งเตือนเมื่อใกล้ชิดผู้ติดเชื้ออนุญาตให้แอปสามารถแจ้งให้คุณทราบหากคุณสัมผัสกับบุคคลที่รายงานว่าได้รับการวินิจฉัยว่าติดเชื้อ\n\nวันที่ ระยะเวลา และความแรงของสัญญาณที่เกี่ยวข้องกับการสัมผัสจะถูกแชร์กับแอปที่เกี่ยวข้อง</string>
|
||||
<string name="pref_exposure_rpis_details_summary">ขณะที่เปิดใช้งาน ของส่วนติดต่อของฟังก์ชั่น “ระบบแจ้งเตือนเมื่อใกล้ชิดผู้ติดเชื้อ” อุปกรณ์ของคุณจะทำการรวบรวม รหัสประจำตัว (เรียกว่า Rolling Proximity Identifiers หรือ RPI) จากอุปกรณ์ใกล้เคียงโดยอัตโนมัติ\n\nเมื่อเจ้าของอุปกรณ์รายงานว่าได้รับการวินิจฉัยว่าเป็นบวก รหัสประจำตัว ของพวกเขาจะถูกแชร์ได้ อุปกรณ์ของคุณจะทำการตรวจสอบว่ามี รหัสประจำตัว ที่ได้รับการวินิจฉัยที่ทราบแล้วตรงกับ รหัสประจำตัว ที่รวบรวมไว้หรือไม่ และคำนวณความเสี่ยงต่อการติดเชื้อของคุณ</string>
|
||||
<string name="exposure_confirm_start_summary">โทรศัพท์ของคุณจำเป็นต้องใช้ Bluetooth เพื่อรวบรวมและแชร์รหัสประจำตัวกับโทรศัพท์เครื่องอื่นที่อยู่ใกล้เคียงอย่างปลอดภัย\n\n<xliff:g example="Corona-Warn">%1$s</xliff:g> สามารถแจ้งเตือนคุณหากคุณสัมผัสกับบุคคลที่รายงานว่าได้รับการวินิจฉัยว่าติดเชื้อ\n\nวันที่ ระยะเวลา และความแรงของสัญญาณที่เกี่ยวข้องกับการสัมผัสจะถูกแชร์กับแอป</string>
|
||||
<string name="exposure_grant_background_location_button">อัปเดตการตั้งค่า</string>
|
||||
<string name="exposure_confirm_permission_description"><xliff:g example="บริการ microG">%1$s</xliff:g> ต้องได้รับการอนุญาตเพิ่มเติม</string>
|
||||
<string name="exposure_confirm_location_description">จำเป็นต้องมีการเข้าถึงตำแหน่ง</string>
|
||||
<string name="exposure_grant_background_location_description">เกือบเสร็จแล้ว! คุณจะต้องเปิดใช้งานการเข้าถึงตำแหน่งพื้นหลังโดยเลือกตัวเลือก \"อนุญาตตลอดเวลา\" ในหน้าจอถัดไป จากนั้นกดย้อนกลับ</string>
|
||||
</resources>
|
||||
62
play-services-nearby/core/src/main/res/values-tr/strings.xml
Normal file
62
play-services-nearby/core/src/main/res/values-tr/strings.xml
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="pref_exposure_error_bluetooth_off_title">Bluetooth\'u etkinleştir</string>
|
||||
<string name="exposure_notify_off_title">Temas Bildirimleri devre dışı</string>
|
||||
<string name="exposure_notify_off_bluetooth">Temas Bildirimleri\'ni almak için Bluetooth\'un etkinleştirilmesi gerekiyor.</string>
|
||||
<string name="exposure_notify_off_location">Temas Bildirimleri\'ni almak için konum izinleri gerekiyor.</string>
|
||||
<string name="exposure_notify_off_bluetooth_location">Temas Bildirimleri\'ni almak için hem Bluetooth hem de konum izinlerinin etkinleştirilmesi gerekiyor.</string>
|
||||
<string name="pref_exposure_enable_info_summary">Temas Bildirimleri\'ni etkinleştirmek için, bu özelliği kullanan bir uygulamayı açın.</string>
|
||||
<string name="pref_exposure_error_location_off_title">Konum ayarlarını aç</string>
|
||||
<string name="prefcat_exposure_apps_title">Temas Bildirimleri kullanan uygulamalar</string>
|
||||
<string name="pref_exposure_collected_rpis_title">Toplanan kimlikler</string>
|
||||
<string name="pref_exposure_error_bluetooth_no_advertise_summary">Ne yazık ki, cihazınız Temas Bildirimleri\'ni sadece kısmen destekliyor. Bu da, kendi riskli temaslarınızdan bilgilendirileceğiniz ancak başkalarını bilgilendiremeyeceğiniz anlamına geliyor.</string>
|
||||
<string name="pref_exposure_advertising_id_title">Şu anki yayınlanan kimlik</string>
|
||||
<string name="pref_exposure_app_report_entry_time_short">5 dakikadan az</string>
|
||||
<string name="pref_exposure_app_report_entry_distance_close">yakın temas</string>
|
||||
<string name="prefcat_exposure_app_report_title">Rapor edilen temaslar</string>
|
||||
<string name="pref_exposure_app_report_updated_title">Güncellendi: <xliff:g example="Today, 14:02">%1$s</xliff:g></string>
|
||||
<string name="pref_exposure_app_report_entry_combined"><xliff:g example="Yaklaşık 12 dakika">%1$s</xliff:g>, <xliff:g example="yakın temas">%2$s</xliff:g></string>
|
||||
<string name="pref_exposure_app_last_report_summary_diagnosis_keys"><xliff:g example="121031">%1$d</xliff:g> teşhis anahtarı işlendi.</string>
|
||||
<string name="pref_exposure_app_api_usage_title">Son 14 gün içinde API kullanımı</string>
|
||||
<string name="pref_exposure_rpis_histogram_legend_no_records">Kayıt yok</string>
|
||||
<string name="prefcat_exposure_rpis_histogram_title"><xliff:g example="230">%1$d</xliff:g> kimlik toplandı</string>
|
||||
<string name="pref_exposure_app_last_report_summary_encounters_prefix"><xliff:g example="3">%1$d</xliff:g> temas karşılaşmaları raporlandı:</string>
|
||||
<string name="pref_exposure_app_last_report_summary_encounters_line"><xliff:g example="Dün, 12:00 - 14:00">%1$s</xliff:g>, risk skoru <xliff:g example="99">%2$d</xliff:g></string>
|
||||
<string name="pref_exposure_rpi_delete_all_title">Sil</string>
|
||||
<string name="pref_exposure_rpi_delete_all_summary">Toplanan tüm kimlikleri sil</string>
|
||||
<string name="pref_exposure_rpi_delete_all_warning_confirm_button">Yine de sil</string>
|
||||
<string name="pref_exposure_rpis_histogram_legend_records">Saat başı <xliff:g example="0 - 50">%1$s</xliff:g> kimlik</string>
|
||||
<string name="pref_exposure_rpi_delete_all_warning">Toplanan kimliklerin silinmesi, son 14 gün içindeki kişilerinizden herhangi birinin teşhis edilmesi durumunda bilgilendirilmenizi imkansız hale getirecektir.</string>
|
||||
<string name="pref_exposure_rpi_export_summary">Veriler ile analiz yapmak için kullanmak üzere toplanan kimlikleri başka bir uygulama ile dışa aktarın.</string>
|
||||
<string name="pref_exposure_info_summary">Temas Bildirimleri API\'si, uygulamaların, daha önceden pozitif teşhis olduğu bildirilen kişilerle temas halinde olmanız durumunda sizi bilgilendirmesine olanak tanır.\n\nBulunduğunuz temasın, tarihi, süresi, ve sinyal menzili, ilgili uygulama ile paylaşılır.</string>
|
||||
<string name="exposure_confirm_start_title">Temas Bildirimleri\'ni etkinleştir?</string>
|
||||
<string name="exposure_enable_switch">Temas Bildirimleri\'ni kullan</string>
|
||||
<string name="exposure_confirm_start_summary">Kimlikleri güvenli bir şekilde toplamak ve yakındaki diğer telefonlarla paylaşmak için telefonunuzun Bluetooth\'u kullanması gerekir.\n\n<xliff:g example="Corona-Warn">%1$s</xliff:g>, pozitif teşhis konduğunu bildiren biriyle temas halindeyseniz sizi bilgilendirebilir.\n\nTemasla ilişkili tarih, süre ve sinyal gücü uygulamayla paylaşılacaktır.</string>
|
||||
<string name="exposure_confirm_start_button">Etkinleştir</string>
|
||||
<string name="exposure_confirm_stop_title">Temas Bildirimleri\'ni devre dışı bırak?</string>
|
||||
<string name="exposure_confirm_stop_summary">Temas Bildirimleri\'ni devre dışı bırakmanız halinde, pozitif teşhis konulduğu bilinen biri ile temasa geçmeniz durumunda bilgilendirilmeyeceksiniz.</string>
|
||||
<string name="exposure_confirm_keys_title">Kimliklerinizi <xliff:g example="Corona-Warn">%1$s</xliff:g> ile paylaşmak istiyor musunuz?</string>
|
||||
<string name="exposure_confirm_permission_button">Yetkilendir</string>
|
||||
<string name="exposure_confirm_location_description">Konum erişimi gerekiyor.</string>
|
||||
<string name="pref_exposure_error_nearby_not_granted_title">Yeni izinler gerekiyor</string>
|
||||
<string name="pref_exposure_error_nearby_not_granted_description">Temas Bildirimleri\'ne gerekli izinleri vermek için dokunun</string>
|
||||
<string name="exposure_grant_background_location_button">Ayarları değiştir</string>
|
||||
<string name="exposure_confirm_permission_description"><xliff:g example="microG Services">%1$s</xliff:g> ek izinlere ihtiyaç duyuyor.</string>
|
||||
<string name="pref_exposure_collected_rpis_summary">Son saat içinde <xliff:g example="63">%1$d</xliff:g> kimlik</string>
|
||||
<string name="pref_exposure_rpi_export_title">Dışa aktar</string>
|
||||
<string name="exposure_confirm_button">Etkinleştir</string>
|
||||
<string name="exposure_confirm_stop_button">Devre dışı bırak</string>
|
||||
<string name="exposure_confirm_bluetooth_description">Bluetooth\'un etkinleştirilmesi gerekiyor.</string>
|
||||
<string name="pref_exposure_error_bluetooth_unsupported_summary">Ne yazık ki, cihazınız Temas Bildirimleri için uyumlu değil.</string>
|
||||
<string name="exposure_confirm_keys_button">Paylaş</string>
|
||||
<string name="service_name_exposure">Temas Bildirimleri</string>
|
||||
<string name="pref_exposure_app_report_entry_distance_far">uzak temas</string>
|
||||
<string name="pref_exposure_app_last_report_summary_encounters_no">Bildirilen bir temas yok.</string>
|
||||
<string name="exposure_notify_off_nearby">Temas Bildirimleri\'nin çalışması için ek izinlere ihtiyaç var</string>
|
||||
<string name="pref_exposure_app_report_entry_time_about">Yaklaşık <xliff:g example="13">%1$d</xliff:g> dakika</string>
|
||||
<string name="pref_exposure_app_last_report_summary_encounters_suffix">Not: Risk skoru uygulama tarafından belirlenir. Yüksek sayılar düşük risk anlamına veya tam tersini olabilir.</string>
|
||||
<string name="pref_exposure_rpis_details_summary">Temas Bildirimleri API\'si etkin iken, cihazınız yakındaki diğer cihazlardan pasif olarak kimlik toplar. (bu kimlikler, Rolling Identifiers, veya RPI olarak da bilinir)\n\nCihaz sahiplerin testi pozitif çıktığı bilindiğinde, kendilerinin kimlikleri paylaşılabilir. Bu sayede, cihazınız, bilinen kimlikler ile toplanan kimlikleri eşleştirir ve enfeksiyon riskinizi hesaplar.</string>
|
||||
<string name="exposure_grant_background_location_description">Neredeyse bitti! Bir sonraki ekranda, arkaplanda konum erişimini vermek için \'Her zaman izin ver\' seçeneğini seçin. Ardından geri dönün.</string>
|
||||
<string name="pref_exposure_app_api_usage_summary_line"><xliff:g example="provideDiagnosisKeys">%2$s</xliff:g> için <xliff:g example="12">%1$d</xliff:g> çağrı</string>
|
||||
<string name="exposure_confirm_keys_summary">Son 14 gün içindeki kimlikleriniz, çevrenizdekilere potansiyel temasta bulunduğunuz konusunda haber vermeye yardımcı olmak için kullanılır.\n\nKişisel bilgileriniz veya test sonuçlarınız başkaları ile paylaşılmaz.</string>
|
||||
</resources>
|
||||
62
play-services-nearby/core/src/main/res/values-ug/strings.xml
Normal file
62
play-services-nearby/core/src/main/res/values-ug/strings.xml
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="exposure_notify_off_nearby">ئۇچرىشىش ئۇقتۇرۇشىنىڭ ئىشلىشى ئۈچۈن قوشۇمچە ئىجازەت زۆرۈر</string>
|
||||
<string name="service_name_exposure">ئۇچرىشىش ئۇقتۇرۇشى</string>
|
||||
<string name="exposure_notify_off_bluetooth_location">ئۇچرىشىش ئۇقتۇرۇشى تاپشۇرۇۋېلىشتا كۆكچىش ۋە ئورۇن ئۇچۇرى ئىجازىتى قوزغىتىلىشى كېرەك.</string>
|
||||
<string name="pref_exposure_enable_info_summary">ئۇچرىشىش ئۇقتۇرۇشىنى قوزغىتىشتا، ئۇنى قوللايدىغان خالىغان ئەپنى ئېچىڭ.</string>
|
||||
<string name="pref_exposure_error_bluetooth_off_title">كۆكچىشنى قوزغات</string>
|
||||
<string name="pref_exposure_error_location_off_title">ئورۇن تەڭشىكىنى ئاچىدۇ</string>
|
||||
<string name="pref_exposure_error_bluetooth_unsupported_summary">ئەپسۇسلىنارلىقى، ئۈسكۈنىڭىز ئۇچرىشىش ئۇقتۇرۇشى بىلەن ماسلاشمايدۇ.</string>
|
||||
<string name="pref_exposure_error_bluetooth_no_advertise_summary">ئەپسۇسلىنارلىقى، ئۈسكۈنىڭىز ئۇچرىشىش ئۇقتۇرۇشى بىلەن قىسمەن ماسلىشىدۇ. خەتەر بىلەن ئۇچرىشىش ئۇقتۇرۇشى تاپشۇرۇۋالالايسىز ئەمما باشقىلارغا ئۇقتۇرالمايسىز.</string>
|
||||
<string name="prefcat_exposure_apps_title">ئۇچرىشىش ئۇقتۇرۇشى ئىشلىتىدىغان ئەپ</string>
|
||||
<string name="pref_exposure_advertising_id_title">نۆۋەتتە تارقاتقان كىملىك</string>
|
||||
<string name="prefcat_exposure_app_report_title">دوكلات قىلىنغان ئۇچرىشىش</string>
|
||||
<string name="pref_exposure_app_report_entry_time_short">5 مىنۇتتىن قىسقا</string>
|
||||
<string name="pref_exposure_collected_rpis_title">توپلانغان كىملىك</string>
|
||||
<string name="pref_exposure_app_report_entry_distance_close">يېقىن ئەتراپتىكى ئۇچرىشىش</string>
|
||||
<string name="pref_exposure_app_report_entry_distance_far">يىراقتىن ئۇچرىشىش</string>
|
||||
<string name="pref_exposure_app_last_report_summary_encounters_no">ھېچقانداق ئۇچراشقۇچى مەلۇم قىلىنمىدى.</string>
|
||||
<string name="pref_exposure_app_last_report_summary_encounters_suffix">ئەسكەرتىش: خەتەر نومۇرىنى ئەپ بەلگىلەيدۇ. نومۇرى يۇقىرى بولسا خەتەر تۆۋەن بولىدۇ ياكى ئەكسىچە بولسا يۇقىرى بولىدۇ.</string>
|
||||
<string name="pref_exposure_app_api_usage_title">ئۆتكەن 14 كۈندىكى API ئىشلىتىلىشى</string>
|
||||
<string name="pref_exposure_rpi_delete_all_title">ئۆچۈر</string>
|
||||
<string name="pref_exposure_rpi_delete_all_summary">توپلىغان ھەممە كىملىكنى ئۆچۈر</string>
|
||||
<string name="pref_exposure_rpi_delete_all_warning">توپلانغان بارلىق كىملىك ئۆچۈرۈلسە يېقىنقى 14 كۈندە ئۇچراشقانلارغا دىياگنوز قويۇلغان ئەھۋالدا سىزگە خەۋەر قىلغىلى بولمايدۇ.</string>
|
||||
<string name="pref_exposure_rpis_histogram_legend_no_records">خاتىرە يوق</string>
|
||||
<string name="pref_exposure_rpi_delete_all_warning_confirm_button">ئۆچۈرۈۋەر</string>
|
||||
<string name="pref_exposure_rpi_export_title">چىقار</string>
|
||||
<string name="pref_exposure_rpi_export_summary">باشقا ئەپتە تېخىمۇ ئىلگىرىلەپ تەھلىل قىلىش ئۈچۈن توپلانغان كىملىكنى چىقىرىدۇ.</string>
|
||||
<string name="pref_exposure_info_summary">ئۇچرىشىش ئۇقتۇرۇش API سى ئەپنىڭ سىز ئۇچراشقانلارنىڭ ئىچىدە جەزملەپ دىياگنوز قويۇلغانلار بار دەپ مەلۇم قىلىنسا سىزگە ئۇقتۇرۇش قىلىشىغا يول قويىدۇ.\n\nئۇچراشقان چېسلا، داۋاملاشقان ۋاقىت ۋە سىگنال كۈچلۈكلۈكى مۇناسىپ ئەپكە ھەمبەھىرلىنىدۇ.</string>
|
||||
<string name="exposure_enable_switch">ئۇچرىشىش ئۇقتۇرۇشىنى ئىشلىتىدۇ</string>
|
||||
<string name="exposure_confirm_start_title">ئۇچرىشىش ئۇقتۇرۇشىنى ئاچامدۇ؟</string>
|
||||
<string name="pref_exposure_rpis_details_summary">ئۇچرىشىش ئۇقتۇرۇش API سى قوزغىتىلغاندا، ئۈسكۈنىڭىز پاسسىپلىق بىلەن يېقىن ئەتراپتىكى ئۈسكۈنىلەردىن كىملىك (دومىلىما يېقىنلىق پەرقلەندۈرگۈچ ياكى RPI دېيىلىدۇ) توپلايدۇ.\n\nئۈسكۈنە ئىگىسى جەزملەپ دىياگنوز قويۇلغانلىقى مەلۇم قىلىنسا، ئۇلارنىڭ كىملىكىنى ھەمبەھىرلەشكە بولىدۇ. ئۈسكۈنىڭىز جەزملەپ دىياگنوز قويۇلغانلارنىڭ بەلگىسى توپلىغان كىملىكتە بار يوقلۇقىنى تەكشۈرۈپ، يۇقۇملىنىشىڭىزنىڭ خەتىرىنى ھېسابلايدۇ.</string>
|
||||
<string name="exposure_notify_off_title">ئۇچرىشىش ئۇقتۇرۇشى ئاكتىپسىز</string>
|
||||
<string name="exposure_notify_off_bluetooth">ئۇچرىشىش ئۇقتۇرۇشى تاپشۇرۇۋېلىشتا كۆكچىش قوزغىتىلىشى كېرەك.</string>
|
||||
<string name="exposure_notify_off_location">ئۇچرىشىش ئۇقتۇرۇشى تاپشۇرۇۋېلىشتا ئورۇن ئۇچۇرى ئىجازىتى زۆرۈر.</string>
|
||||
<string name="pref_exposure_collected_rpis_summary">ئاخىرقى بىر سائەتتە <xliff:g example="63">%1$d</xliff:g> كىملىك توپلىدى</string>
|
||||
<string name="pref_exposure_app_report_updated_title">يېڭىلاندى: <xliff:g example="Today, 14:02">%1$s</xliff:g></string>
|
||||
<string name="pref_exposure_app_report_entry_time_about">تەخمىنەن <xliff:g example="13">%1$d</xliff:g> مىنۇت</string>
|
||||
<string name="pref_exposure_app_report_entry_combined"><xliff:g example="About 12 minutes">%1$s</xliff:g>، <xliff:g example="distant exposure">%2$s</xliff:g></string>
|
||||
<string name="pref_exposure_app_last_report_summary_diagnosis_keys">دىياگنوز ئاچقۇچىدىن <xliff:g example="121031">%1$d</xliff:g> بىر تەرەپ قىلىندى.</string>
|
||||
<string name="pref_exposure_app_last_report_summary_encounters_prefix"><xliff:g example="3">%1$d</xliff:g> ئۇچرىشىش مەلۇم قىلىندى:</string>
|
||||
<string name="pref_exposure_app_last_report_summary_encounters_line"><xliff:g example="Yesterday, 12:00 - 14:00">%1$s</xliff:g>، risk score <xliff:g example="99">%2$d</xliff:g></string>
|
||||
<string name="pref_exposure_app_api_usage_summary_line"><xliff:g example="12">%1$d</xliff:g> قېتىم چاقىرغىنى <xliff:g example="provideDiagnosisKeys">%2$s</xliff:g></string>
|
||||
<string name="prefcat_exposure_rpis_histogram_title"><xliff:g example="230">%1$d</xliff:g> كىملىك توپلاندى</string>
|
||||
<string name="pref_exposure_rpis_histogram_legend_records">سائىتىگە <xliff:g example="0 - 50">%1$s</xliff:g> كىملىك</string>
|
||||
<string name="exposure_confirm_start_summary">تېلېفونىڭىز كۆكچىشنى ئىشلىتىپ ئەتراپتىكى باشقا تېلېفونلاردىن بىخەتەر ھالدا كىملىك توپلاپ ۋە ھەمبەھىرلەيدۇ.\n\nئەگەر سىز ئۇچراشقان بىرەرسى جەزملەپ دىياگنوز قويۇلغان بولسا <xliff:g example="Corona-Warn">%1$s</xliff:g> سىزگە ئۇقتۇرۇش قىلالايدۇ.\n\nئۇچراشقان چېسلا، داۋاملىشىش ۋاقتى ۋە سىگنال كۈچلۈكلۈكى باشقا ئەپ بىلەن ھەمبەھىرلىنىدۇ.</string>
|
||||
<string name="exposure_confirm_start_button">ئاچ</string>
|
||||
<string name="exposure_confirm_stop_title">ئۇچرىشىش ئۇقتۇرۇشىنى تاقامدۇ؟</string>
|
||||
<string name="exposure_confirm_stop_summary">ئۇچرىشىش ئۇقتۇرۇشى چەكلەنگەندىن كېيىن، يېقىندا ئۇچراشقانلار ئىچىدە جەزملەپ دىياگنوز قويۇلغانلار دوكلات قىلىنغان بولسا سىز ئۇقتۇرۇش تاپشۇرۇۋالمايسىز.</string>
|
||||
<string name="exposure_confirm_stop_button">تاقا</string>
|
||||
<string name="exposure_confirm_keys_summary">سىزنىڭ يېقىنقى 14 كۈندىكى كىملىكىڭىز ئەتراپىڭىزدىكى كىشىلەرگە سىزنىڭ يوشۇرۇن ئۇچرىشىش كەچمىشىڭىزنى ئۇقتۇرۇشقا ياردەم بېرىدۇ.\n\nسىزنىڭ شەخسىي سالاھىيەت ۋە تەكشۈرۈش نەتىجىڭىز باشقىلارغا ھەمبەھىرلەنمەيدۇ.</string>
|
||||
<string name="exposure_confirm_keys_button">ھەمبەھىر</string>
|
||||
<string name="exposure_confirm_permission_button">ئىجازەت</string>
|
||||
<string name="exposure_confirm_bluetooth_description">كۆكچىش قوزغىتىلىشى كېرەك.</string>
|
||||
<string name="exposure_confirm_location_description">ئورۇن ئۇچۇرى زىيارەت ئىجازىتى زۆرۈر.</string>
|
||||
<string name="exposure_confirm_button">قوزغات</string>
|
||||
<string name="exposure_confirm_keys_title"><xliff:g example="Corona-Warn">%1$s</xliff:g> غا كىملىكىڭىزنى ھەمبەھىرلەمدۇ؟</string>
|
||||
<string name="exposure_confirm_permission_description"><xliff:g example="microG Services">%1$s</xliff:g> قوشۇمچە ئىجازەتكە موھتاج.</string>
|
||||
<string name="pref_exposure_error_nearby_not_granted_title">ھېچقانداق ئىجازەت كېرەك ئەمەس</string>
|
||||
<string name="pref_exposure_error_nearby_not_granted_description">چېكىلسە ئۇچرىشىش ئۇقتۇرۇشىغا زۆرۈر ئىجازەت بېرىلىدۇ</string>
|
||||
<string name="exposure_grant_background_location_description">تۈگەي دېدى! كېيىنكى ئېكراندا «ھەمىشە يول قوي» نى تاللاپ ئارقا سۇپىدا ئورۇن ئۇچۇرىنى زىيارەت قىلىش ئىجازىتى بېرىپ، ئاندىن قايت توپچىنى چېكىڭ.</string>
|
||||
<string name="exposure_grant_background_location_button">يېڭىلاش تەڭشىكى</string>
|
||||
</resources>
|
||||
68
play-services-nearby/core/src/main/res/values-uk/strings.xml
Normal file
68
play-services-nearby/core/src/main/res/values-uk/strings.xml
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="pref_exposure_error_bluetooth_off_title">Ввімкнути Bluetooth</string>
|
||||
<string name="exposure_notify_off_bluetooth_location">Щоб отримувати сповіщення про вплив, потрібно увімкнути Bluetooth і доступ до розташування.</string>
|
||||
<string name="exposure_notify_off_title">Сповіщення про вплив неактивні</string>
|
||||
<string name="pref_exposure_error_location_off_title">Відкрити параметри розташування</string>
|
||||
<string name="pref_exposure_enable_info_summary">Щоб увімкнути сповіщення про вплив, відкрийте будь-який застосунок, що підтримує цю функцію.</string>
|
||||
<string name="service_name_exposure">Сповіщення про вплив</string>
|
||||
<string name="exposure_notify_off_bluetooth">Bluetooth повинен бути включений для отримання повідомлень про експозицію.</string>
|
||||
<string name="exposure_notify_off_location">Для отримання сповіщень про експозицію необхідний доступ до місця розташування.</string>
|
||||
<string name="exposure_notify_off_nearby">Сповіщення про вплив вимагають додаткових дозволів на роботу</string>
|
||||
<string name="pref_exposure_error_bluetooth_unsupported_summary">На жаль, ваш пристрій не сумісний з функцією сповіщень про зараження.</string>
|
||||
<string name="pref_exposure_error_bluetooth_no_advertise_summary">На жаль, ваш пристрій лише частково сумісний зі сповіщеннями про зараження. Ви можете отримувати сповіщення про небезпечні контакти, але не зможете сповіщати інших.</string>
|
||||
<string name="pref_exposure_collected_rpis_summary"><xliff:g example="63">%1$d</xliff:g> ідентифікаторів за останню годину</string>
|
||||
<string name="pref_exposure_app_report_updated_title">Оновлено: <xliff:g example="Today, 14:02">%1$s</xliff:g></string>
|
||||
<string name="pref_exposure_app_report_entry_time_about">Близько <xliff:g example="13">%1$d</xliff:g> хвилин</string>
|
||||
<string name="pref_exposure_app_report_entry_combined"><xliff:g example="About 12 minutes">%1$s</xliff:g>, <xliff:g example="distant exposure">%2$s</xliff:g></string>
|
||||
<string name="pref_exposure_app_last_report_summary_diagnosis_keys">Оброблено <xliff:g example="121031">%1$d</xliff:g> діагностичних ключів.</string>
|
||||
<string name="prefcat_exposure_apps_title">Застосунок, який використовує сповіщення про зараження</string>
|
||||
<string name="pref_exposure_collected_rpis_title">Зібрані ідентифікатори</string>
|
||||
<string name="pref_exposure_advertising_id_title">Поточний ідентифікатор, який транслюється</string>
|
||||
<string name="prefcat_exposure_app_report_title">Виявлені зараження</string>
|
||||
<string name="pref_exposure_app_report_entry_time_short">Менше 5 хвилин тому</string>
|
||||
<string name="pref_exposure_app_report_entry_distance_close">поблизу зараження</string>
|
||||
<string name="pref_exposure_app_report_entry_distance_far">зараження далеко</string>
|
||||
<string name="pref_exposure_app_last_report_summary_encounters_prefix">Повідомлено про <xliff:g example="3">%1$d</xliff:g> небезпечні контакти:</string>
|
||||
<string name="pref_exposure_app_last_report_summary_encounters_line"><xliff:g example="Yesterday, 12:00 - 14:00">%1$s</xliff:g>, оцінка ризику <xliff:g example="99">%2$d</xliff:g></string>
|
||||
<string name="pref_exposure_app_api_usage_summary_line"><xliff:g example="12">%1$d</xliff:g> запитів до <xliff:g example="provideDiagnosisKeys">%2$s</xliff:g></string>
|
||||
<string name="pref_exposure_app_last_report_summary_encounters_no">Про випадки небезпечних контактів не повідомлялося.</string>
|
||||
<string name="pref_exposure_app_last_report_summary_encounters_suffix">Примітка: Оцінка ризику визначається застосунком. Високі показники можуть означати низький ризик або навпаки.</string>
|
||||
<string name="pref_exposure_app_api_usage_title">Використання API за останні 14 днів</string>
|
||||
<string name="pref_exposure_rpis_histogram_legend_records"><xliff:g example="0 - 50">%1$s</xliff:g> ID на годину</string>
|
||||
<string name="exposure_confirm_permission_description"><xliff:g example="microG Services">%1$s</xliff:g> потребує додаткових дозволів.</string>
|
||||
<string name="prefcat_exposure_rpis_histogram_title"><xliff:g example="230">%1$d</xliff:g> ID зібрано</string>
|
||||
<string name="exposure_confirm_stop_button">Вимкнути</string>
|
||||
<string name="pref_exposure_rpis_details_summary">Коли API сповіщень про вплив увімкнено, ваш пристрій пасивно збирає ідентифікатори (так звані «рухомі ідентифікатори близькості», Rolling Proximity Identifiers, або RPI) з пристроїв, що знаходяться поруч.
|
||||
\n
|
||||
\nКоли власники пристроїв повідомляють про позитивний результат діагностики, їхні ідентифікатори можна використовувати спільно. Ваш пристрій перевіряє, чи збігається будь-який з відомих діагностованих ідентифікаторів з будь-яким із зібраних ідентифікаторів, і обчислює ризик зараження.</string>
|
||||
<string name="exposure_confirm_start_button">Ввімкнути</string>
|
||||
<string name="exposure_confirm_stop_title">Вимкнути сповіщення про вплив?</string>
|
||||
<string name="exposure_confirm_stop_summary">Після вимкнення сповіщень про вплив ви більше не отримуватимете сповіщень, якщо ви контактували з людиною, яка повідомила про позитивний результат тесту.</string>
|
||||
<string name="exposure_grant_background_location_description">Майже готово! Вам потрібно буде ввімкнути доступ до розташування у фоновому режимі, вибравши параметр «Дозволити постійно» на наступному екрані. Потім поверніться назад.</string>
|
||||
<string name="pref_exposure_rpis_histogram_legend_no_records">Немає записів</string>
|
||||
<string name="pref_exposure_rpi_delete_all_title">Видалити</string>
|
||||
<string name="pref_exposure_rpi_delete_all_summary">Видалити всі зібрані ID</string>
|
||||
<string name="pref_exposure_rpi_delete_all_warning">Видалення зібраних ідентифікаторів унеможливить сповіщення вас у випадку, якщо хтось із ваших контактів за останні 14 днів буде діагностований.</string>
|
||||
<string name="pref_exposure_rpi_delete_all_warning_confirm_button">Всеодно видалити</string>
|
||||
<string name="pref_exposure_rpi_export_title">Експортування</string>
|
||||
<string name="pref_exposure_rpi_export_summary">Експортуйте зібрані ідентифікатори для розширеного аналізу за допомогою іншого застосунку.</string>
|
||||
<string name="pref_exposure_info_summary">API сповіщень про контакт дозволяє застосункам сповіщати вас, якщо ви контактували з людиною, яка повідомила про позитивний результат тесту.
|
||||
\n
|
||||
\nДата, тривалість і рівень сигналу, пов\'язані з контактом, будуть передані відповідному застосунку.</string>
|
||||
<string name="exposure_enable_switch">Використовувати сповіщення про вплив</string>
|
||||
<string name="exposure_confirm_start_title">Увімкнути сповіщення про вплив?</string>
|
||||
<string name="exposure_confirm_start_summary">Ваш телефон повинен використовувати Bluetooth для безпечного збору та обміну ідентифікаторами з іншими телефонами, які знаходяться поблизу.\n\n<xliff:g example="Corona-Warn">%1$s</xliff:g> може сповістити вас, якщо ви зазнали контакту з людиною, яка повідомила про позитивний діагноз.\n\nДата, тривалість і рівень сигналу, пов\'язані з контактом, будуть передані застосунку.</string>
|
||||
<string name="exposure_confirm_keys_title">Поділітися своїми ідентифікаторами з <xliff:g example="Corona-Warn">%1$s</xliff:g>\?</string>
|
||||
<string name="exposure_confirm_keys_summary">Ваші ідентифікаційні дані за останні 14 днів будуть використані, щоби повідомити інших людей, які перебували поруч з вами, про потенційний ризик зараження.
|
||||
\n
|
||||
\nВаші дані або результати тесту не будуть передані іншим особам.</string>
|
||||
<string name="exposure_confirm_keys_button">Поділитися</string>
|
||||
<string name="exposure_confirm_permission_button">Надати дозвіл</string>
|
||||
<string name="exposure_confirm_bluetooth_description">Bluetooth має бути ввімкнено.</string>
|
||||
<string name="exposure_confirm_location_description">Доступ до розташування є обов\'язковим.</string>
|
||||
<string name="exposure_confirm_button">Ввімкнути</string>
|
||||
<string name="pref_exposure_error_nearby_not_granted_title">Потрібні нові дозволи</string>
|
||||
<string name="pref_exposure_error_nearby_not_granted_description">Натисніть, щоб надати необхідні дозволи для сповіщень про вплив</string>
|
||||
<string name="exposure_grant_background_location_button">Оновити налаштування</string>
|
||||
</resources>
|
||||
62
play-services-nearby/core/src/main/res/values-vi/strings.xml
Normal file
62
play-services-nearby/core/src/main/res/values-vi/strings.xml
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="exposure_notify_off_title">Thông báo Tiếp xúc hiện không hoạt động</string>
|
||||
<string name="exposure_notify_off_bluetooth">Cần bật Bluetooth để nhận Thông báo Tiếp xúc.</string>
|
||||
<string name="exposure_notify_off_location">Cần quyền truy cập Vị trí để nhận Thông báo Tiếp xúc.</string>
|
||||
<string name="exposure_notify_off_nearby">Thông báo Tiếp xúc cần thêm các quyền để hoạt động</string>
|
||||
<string name="service_name_exposure">Thông báo Tiếp xúc</string>
|
||||
<string name="pref_exposure_error_location_off_title">Mở cài đặt Vị trí</string>
|
||||
<string name="pref_exposure_error_bluetooth_unsupported_summary">Rất tiếc, thiết bị của bạn không tương thích với Thông báo Tiếp xúc.</string>
|
||||
<string name="exposure_notify_off_bluetooth_location">Cần bật Bluetooth và quyền truy cập Vị trí để nhận Thông báo Tiếp xúc.</string>
|
||||
<string name="prefcat_exposure_apps_title">Ứng dụng sử dụng Thông báo Tiếp xúc</string>
|
||||
<string name="pref_exposure_collected_rpis_title">Các ID đã thu thập</string>
|
||||
<string name="pref_exposure_advertising_id_title">ID đang được phát sóng</string>
|
||||
<string name="prefcat_exposure_app_report_title">Các tiếp xúc đã được báo cáo</string>
|
||||
<string name="pref_exposure_app_report_entry_time_short">Ít hơn 5 phút</string>
|
||||
<string name="pref_exposure_app_report_updated_title">Đã cập nhật: <xliff:g example="Hôm nay, 14:02">%1$s</xliff:g></string>
|
||||
<string name="pref_exposure_app_report_entry_time_about">Khoảng <xliff:g example="13">%1$d</xliff:g> phút</string>
|
||||
<string name="pref_exposure_app_report_entry_distance_close">tiếp xúc gần</string>
|
||||
<string name="pref_exposure_app_report_entry_distance_far">tiếp xúc xa</string>
|
||||
<string name="pref_exposure_app_report_entry_combined"><xliff:g example="Khoảng 12 phút">%1$s</xliff:g>, <xliff:g example="tiếp xúc xa">%2$s</xliff:g></string>
|
||||
<string name="pref_exposure_app_last_report_summary_diagnosis_keys">Đã xử trí khoá chẩn đoán <xliff:g example="121031">%1$d</xliff:g>.</string>
|
||||
<string name="pref_exposure_app_last_report_summary_encounters_no">Không có trường hợp tiếp xúc nào được báo cáo.</string>
|
||||
<string name="pref_exposure_app_last_report_summary_encounters_suffix">Lưu ý: Điểm rủi ro được xác định bởi ứng dụng. Số điểm cao có thể liên quan đến rủi ro thấp hoặc ngược lại.</string>
|
||||
<string name="pref_exposure_app_api_usage_title">Sử dụng API trong 14 ngày qua</string>
|
||||
<string name="pref_exposure_app_api_usage_summary_line"><xliff:g example="12">%1$d</xliff:g> gọi đến <xliff:g example="provideDiagnosisKeys">%2$s</xliff:g></string>
|
||||
<string name="pref_exposure_app_last_report_summary_encounters_prefix">Đã báo cáo các trường hợp tiếp xúc với <xliff:g example="3">%1$d</xliff:g>:</string>
|
||||
<string name="pref_exposure_app_last_report_summary_encounters_line"><xliff:g example="Hôm qua, 12:00 - 14:00">%1$s</xliff:g>, điểm rủi ro <xliff:g example="99">%2$d</xliff:g></string>
|
||||
<string name="prefcat_exposure_rpis_histogram_title"><xliff:g example="230">%1$d</xliff:g> ID đã thu thập</string>
|
||||
<string name="pref_exposure_rpis_histogram_legend_records"><xliff:g example="0 - 50">%1$s</xliff:g> ID mỗi giờ</string>
|
||||
<string name="pref_exposure_rpi_delete_all_title">Xoá</string>
|
||||
<string name="pref_exposure_rpi_delete_all_summary">Xoá tất cả ID đã thu thập</string>
|
||||
<string name="pref_exposure_rpis_histogram_legend_no_records">Không có bản ghi</string>
|
||||
<string name="pref_exposure_rpi_delete_all_warning">Việc xóa các ID đã thu thập sẽ khiến bạn không thể nhận thông báo nếu bất kỳ ai trong số các liên lạc của bạn trong 14 ngày qua được chẩn đoán.</string>
|
||||
<string name="pref_exposure_rpi_delete_all_warning_confirm_button">Vẫn xoá</string>
|
||||
<string name="pref_exposure_rpi_export_title">Xuất</string>
|
||||
<string name="pref_exposure_rpi_export_summary">Xuất ID đã thu thập để phân tích mở rộng bằng ứng dụng khác.</string>
|
||||
<string name="pref_exposure_rpis_details_summary">Khi đã kích hoạt API Thông báo Tiếp xúc, thiết bị của bạn sẽ thụ động thu thập các ID (gọi là Rolling Proximity Identifiers, hoặc RPIs) từ các thiết bị gần đó.\n\nKhi chủ sở hữu thiết được chẩn đoán dương tính, ID của họ có thể được chia sẻ. Thiết bị của bạn kiểm tra xem có ID nào đã biết được chẩn đoán dương tính trùng khớp với các ID đã thu thập hay không và tính toán mức độ rủi ro nhiễm bệnh của bạn.</string>
|
||||
<string name="exposure_enable_switch">Sử dụng Thông báo Tiếp xúc</string>
|
||||
<string name="exposure_confirm_start_title">Bật Thông báo Tiếp xúc?</string>
|
||||
<string name="exposure_confirm_start_button">Bật</string>
|
||||
<string name="exposure_confirm_stop_title">Tắt Thông báo Tiếp xúc?</string>
|
||||
<string name="exposure_confirm_stop_summary">Sau khi tắt Thông báo Tiếp xúc, bạn sẽ không còn nhận được thông báo khi bạn đã tiếp xúc với ai đó đã được chẩn đoán dương tính.</string>
|
||||
<string name="exposure_confirm_stop_button">Tắt</string>
|
||||
<string name="exposure_confirm_keys_title">Chia sẻ ID của bạn với <xliff:g example="Corona-Warn">%1$s</xliff:g>\?</string>
|
||||
<string name="exposure_confirm_keys_summary">ID của bạn trong 14 ngày qua sẽ được sử dụng để giúp thông báo cho người khác rằng bạn đã ở gần những trường hợp phơi nhiễm tiềm tàng.\n\nDanh tính hoặc kết quả xét nghiệm của bạn sẽ không được chia sẻ với người khác.</string>
|
||||
<string name="exposure_confirm_keys_button">Chia sẻ</string>
|
||||
<string name="exposure_confirm_permission_description"><xliff:g example="Dịch vụ microG">%1$s</xliff:g> cần thêm quyền.</string>
|
||||
<string name="exposure_confirm_permission_button">Cấp quyền</string>
|
||||
<string name="exposure_confirm_bluetooth_description">Cần phải bật Bluetooth.</string>
|
||||
<string name="exposure_confirm_location_description">Cần phải có quyền truy cập vị trí.</string>
|
||||
<string name="exposure_confirm_button">Bật</string>
|
||||
<string name="pref_exposure_error_nearby_not_granted_description">Nhấn để cấp các quyền cần thiết cho Thông báo Tiếp xúc</string>
|
||||
<string name="exposure_grant_background_location_description">Gần xong rồi! Bạn sẽ cần bật quyền truy cập vị trí nền bằng cách chọn tùy chọn \'Cho phép mọi lúc\' trên màn hình tiếp theo. Sau đó nhấn quay lại.</string>
|
||||
<string name="exposure_grant_background_location_button">Cập nhật cài đặt</string>
|
||||
<string name="pref_exposure_enable_info_summary">Để bật Thông báo Tiếp xúc, hãy mở bất kỳ ứng dụng nào hỗ trợ tính năng này.</string>
|
||||
<string name="pref_exposure_error_bluetooth_off_title">Bật Bluetooth</string>
|
||||
<string name="pref_exposure_error_bluetooth_no_advertise_summary">Rất tiếc, thiết bị của bạn chỉ tương thích một phần với Thông báo Tiếp xúc. Bạn có thể nhận thông báo về các tiếp xúc có nguy cơ, nhưng sẽ không thể thông báo cho người khác.</string>
|
||||
<string name="pref_exposure_collected_rpis_summary"><xliff:g example="63">%1$d</xliff:g> ID trong giờ qua</string>
|
||||
<string name="pref_exposure_info_summary">API Thông báo Tiếp xúc cho phép các ứng dụng thông báo cho bạn nếu bạn đã tiếp xúc với ai đó được chẩn đoán là dương tính.\n\nNgày, thời gian, và cường độ tín hiệu liên quan đến lần tiếp xúc sẽ được chia sẻ với ứng dụng tương ứng.</string>
|
||||
<string name="exposure_confirm_start_summary">Điện thoại của bạn cần sử dụng Bluetooth để thu thập và chia sẻ ID một cách an toàn với các điện thoại khác ở gần.\n\n<xliff:g example="Corona-Warn">%1$s</xliff:g> có thể thông báo cho bạn nếu bạn đã tiếp xúc với người được báo cáo là dương tính.\n\nNgày, thời gian và cường độ tín hiệu liên quan đến lần tiếp xúc sẽ được chia sẻ với ứng dụng.</string>
|
||||
<string name="pref_exposure_error_nearby_not_granted_title">Cần có Quyền mới</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ SPDX-FileCopyrightText: 2020, microG Project Team
|
||||
~ SPDX-License-Identifier: Apache-2.0
|
||||
--><resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="exposure_notify_off_title">接触史通知未启用</string>
|
||||
<string name="exposure_notify_off_bluetooth">需要启用蓝牙以接收接触史通知。</string>
|
||||
<string name="exposure_notify_off_location">需要位置访问权限以接收接触史通知。</string>
|
||||
<string name="exposure_notify_off_bluetooth_location">需要启用蓝牙和位置访问权限以接收接触史通知。</string>
|
||||
<string name="exposure_notify_off_nearby">接触史通知需要额外权限来运作</string>
|
||||
<string name="service_name_exposure">接触史通知系统</string>
|
||||
<string name="pref_exposure_enable_info_summary">要启用接触史通知系统,请打开支持该系统的应用。</string>
|
||||
<string name="pref_exposure_error_bluetooth_off_title">启用蓝牙</string>
|
||||
<string name="pref_exposure_error_location_off_title">打开位置设置</string>
|
||||
<string name="pref_exposure_error_bluetooth_unsupported_summary">很抱歉,您的设备与接触史通知系统不兼容。</string>
|
||||
<string name="pref_exposure_error_bluetooth_no_advertise_summary">很抱歉,您的设备与接触史通知系统仅部分兼容。您可以收到接触风险通知,但无法向他人发出通知。</string>
|
||||
<string name="prefcat_exposure_apps_title">使用接触史通知系统的应用</string>
|
||||
<string name="pref_exposure_collected_rpis_title">已收集的标识符</string>
|
||||
<string name="pref_exposure_collected_rpis_summary">最近一小时已收集 <xliff:g example="63">%1$d</xliff:g> 个标识符</string>
|
||||
<string name="pref_exposure_advertising_id_title">当前已广播的标识符</string>
|
||||
<string name="prefcat_exposure_app_report_title">已报告接触史</string>
|
||||
<string name="pref_exposure_app_report_updated_title">最后更新于:<xliff:g example="Today, 14:02">%1$s</xliff:g></string>
|
||||
<string name="pref_exposure_app_report_entry_time_short">不到 5 分钟</string>
|
||||
<string name="pref_exposure_app_report_entry_time_about">约 <xliff:g example="13">%1$d</xliff:g> 分钟</string>
|
||||
<string name="pref_exposure_app_last_report_summary_encounters_no">没有已报告的接触者。</string>
|
||||
<string name="pref_exposure_app_last_report_summary_encounters_suffix">注意:风险评分由应用定义。数字更高可能代表低风险,或反之。</string>
|
||||
<string name="pref_exposure_app_api_usage_title">14 天内的 API 使用情况</string>
|
||||
<string name="pref_exposure_rpis_histogram_legend_no_records">无记录</string>
|
||||
<string name="pref_exposure_rpi_delete_all_title">删除</string>
|
||||
<string name="pref_exposure_rpi_delete_all_summary">删除所有已收集的标识符</string>
|
||||
<string name="pref_exposure_rpi_delete_all_warning">删除所有已收集的标识符会导致您无法在最近 14 天内接触过确诊对象时获得通知。</string>
|
||||
<string name="pref_exposure_rpi_delete_all_warning_confirm_button">仍要删除</string>
|
||||
<string name="pref_exposure_rpi_export_title">导出</string>
|
||||
<string name="exposure_confirm_button">启用</string>
|
||||
<string name="pref_exposure_error_nearby_not_granted_title">需要新权限</string>
|
||||
<string name="exposure_grant_background_location_button">更新设置</string>
|
||||
<string name="exposure_confirm_stop_button">关闭</string>
|
||||
<string name="exposure_confirm_start_button">打开</string>
|
||||
<string name="exposure_confirm_start_title">打开接触史通知?</string>
|
||||
<string name="exposure_enable_switch">使用接触史通知</string>
|
||||
<string name="pref_exposure_rpis_details_summary">"接触史通知启用时,您的设备被动地从附近的设备收集滚动邻近标识符(RPI)。
|
||||
|
||||
其他设备拥有者被确诊为阳性时,他们的标识将被共享。您的设备将检查是否曾收集到已知确诊患者的标识,并据此计算您的感染风险。"</string>
|
||||
<string name="pref_exposure_info_summary">"接触史通知 API 允许应用在您曾经与新冠肺炎阳性确诊患者接触时通知您。
|
||||
|
||||
接触的发生日期、时长和信号强度将被共享给相应的应用。</string>
|
||||
<string name="pref_exposure_rpi_export_summary">导出已收集的标识符以供其他应用进一步分析。</string>
|
||||
<string name="exposure_confirm_stop_title">关闭接触史通知?</string>
|
||||
<string name="pref_exposure_app_report_entry_distance_close">近距离接触</string>
|
||||
<string name="pref_exposure_app_report_entry_distance_far">远距离接触</string>
|
||||
<string name="exposure_confirm_permission_description"><xliff:g example="microG Services">%1$s</xliff:g> 需要额外权限。</string>
|
||||
<string name="exposure_confirm_permission_button">授予权限</string>
|
||||
<string name="exposure_confirm_bluetooth_description">需要打开蓝牙。</string>
|
||||
<string name="exposure_confirm_location_description">需要位置访问权限。</string>
|
||||
<string name="exposure_grant_background_location_description">马上就好!请在下一屏幕中选择“一律允许”以授予后台位置访问权限,然后返回。</string>
|
||||
<string name="exposure_confirm_keys_title">向 <xliff:g example="Corona-Warn">%1$s</xliff:g> 共享您的标识符?</string>
|
||||
<string name="exposure_confirm_keys_button">共享</string>
|
||||
<string name="exposure_confirm_stop_summary">关闭接触史通知后,您将无法在最近接触过确诊对象时获得通知。</string>
|
||||
<string name="pref_exposure_error_nearby_not_granted_description">点击以向接触史通知授予权限</string>
|
||||
<string name="exposure_confirm_keys_summary">您最近 14 天的标识符将被用来帮助向您附近的人通知您的潜在接触史。
|
||||
\n
|
||||
\n不会向他人共享您的个人身份和检测结果。</string>
|
||||
<string name="exposure_confirm_start_summary">"您的设备需要蓝牙以安全地收集并与附近的其他设备共享标识符。
|
||||
|
||||
<xliff:g example="Corona-Warn">%1$s</xliff:g> 可以在您曾与新冠肺炎阳性确诊患者接触时通知您。
|
||||
|
||||
接触的发生日期、时长和与信号强度将被共享给相应的应用。"</string>
|
||||
<string name="pref_exposure_rpis_histogram_legend_records">每小时 <xliff:g example="0 - 50">%1$s</xliff:g> 个标识符</string>
|
||||
<string name="prefcat_exposure_rpis_histogram_title">已收集 <xliff:g example="230">%1$d</xliff:g> 个标识符</string>
|
||||
<string name="pref_exposure_app_last_report_summary_encounters_line"><xliff:g example="Yesterday, 12:00 - 14:00">%1$s</xliff:g>,风险评分:<xliff:g example="99">%2$d</xliff:g></string>
|
||||
<string name="pref_exposure_app_report_entry_combined"><xliff:g example="About 12 minutes">%1$s</xliff:g>, <xliff:g example="distant exposure">%2$s</xliff:g></string>
|
||||
<string name="pref_exposure_app_last_report_summary_encounters_prefix">已报告<xliff:g example="3">%1$d</xliff:g>暴露遭遇:</string>
|
||||
<string name="pref_exposure_app_api_usage_summary_line"><xliff:g example="12">%1$d</xliff:g> 联系<xliff:g example="provideDiagnosisKeys">%2$s</xliff:g></string>
|
||||
<string name="pref_exposure_app_last_report_summary_diagnosis_keys">处理<xliff:g example="121031">%1$d</xliff:g>诊断密钥。</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="exposure_notify_off_title">暴露通知未激活</string>
|
||||
<string name="exposure_notify_off_bluetooth">需要啟用藍牙才能接收暴露通知。</string>
|
||||
<string name="exposure_notify_off_location">需要位置访问權限才能接收暴露通知。</string>
|
||||
</resources>
|
||||
77
play-services-nearby/core/src/main/res/values/strings.xml
Normal file
77
play-services-nearby/core/src/main/res/values/strings.xml
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
~ SPDX-FileCopyrightText: 2020, microG Project Team
|
||||
~ SPDX-License-Identifier: Apache-2.0
|
||||
-->
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="exposure_notify_off_title">Exposure Notifications inactive</string>
|
||||
<string name="exposure_notify_off_bluetooth">Bluetooth needs to be enabled to receive Exposure Notifications.</string>
|
||||
<string name="exposure_notify_off_location">Location access is required to receive Exposure Notifications.</string>
|
||||
<string name="exposure_notify_off_bluetooth_location">Bluetooth and Location access need to be enabled to receive Exposure Notifications.</string>
|
||||
<string name="exposure_notify_off_nearby">Exposure Notifications require additional permissions to work</string>
|
||||
|
||||
<string name="service_name_exposure">Exposure Notifications</string>
|
||||
<string name="pref_exposure_enable_info_summary">To enable Exposure Notifications, open any app supporting it.</string>
|
||||
<string name="pref_exposure_error_bluetooth_off_title">Enable Bluetooth</string>
|
||||
<string name="pref_exposure_error_location_off_title">Open Location settings</string>
|
||||
<string name="pref_exposure_error_bluetooth_unsupported_summary">Unfortunately, your device is not compatible with Exposure Notifications.</string>
|
||||
<string name="pref_exposure_error_bluetooth_no_advertise_summary">Unfortunately, your device is only partially compatible with Exposure Notifications. You can be notified for risk contacts but won\'t be able to notify others.</string>
|
||||
<string name="prefcat_exposure_apps_title">Apps using Exposure Notifications</string>
|
||||
<string name="pref_exposure_collected_rpis_title">Collected IDs</string>
|
||||
<string name="pref_exposure_collected_rpis_summary"><xliff:g example="63">%1$d</xliff:g> IDs in last hour</string>
|
||||
<string name="pref_exposure_advertising_id_title">Currently broadcasted ID</string>
|
||||
<string name="prefcat_exposure_app_report_title">Reported exposures</string>
|
||||
<string name="pref_exposure_app_report_updated_title">Updated: <xliff:g example="Today, 14:02">%1$s</xliff:g></string>
|
||||
<string name="pref_exposure_app_report_entry_time_short">Less than 5 minutes</string>
|
||||
<string name="pref_exposure_app_report_entry_time_about">About <xliff:g example="13">%1$d</xliff:g> minutes</string>
|
||||
<string name="pref_exposure_app_report_entry_distance_close">nearby exposure</string>
|
||||
<string name="pref_exposure_app_report_entry_distance_far">distant exposure</string>
|
||||
<string name="pref_exposure_app_report_entry_combined"><xliff:g example="About 12 minutes">%1$s</xliff:g>, <xliff:g example="distant exposure">%2$s</xliff:g></string>
|
||||
<string name="pref_exposure_app_last_report_summary_diagnosis_keys">Processed <xliff:g example="121031">%1$d</xliff:g> diagnosis keys.</string>
|
||||
<string name="pref_exposure_app_last_report_summary_encounters_no">No exposure encounters reported.</string>
|
||||
<string name="pref_exposure_app_last_report_summary_encounters_prefix">Reported <xliff:g example="3">%1$d</xliff:g> exposure encounters:</string>
|
||||
<string name="pref_exposure_app_last_report_summary_encounters_line"><xliff:g example="Yesterday, 12:00 - 14:00">%1$s</xliff:g>, risk score <xliff:g example="99">%2$d</xliff:g></string>
|
||||
<string name="pref_exposure_app_last_report_summary_encounters_suffix">Note: The risk score is defined by the app. High numbers can refer to low risk or vice-versa.</string>
|
||||
<string name="pref_exposure_app_api_usage_title">API usage in the last 14 days</string>
|
||||
<string name="pref_exposure_app_api_usage_summary_line"><xliff:g example="12">%1$d</xliff:g> calls to <xliff:g example="provideDiagnosisKeys">%2$s</xliff:g></string>
|
||||
<string name="prefcat_exposure_rpis_histogram_title"><xliff:g example="230">%1$d</xliff:g> IDs collected</string>
|
||||
<string name="pref_exposure_rpis_histogram_legend_no_records">No records</string>
|
||||
<string name="pref_exposure_rpis_histogram_legend_records"><xliff:g example="0 - 50">%1$s</xliff:g> IDs per hour</string>
|
||||
<string name="pref_exposure_rpi_delete_all_title">Delete</string>
|
||||
<string name="pref_exposure_rpi_delete_all_summary">Delete all collected IDs</string>
|
||||
<string name="pref_exposure_rpi_delete_all_warning">Deleting collected IDs will make it impossible to notify you in case any of your contacts of the last 14 days is diagnosed.</string>
|
||||
<string name="pref_exposure_rpi_delete_all_warning_confirm_button">Delete anyways</string>
|
||||
<string name="pref_exposure_rpi_export_title">Export</string>
|
||||
<string name="pref_exposure_rpi_export_summary">Export collected IDs for extended analysis with another app.</string>
|
||||
<string name="pref_exposure_info_summary">"Exposure Notifications API allows apps to notify you if you were exposed to someone who reported to be diagnosed positive.
|
||||
|
||||
The date, duration, and signal strength associated with an exposure will be shared with the corresponding app."</string>
|
||||
<string name="pref_exposure_rpis_details_summary">"While Exposure Notification API is enabled, your device passively collects IDs (called Rolling Proximity Identifiers, or RPIs) from nearby devices.
|
||||
|
||||
When device owners report to be diagnosed positive, their IDs can be shared. Your device checks if any of the known diagnosed IDs matches any of the collected IDs and calculates your infection risk."</string>
|
||||
|
||||
<string name="exposure_enable_switch">Use Exposure Notifications</string>
|
||||
<string name="exposure_confirm_start_title">Turn on Exposure Notifications?</string>
|
||||
<string name="exposure_confirm_start_summary">"Your phone needs to use Bluetooth to securely collect and share IDs with other phones that are nearby.
|
||||
|
||||
<xliff:g example="Corona-Warn">%1$s</xliff:g> can notify you if you were exposed to someone who reported to be diagnosed positive.
|
||||
|
||||
The date, duration, and signal strength associated with an exposure will be shared with the app."</string>
|
||||
<string name="exposure_confirm_start_button">Turn on</string>
|
||||
<string name="exposure_confirm_stop_title">Turn off Exposure Notifications?</string>
|
||||
<string name="exposure_confirm_stop_summary">After disabling Exposure Notifications, you will no longer be notified when you were exposed to someone who reported to be diagnosed positive.</string>
|
||||
<string name="exposure_confirm_stop_button">Turn off</string>
|
||||
<string name="exposure_confirm_keys_title">Share your IDs with <xliff:g example="Corona-Warn">%1$s</xliff:g>?</string>
|
||||
<string name="exposure_confirm_keys_summary">"Your IDs from the last 14 days will be used to help notify others that you've been near about potential exposure.
|
||||
|
||||
Your identity or test result won't be shared with other people."</string>
|
||||
<string name="exposure_confirm_keys_button">Share</string>
|
||||
<string name="exposure_confirm_permission_description"><xliff:g example="microG Services">%1$s</xliff:g> needs additional permissions.</string>
|
||||
<string name="exposure_confirm_permission_button">Grant</string>
|
||||
<string name="exposure_confirm_bluetooth_description">Bluetooth needs to be enabled.</string>
|
||||
<string name="exposure_confirm_location_description">Location access is required.</string>
|
||||
<string name="exposure_confirm_button">Enable</string>
|
||||
<string name="pref_exposure_error_nearby_not_granted_title">New Permissions required</string>
|
||||
<string name="pref_exposure_error_nearby_not_granted_description">Tap to grant required permissions to Exposure Notifications</string>
|
||||
<string name="exposure_grant_background_location_description">Almost there! You will need to enable background location access by selecting the \'Allow all the time\' option on the next screen. Then press back.</string>
|
||||
<string name="exposure_grant_background_location_button">Update Settings</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,90 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ SPDX-FileCopyrightText: 2020, microG Project Team
|
||||
~ SPDX-License-Identifier: Apache-2.0
|
||||
-->
|
||||
|
||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<org.microg.gms.ui.SwitchBarPreference
|
||||
android:title="@string/exposure_enable_switch"
|
||||
android:key="pref_exposure_enabled"
|
||||
android:persistent="false" />
|
||||
|
||||
<Preference
|
||||
android:key="pref_exposure_enable_info"
|
||||
android:selectable="false"
|
||||
android:summary="@string/pref_exposure_enable_info_summary"
|
||||
app:isPreferenceVisible="false"
|
||||
tools:isPreferenceVisible="true" />
|
||||
|
||||
<Preference
|
||||
android:icon="@drawable/ic_bluetooth_off"
|
||||
android:key="pref_exposure_error_bluetooth_off"
|
||||
android:title="@string/pref_exposure_error_bluetooth_off_title"
|
||||
android:summary="@string/exposure_confirm_bluetooth_description"
|
||||
app:isPreferenceVisible="false"
|
||||
tools:isPreferenceVisible="true" />
|
||||
|
||||
<Preference
|
||||
android:icon="@drawable/ic_location_off"
|
||||
android:key="pref_exposure_error_location_off"
|
||||
android:title="@string/pref_exposure_error_location_off_title"
|
||||
android:summary="@string/exposure_confirm_location_description"
|
||||
app:isPreferenceVisible="false"
|
||||
tools:isPreferenceVisible="true" />
|
||||
|
||||
<Preference
|
||||
android:icon="@drawable/ic_info_outline"
|
||||
android:key="pref_exposure_error_nearby_not_granted"
|
||||
android:title="@string/pref_exposure_error_nearby_not_granted_title"
|
||||
android:summary="@string/pref_exposure_error_nearby_not_granted_description"
|
||||
app:isPreferenceVisible="false"
|
||||
tools:isPreferenceVisible="true" />
|
||||
|
||||
<Preference
|
||||
android:icon="@drawable/ic_alert"
|
||||
android:key="pref_exposure_error_bluetooth_unsupported"
|
||||
android:selectable="false"
|
||||
android:summary="@string/pref_exposure_error_bluetooth_unsupported_summary"
|
||||
app:isPreferenceVisible="false"
|
||||
tools:isPreferenceVisible="true" />
|
||||
|
||||
<Preference
|
||||
android:icon="@drawable/ic_alert"
|
||||
android:key="pref_exposure_error_bluetooth_no_advertise"
|
||||
android:selectable="false"
|
||||
android:summary="@string/pref_exposure_error_bluetooth_no_advertise_summary"
|
||||
app:isPreferenceVisible="false"
|
||||
tools:isPreferenceVisible="true" />
|
||||
|
||||
<PreferenceCategory
|
||||
android:key="prefcat_exposure_apps"
|
||||
android:title="@string/prefcat_exposure_apps_title">
|
||||
<Preference
|
||||
android:enabled="false"
|
||||
android:key="pref_exposure_apps_none"
|
||||
android:title="@string/list_no_item_none" />
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory android:layout="@layout/preference_category_no_label">
|
||||
<Preference
|
||||
android:key="pref_exposure_collected_rpis"
|
||||
android:title="@string/pref_exposure_collected_rpis_title"
|
||||
tools:summary="@string/pref_exposure_collected_rpis_summary" />
|
||||
<Preference
|
||||
android:enabled="false"
|
||||
android:key="pref_exposure_advertising_id"
|
||||
android:title="@string/pref_exposure_advertising_id_title"
|
||||
tools:summary="9a799d68-925f-4c0c-a73c-b418f22a1250" />
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory android:layout="@layout/preference_category_no_label">
|
||||
<org.microg.gms.ui.TextPreference
|
||||
android:icon="@drawable/ic_info_outline"
|
||||
android:selectable="false"
|
||||
android:summary="@string/pref_exposure_info_summary" />
|
||||
</PreferenceCategory>
|
||||
</PreferenceScreen>
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ SPDX-FileCopyrightText: 2020, microG Project Team
|
||||
~ SPDX-License-Identifier: Apache-2.0
|
||||
-->
|
||||
|
||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
<PreferenceCategory android:layout="@layout/preference_category_no_label">
|
||||
<Preference
|
||||
android:icon="@drawable/ic_open"
|
||||
android:key="pref_exposure_app_open"
|
||||
android:title="@string/open_app" />
|
||||
</PreferenceCategory>
|
||||
<PreferenceCategory
|
||||
android:key="prefcat_exposure_app_report"
|
||||
android:title="@string/prefcat_exposure_app_report_title">
|
||||
<Preference
|
||||
android:enabled="false"
|
||||
android:key="pref_exposure_app_report_none"
|
||||
android:order="0"
|
||||
android:title="@string/list_no_item_none"
|
||||
app:isPreferenceVisible="false"
|
||||
tools:isPreferenceVisible="true" />
|
||||
<Preference
|
||||
android:enabled="false"
|
||||
android:key="pref_exposure_app_report_updated"
|
||||
android:order="100"
|
||||
android:summary="@string/pref_exposure_app_last_report_summary_diagnosis_keys"
|
||||
android:title="@string/pref_exposure_app_report_updated_title" />
|
||||
</PreferenceCategory>
|
||||
<PreferenceCategory android:layout="@layout/preference_category_no_label">
|
||||
<Preference
|
||||
android:enabled="false"
|
||||
android:key="pref_exposure_app_api_usage"
|
||||
android:title="@string/pref_exposure_app_api_usage_title"
|
||||
tools:summary="@string/pref_exposure_app_api_usage_summary_line" />
|
||||
</PreferenceCategory>
|
||||
</PreferenceScreen>
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<paths>
|
||||
<cache-path name="exposureDatabase" path="exposureDatabase" />
|
||||
</paths>
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ SPDX-FileCopyrightText: 2020, microG Project Team
|
||||
~ SPDX-License-Identifier: Apache-2.0
|
||||
-->
|
||||
|
||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
<PreferenceCategory
|
||||
android:key="prefcat_exposure_rpi_histogram"
|
||||
tools:title="@string/prefcat_exposure_rpis_histogram_title">
|
||||
<org.microg.gms.nearby.exposurenotification.ui.DotChartPreference
|
||||
android:key="pref_exposure_rpi_histogram"
|
||||
android:selectable="false"
|
||||
tools:layout="@layout/preference_dot_chart" />
|
||||
</PreferenceCategory>
|
||||
<PreferenceCategory android:layout="@layout/preference_category_no_label">
|
||||
<Preference
|
||||
android:key="pref_exposure_export_database"
|
||||
android:summary="@string/pref_exposure_rpi_export_summary"
|
||||
android:title="@string/pref_exposure_rpi_export_title" />
|
||||
<Preference
|
||||
android:key="pref_exposure_rpi_delete_all"
|
||||
android:summary="@string/pref_exposure_rpi_delete_all_summary"
|
||||
android:title="@string/pref_exposure_rpi_delete_all_title" />
|
||||
</PreferenceCategory>
|
||||
<PreferenceCategory android:layout="@layout/preference_category_no_label">
|
||||
<org.microg.gms.ui.TextPreference
|
||||
android:icon="@drawable/ic_info_outline"
|
||||
android:selectable="false"
|
||||
android:summary="@string/pref_exposure_rpis_details_summary" />
|
||||
</PreferenceCategory>
|
||||
</PreferenceScreen>
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2020, microG Project Team
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package org.microg.gms.nearby.exposurenotification;
|
||||
|
||||
|
||||
import com.google.android.gms.nearby.exposurenotification.TemporaryExposureKey;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.junit.Assert;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
public class CryptoTest extends TestCase {
|
||||
private TemporaryExposureKey key;
|
||||
|
||||
@Override
|
||||
protected void setUp() {
|
||||
key = new TemporaryExposureKey.TemporaryExposureKeyBuilder()
|
||||
.setKeyData(TestVectors.get_TEMPORARY_TRACING_KEY())
|
||||
.setRollingStartIntervalNumber(TestVectors.CTINTERVAL_NUMBER_OF_GENERATED_KEY)
|
||||
.setRollingPeriod(TestVectors.KEY_ROLLING_PERIOD_MULTIPLE_OF_ID_PERIOD)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void tearDown() {
|
||||
key = null;
|
||||
}
|
||||
|
||||
public void testGenerateRpiKey() {
|
||||
Assert.assertArrayEquals(CryptoKt.generateRpiKey(key).getEncoded(), TestVectors.get_RPIK());
|
||||
}
|
||||
|
||||
public void testGenerateAemKey() {
|
||||
Assert.assertArrayEquals(CryptoKt.generateAemKey(key).getEncoded(), TestVectors.get_AEMK());
|
||||
}
|
||||
|
||||
public void testGenerateRpiId() {
|
||||
for (int i = 0; i < TestVectors.KEY_ROLLING_PERIOD_MULTIPLE_OF_ID_PERIOD; i++) {
|
||||
byte[] gen = CryptoKt.generateRpiId(key, key.getRollingStartIntervalNumber() + i);
|
||||
Assert.assertArrayEquals(gen, TestVectors.ADVERTISED_DATA.get(i).get_RPI());
|
||||
}
|
||||
}
|
||||
|
||||
public void testGeneratePayload() {
|
||||
for (int i = 0; i < TestVectors.KEY_ROLLING_PERIOD_MULTIPLE_OF_ID_PERIOD; i++) {
|
||||
byte[] gen = CryptoKt.generatePayload(key, key.getRollingStartIntervalNumber() + i, TestVectors.get_BLE_METADATA());
|
||||
Assert.assertArrayEquals(gen, TestVectors.ADVERTISED_DATA.get(i).get_merged());
|
||||
}
|
||||
}
|
||||
|
||||
public void testGenerateAllRpiIds() {
|
||||
byte[] all = CryptoKt.generateAllRpiIds(key);
|
||||
for (int i = 0; i < TestVectors.KEY_ROLLING_PERIOD_MULTIPLE_OF_ID_PERIOD; i++) {
|
||||
byte[] ref = CryptoKt.generateRpiId(key, key.getRollingStartIntervalNumber() + i);
|
||||
byte[] gen = Arrays.copyOfRange(all, i * 16, (i + 1) * 16);
|
||||
Assert.assertArrayEquals(gen, ref);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,976 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2020, Google LLC
|
||||
* SPDX-FileCopyrightText: 2020, microG Project Team
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
* Notice: Portions of this file are derived from work created and shared by Google and used
|
||||
* according to the terms described in the Apache License, Version 2.0.
|
||||
* See https://github.com/google/exposure-notifications-internals
|
||||
*/
|
||||
|
||||
package org.microg.gms.nearby.exposurenotification;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class TestVectors {
|
||||
|
||||
public static byte[] asBytes(int... ints) {
|
||||
byte[] bytes = new byte[ints.length];
|
||||
for (int i = 0; i < ints.length; i++) {
|
||||
int value = ints[i];
|
||||
bytes[i] = (byte) value;
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Class holding a matched pair of RPI and AEM values.
|
||||
*/
|
||||
public static class AdvertisedData {
|
||||
private final byte[] rollingProximityIndicator;
|
||||
private final byte[] associatedEncryptedMetadata;
|
||||
|
||||
AdvertisedData(byte[] rollingProximityIndicator, byte[] associatedEncryptedMetadata) {
|
||||
this.rollingProximityIndicator = rollingProximityIndicator;
|
||||
this.associatedEncryptedMetadata = associatedEncryptedMetadata;
|
||||
}
|
||||
|
||||
public byte[] get_RPI() {
|
||||
return rollingProximityIndicator.clone();
|
||||
}
|
||||
|
||||
public byte[] get_AEM() {
|
||||
return associatedEncryptedMetadata.clone();
|
||||
}
|
||||
|
||||
public byte[] get_merged() {
|
||||
byte[] bytes = new byte[rollingProximityIndicator.length + associatedEncryptedMetadata.length];
|
||||
System.arraycopy(rollingProximityIndicator, 0, bytes, 0, rollingProximityIndicator.length);
|
||||
System.arraycopy(associatedEncryptedMetadata, 0, bytes, rollingProximityIndicator.length, associatedEncryptedMetadata.length);
|
||||
return bytes;
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] get_TEMPORARY_TRACING_KEY() {
|
||||
return TEMPORARY_TRACING_KEY.clone();
|
||||
}
|
||||
|
||||
public static byte[] get_RPIK() {
|
||||
return RPIK.clone();
|
||||
}
|
||||
|
||||
public static byte[] get_AEMK() {
|
||||
return AEMK.clone();
|
||||
}
|
||||
|
||||
public static byte[] get_BLE_METADATA() {
|
||||
return BLE_METADATA.clone();
|
||||
}
|
||||
|
||||
public static String get_RPIK_HKDF_INFO_STRING() {
|
||||
return "EN-RPIK";
|
||||
}
|
||||
|
||||
public static String get_RPI_AES_PADDED_STRING() {
|
||||
return "EN-RPI";
|
||||
}
|
||||
|
||||
public static String get_AEMK_HKDF_INFO_STRING() {
|
||||
return "EN-AEMK";
|
||||
}
|
||||
|
||||
// From TestVectors.h.txt
|
||||
// ------------------------------------------------------------------------------
|
||||
public static final int KEY_GENERATION_NSECONDS = 1585785600;
|
||||
public static final int CTINTERVAL_NUMBER_OF_GENERATED_KEY = 2642976;
|
||||
public static final int ID_ROLLING_PERIOD_MINUTES = 10;
|
||||
public static final int KEY_ROLLING_PERIOD_MULTIPLE_OF_ID_PERIOD = 144;
|
||||
|
||||
private static final byte[] TEMPORARY_TRACING_KEY =
|
||||
asBytes(
|
||||
0x75, 0xc7, 0x34, 0xc6, 0xdd, 0x1a, 0x78, 0x2d, 0xe7, 0xa9, 0x65, 0xda, 0x5e, 0xb9, 0x31,
|
||||
0x25);
|
||||
|
||||
private static final byte[] RPIK =
|
||||
asBytes(
|
||||
0x18, 0x5a, 0xd9, 0x1d, 0xb6, 0x9e, 0xc7, 0xdd, 0x04, 0x89, 0x60, 0xf1, 0xf3, 0xba, 0x61,
|
||||
0x75);
|
||||
private static final byte[] AEMK =
|
||||
asBytes(
|
||||
0xd5, 0x7c, 0x46, 0xaf, 0x7a, 0x1d, 0x83, 0x96, 0x5b, 0x9b, 0xed, 0x8b, 0xd1, 0x52, 0x93,
|
||||
0x6a);
|
||||
private static final byte[] BLE_METADATA = asBytes(0x40, 0x08, 0x00, 0x00);
|
||||
private static final byte[] RPI0 =
|
||||
asBytes(
|
||||
0x8b, 0xe6, 0xcd, 0x37, 0x1c, 0x5c, 0x89, 0x16, 0x04, 0xbf, 0xbe, 0x49, 0xdf, 0x84, 0x50,
|
||||
0x96);
|
||||
private static final byte[] AEM0 = asBytes(0x72, 0x03, 0x38, 0x74);
|
||||
private static final byte[] RPI1 =
|
||||
asBytes(
|
||||
0x3c, 0x9a, 0x1d, 0xe5, 0xdd, 0x6b, 0x02, 0xaf, 0xa7, 0xfd, 0xed, 0x7b, 0x57, 0x0b, 0x3e,
|
||||
0x56);
|
||||
private static final byte[] AEM1 = asBytes(0xc2, 0x92, 0x11, 0xb1);
|
||||
private static final byte[] RPI2 =
|
||||
asBytes(
|
||||
0x24, 0x3f, 0xfe, 0x9a, 0x3b, 0x08, 0xbd, 0xed, 0x30, 0x94, 0xba, 0xc8, 0x63, 0x0b, 0xb8,
|
||||
0xad);
|
||||
private static final byte[] AEM2 = asBytes(0x6a, 0xdf, 0xad, 0x03);
|
||||
private static final byte[] RPI3 =
|
||||
asBytes(
|
||||
0xdf, 0xc3, 0xed, 0x26, 0x5e, 0x97, 0xd0, 0xea, 0xbb, 0x63, 0x0e, 0x16, 0x8b, 0x42, 0x14,
|
||||
0xed);
|
||||
private static final byte[] AEM3 = asBytes(0xf1, 0xe2, 0xf8, 0x0b);
|
||||
private static final byte[] RPI4 =
|
||||
asBytes(
|
||||
0xb3, 0xb8, 0x5a, 0x69, 0xeb, 0xae, 0xc7, 0x8d, 0xb7, 0x39, 0x85, 0x2d, 0x1f, 0x34, 0xe0,
|
||||
0xfa);
|
||||
private static final byte[] AEM4 = asBytes(0x56, 0x68, 0xc4, 0x74);
|
||||
private static final byte[] RPI5 =
|
||||
asBytes(
|
||||
0x29, 0x8a, 0xbd, 0x6f, 0xda, 0xd2, 0x9e, 0xfb, 0xf0, 0xf8, 0x5a, 0x63, 0x95, 0x6c, 0xf1,
|
||||
0x88);
|
||||
private static final byte[] AEM5 = asBytes(0xf7, 0xb9, 0x7e, 0x84);
|
||||
private static final byte[] RPI6 =
|
||||
asBytes(
|
||||
0x10, 0x5e, 0x82, 0x21, 0xdd, 0x60, 0x3d, 0x25, 0xb9, 0x4a, 0xba, 0x0c, 0x3c, 0xc8, 0xde,
|
||||
0xe1);
|
||||
private static final byte[] AEM6 = asBytes(0xee, 0xab, 0xfd, 0xc7);
|
||||
private static final byte[] RPI7 =
|
||||
asBytes(
|
||||
0x98, 0x88, 0xca, 0x7e, 0x67, 0x38, 0xec, 0x4b, 0xc6, 0xe4, 0x20, 0xb2, 0x0f, 0x87, 0x8b,
|
||||
0x3a);
|
||||
private static final byte[] AEM7 = asBytes(0x9f, 0x84, 0xa9, 0xa6);
|
||||
private static final byte[] RPI8 =
|
||||
asBytes(
|
||||
0x86, 0x94, 0xa7, 0x9a, 0xe9, 0x96, 0x71, 0xbe, 0x3f, 0x18, 0xaa, 0xf6, 0xb0, 0x90, 0x65,
|
||||
0x7a);
|
||||
private static final byte[] AEM8 = asBytes(0xc1, 0x1a, 0xcb, 0x4d);
|
||||
private static final byte[] RPI9 =
|
||||
asBytes(
|
||||
0xb8, 0xcd, 0xe2, 0x8a, 0xd2, 0x0d, 0x1c, 0xd2, 0xfd, 0xd7, 0x36, 0x9d, 0xc0, 0xc6, 0xf7,
|
||||
0xc8);
|
||||
private static final byte[] AEM9 = asBytes(0x1f, 0x8d, 0x53, 0xde);
|
||||
private static final byte[] RPI10 =
|
||||
asBytes(
|
||||
0xf6, 0x01, 0x23, 0xc6, 0x7b, 0xd2, 0xfc, 0x4b, 0x62, 0x00, 0x2b, 0x4b, 0x7d, 0x59, 0x5b,
|
||||
0xa6);
|
||||
private static final byte[] AEM10 = asBytes(0xe0, 0xa7, 0xf9, 0xf2);
|
||||
private static final byte[] RPI11 =
|
||||
asBytes(
|
||||
0x8a, 0x84, 0xc8, 0x6e, 0x05, 0xf7, 0xa8, 0x77, 0x2a, 0xae, 0x7a, 0x80, 0x68, 0x6e, 0x1a,
|
||||
0x1c);
|
||||
private static final byte[] AEM11 = asBytes(0xf4, 0xb7, 0xb0, 0x9d);
|
||||
private static final byte[] RPI12 =
|
||||
asBytes(
|
||||
0xac, 0x46, 0x1b, 0xf2, 0xb9, 0x3b, 0x0d, 0x90, 0x84, 0x17, 0x46, 0xf5, 0x1a, 0xde, 0xd6,
|
||||
0xc0);
|
||||
private static final byte[] AEM12 = asBytes(0x73, 0x91, 0xdd, 0x64);
|
||||
private static final byte[] RPI13 =
|
||||
asBytes(
|
||||
0xf2, 0x56, 0x7e, 0xed, 0x0a, 0xa1, 0xcd, 0xf2, 0xcd, 0x3d, 0x0b, 0xd2, 0x82, 0x52, 0xf1,
|
||||
0x96);
|
||||
private static final byte[] AEM13 = asBytes(0x12, 0x7d, 0xb0, 0x9e);
|
||||
private static final byte[] RPI14 =
|
||||
asBytes(
|
||||
0xa2, 0x55, 0x22, 0x5b, 0xaa, 0x9e, 0x37, 0xb7, 0x30, 0xa9, 0x5f, 0x99, 0x7a, 0x69, 0x72,
|
||||
0xf5);
|
||||
private static final byte[] AEM14 = asBytes(0x43, 0x5e, 0xa5, 0x56);
|
||||
private static final byte[] RPI15 =
|
||||
asBytes(
|
||||
0x04, 0xcf, 0xae, 0xe4, 0x10, 0x21, 0xcb, 0x7d, 0x4d, 0x02, 0x0b, 0x30, 0x6b, 0x24, 0xbe,
|
||||
0xa8);
|
||||
private static final byte[] AEM15 = asBytes(0xdc, 0x1f, 0x19, 0x06);
|
||||
private static final byte[] RPI16 =
|
||||
asBytes(
|
||||
0xf5, 0x37, 0x2b, 0xbc, 0x92, 0xf7, 0x80, 0x59, 0x64, 0x70, 0x1e, 0x87, 0x9b, 0x48, 0xd4,
|
||||
0x31);
|
||||
private static final byte[] AEM16 = asBytes(0xb3, 0xea, 0xaf, 0xdd);
|
||||
private static final byte[] RPI17 =
|
||||
asBytes(
|
||||
0xf2, 0xc8, 0x11, 0x54, 0x63, 0x82, 0xb1, 0x0d, 0xf1, 0xac, 0x06, 0xc3, 0x2c, 0x61, 0x7b,
|
||||
0xa7);
|
||||
private static final byte[] AEM17 = asBytes(0xcd, 0x51, 0x86, 0xf9);
|
||||
private static final byte[] RPI18 =
|
||||
asBytes(
|
||||
0xf8, 0xf3, 0x44, 0x1f, 0x76, 0x22, 0x3d, 0xac, 0x15, 0xec, 0x6b, 0x35, 0xfd, 0xb2, 0x51,
|
||||
0x40);
|
||||
private static final byte[] AEM18 = asBytes(0x7f, 0x38, 0x7e, 0x7f);
|
||||
private static final byte[] RPI19 =
|
||||
asBytes(
|
||||
0xd0, 0x71, 0x83, 0xdb, 0x3c, 0x80, 0x45, 0x08, 0x7d, 0x61, 0xee, 0x9e, 0x73, 0x0c, 0x93,
|
||||
0x06);
|
||||
private static final byte[] AEM19 = asBytes(0x1a, 0x42, 0xa1, 0x5b);
|
||||
private static final byte[] RPI20 =
|
||||
asBytes(
|
||||
0xc7, 0x42, 0xdd, 0x9c, 0x96, 0xa3, 0xe6, 0xfa, 0x7c, 0x4f, 0x22, 0x62, 0x1d, 0xac, 0xc2,
|
||||
0x4d);
|
||||
private static final byte[] AEM20 = asBytes(0x06, 0x39, 0x0d, 0xed);
|
||||
private static final byte[] RPI21 =
|
||||
asBytes(
|
||||
0x08, 0x23, 0x33, 0xfa, 0xd9, 0xfa, 0x29, 0x2a, 0xb8, 0x99, 0xd6, 0x00, 0x0c, 0x65, 0x97,
|
||||
0x97);
|
||||
private static final byte[] AEM21 = asBytes(0x0f, 0x01, 0xbc, 0xd7);
|
||||
private static final byte[] RPI22 =
|
||||
asBytes(
|
||||
0xbe, 0x43, 0x00, 0xda, 0xfb, 0x8d, 0x07, 0xc8, 0x8c, 0xb2, 0xb5, 0x07, 0x7a, 0x06, 0x11,
|
||||
0x66);
|
||||
private static final byte[] AEM22 = asBytes(0xc7, 0xbf, 0xbb, 0x92);
|
||||
private static final byte[] RPI23 =
|
||||
asBytes(
|
||||
0x5f, 0xed, 0x1b, 0x4d, 0x3b, 0x3a, 0x13, 0x33, 0x2f, 0x05, 0x44, 0x75, 0x60, 0x35, 0x26,
|
||||
0x32);
|
||||
private static final byte[] AEM23 = asBytes(0x21, 0x7c, 0x8e, 0x4a);
|
||||
private static final byte[] RPI24 =
|
||||
asBytes(
|
||||
0xfd, 0x1e, 0xe2, 0xcc, 0x5c, 0x60, 0xe6, 0xee, 0xe6, 0x1f, 0x04, 0x91, 0x9f, 0x67, 0x59,
|
||||
0xa7);
|
||||
private static final byte[] AEM24 = asBytes(0xee, 0x63, 0x9b, 0xd6);
|
||||
private static final byte[] RPI25 =
|
||||
asBytes(
|
||||
0x96, 0xad, 0xf5, 0xb8, 0xdc, 0x7e, 0xe7, 0x5d, 0xf4, 0x6f, 0xbd, 0x8a, 0x1f, 0xc4, 0xad,
|
||||
0x0d);
|
||||
private static final byte[] AEM25 = asBytes(0x60, 0x8c, 0x13, 0x0f);
|
||||
private static final byte[] RPI26 =
|
||||
asBytes(
|
||||
0xfa, 0x4b, 0xa2, 0x20, 0x6d, 0x42, 0xa1, 0xc8, 0x0d, 0x52, 0x48, 0xae, 0x68, 0x83, 0x09,
|
||||
0xa4);
|
||||
private static final byte[] AEM26 = asBytes(0x74, 0xb2, 0xc8, 0x73);
|
||||
private static final byte[] RPI27 =
|
||||
asBytes(
|
||||
0xa5, 0x90, 0xf9, 0x5d, 0xbf, 0x24, 0x02, 0x61, 0xda, 0x10, 0x1a, 0x7c, 0xdb, 0x24, 0xdb,
|
||||
0xba);
|
||||
private static final byte[] AEM27 = asBytes(0x95, 0x6a, 0x95, 0xeb);
|
||||
private static final byte[] RPI28 =
|
||||
asBytes(
|
||||
0x67, 0xe8, 0x1b, 0x91, 0xd1, 0xcf, 0x9e, 0x09, 0x58, 0x13, 0x54, 0x29, 0xda, 0xd0, 0x1e,
|
||||
0x82);
|
||||
private static final byte[] AEM28 = asBytes(0xc6, 0xfa, 0x3c, 0x7a);
|
||||
private static final byte[] RPI29 =
|
||||
asBytes(
|
||||
0x18, 0x3c, 0xac, 0x22, 0x36, 0xc3, 0xe0, 0x53, 0x3b, 0xe4, 0x70, 0x4d, 0x83, 0x6e, 0x47,
|
||||
0x55);
|
||||
private static final byte[] AEM29 = asBytes(0xa2, 0xab, 0xc7, 0x03);
|
||||
private static final byte[] RPI30 =
|
||||
asBytes(
|
||||
0x34, 0x11, 0x62, 0x55, 0x1c, 0x29, 0x31, 0x9b, 0xc5, 0x35, 0x38, 0xed, 0xfc, 0xf2, 0x30,
|
||||
0x40);
|
||||
private static final byte[] AEM30 = asBytes(0x80, 0x09, 0xb2, 0xaa);
|
||||
private static final byte[] RPI31 =
|
||||
asBytes(
|
||||
0x22, 0x51, 0x68, 0x70, 0x18, 0x21, 0x4b, 0x65, 0xdd, 0x8e, 0xe8, 0x3e, 0xae, 0xd3, 0x30,
|
||||
0xab);
|
||||
private static final byte[] AEM31 = asBytes(0xcf, 0xe8, 0x04, 0xcb);
|
||||
private static final byte[] RPI32 =
|
||||
asBytes(
|
||||
0xa4, 0xcf, 0x6e, 0x50, 0x21, 0x5f, 0xe2, 0x78, 0xcc, 0x5c, 0xff, 0x1b, 0x05, 0x34, 0xa3,
|
||||
0xe0);
|
||||
private static final byte[] AEM32 = asBytes(0xcb, 0x2a, 0x7e, 0x22);
|
||||
private static final byte[] RPI33 =
|
||||
asBytes(
|
||||
0xdf, 0x8f, 0x2a, 0xc3, 0x03, 0x23, 0x2b, 0x2e, 0x5b, 0x3e, 0xfd, 0x86, 0x81, 0xaa, 0xa8,
|
||||
0xdd);
|
||||
private static final byte[] AEM33 = asBytes(0x65, 0x03, 0xa7, 0x27);
|
||||
private static final byte[] RPI34 =
|
||||
asBytes(
|
||||
0xba, 0x2e, 0x75, 0xd7, 0xf4, 0x8c, 0xf5, 0x5c, 0x0c, 0x86, 0x8f, 0xd4, 0x5c, 0xf1, 0x6b,
|
||||
0x5c);
|
||||
private static final byte[] AEM34 = asBytes(0x8f, 0x29, 0x78, 0x7e);
|
||||
private static final byte[] RPI35 =
|
||||
asBytes(
|
||||
0xec, 0x6a, 0x40, 0x05, 0x8d, 0xeb, 0xff, 0xff, 0x3c, 0x51, 0x97, 0x7f, 0x24, 0x56, 0x2e,
|
||||
0x21);
|
||||
private static final byte[] AEM35 = asBytes(0xb2, 0xad, 0xd3, 0xb7);
|
||||
private static final byte[] RPI36 =
|
||||
asBytes(
|
||||
0x6a, 0x68, 0xe3, 0x0b, 0x2f, 0xb9, 0x3b, 0x5d, 0xf7, 0x8e, 0xe3, 0xa9, 0xa3, 0x50, 0xa6,
|
||||
0xce);
|
||||
private static final byte[] AEM36 = asBytes(0x1b, 0xfb, 0x46, 0x0a);
|
||||
private static final byte[] RPI37 =
|
||||
asBytes(
|
||||
0x8d, 0x33, 0xa7, 0x05, 0x62, 0x62, 0x99, 0x94, 0xf8, 0xdf, 0x99, 0x05, 0x2b, 0x0e, 0xb6,
|
||||
0x9a);
|
||||
private static final byte[] AEM37 = asBytes(0x8e, 0xcf, 0x07, 0x7b);
|
||||
private static final byte[] RPI38 =
|
||||
asBytes(
|
||||
0x21, 0x05, 0x3c, 0xcb, 0x8f, 0x92, 0x51, 0x11, 0xe2, 0x54, 0xbd, 0x69, 0x4e, 0x97, 0x94,
|
||||
0x6b);
|
||||
private static final byte[] AEM38 = asBytes(0x2b, 0xa7, 0x7b, 0x38);
|
||||
private static final byte[] RPI39 =
|
||||
asBytes(
|
||||
0xe1, 0xc9, 0xcd, 0xf2, 0x0f, 0x90, 0x0a, 0xe6, 0xd2, 0x4b, 0xf7, 0xbc, 0xb4, 0xe6, 0x61,
|
||||
0x35);
|
||||
private static final byte[] AEM39 = asBytes(0x8c, 0x12, 0x40, 0xde);
|
||||
private static final byte[] RPI40 =
|
||||
asBytes(
|
||||
0xba, 0xf7, 0x89, 0xf5, 0x50, 0x94, 0x6b, 0x43, 0x10, 0x64, 0x45, 0x07, 0x71, 0xb2, 0xa1,
|
||||
0x43);
|
||||
private static final byte[] AEM40 = asBytes(0x43, 0x89, 0x99, 0xb6);
|
||||
private static final byte[] RPI41 =
|
||||
asBytes(
|
||||
0xf7, 0xf9, 0x1e, 0xc2, 0x50, 0x85, 0xd0, 0x35, 0x3e, 0x02, 0x78, 0xe5, 0x98, 0xcc, 0x62,
|
||||
0x01);
|
||||
private static final byte[] AEM41 = asBytes(0x1d, 0xcb, 0xdc, 0x6e);
|
||||
private static final byte[] RPI42 =
|
||||
asBytes(
|
||||
0xc8, 0x93, 0x3d, 0x70, 0x22, 0x0b, 0xa9, 0xc8, 0xc1, 0x48, 0x39, 0x3a, 0x39, 0x59, 0xd2,
|
||||
0x56);
|
||||
private static final byte[] AEM42 = asBytes(0x63, 0x85, 0xff, 0xda);
|
||||
private static final byte[] RPI43 =
|
||||
asBytes(
|
||||
0xf2, 0x93, 0x2e, 0x6e, 0x6e, 0xf6, 0x0f, 0x0f, 0x5b, 0xbc, 0xe4, 0x39, 0x10, 0x0a, 0x90,
|
||||
0xe4);
|
||||
private static final byte[] AEM43 = asBytes(0x69, 0x6c, 0x0c, 0xdf);
|
||||
private static final byte[] RPI44 =
|
||||
asBytes(
|
||||
0x18, 0xf5, 0xd8, 0x10, 0x2a, 0x59, 0x30, 0xd8, 0x02, 0x30, 0xf2, 0xc3, 0x9a, 0x42, 0x66,
|
||||
0xd6);
|
||||
private static final byte[] AEM44 = asBytes(0x63, 0x84, 0x2b, 0xba);
|
||||
private static final byte[] RPI45 =
|
||||
asBytes(
|
||||
0xe6, 0x07, 0x5c, 0x28, 0x93, 0x9f, 0xb0, 0xc6, 0x72, 0x46, 0xce, 0x38, 0xc5, 0xff, 0x93,
|
||||
0x8a);
|
||||
private static final byte[] AEM45 = asBytes(0xb7, 0xe2, 0x2c, 0x60);
|
||||
private static final byte[] RPI46 =
|
||||
asBytes(
|
||||
0x66, 0x16, 0x88, 0x62, 0xbc, 0x44, 0x5f, 0x48, 0xe5, 0xb0, 0xed, 0x07, 0xe1, 0xdf, 0x3f,
|
||||
0x5a);
|
||||
private static final byte[] AEM46 = asBytes(0xd2, 0xe7, 0xd6, 0xd8);
|
||||
private static final byte[] RPI47 =
|
||||
asBytes(
|
||||
0x1d, 0x0a, 0x01, 0xc3, 0x8d, 0xa4, 0xac, 0x41, 0xec, 0x7a, 0x63, 0x8f, 0x5d, 0xf7, 0x05,
|
||||
0xa9);
|
||||
private static final byte[] AEM47 = asBytes(0x91, 0xbe, 0x92, 0x2c);
|
||||
private static final byte[] RPI48 =
|
||||
asBytes(
|
||||
0xa7, 0x37, 0x00, 0x1a, 0x2d, 0x2f, 0x80, 0x2c, 0x64, 0x78, 0x9a, 0x99, 0x52, 0xe6, 0xd1,
|
||||
0xa7);
|
||||
private static final byte[] AEM48 = asBytes(0x7e, 0x04, 0x21, 0xbb);
|
||||
private static final byte[] RPI49 =
|
||||
asBytes(
|
||||
0x7c, 0x37, 0x25, 0xb6, 0x08, 0x4e, 0x68, 0x1f, 0xb3, 0x4d, 0x26, 0xc3, 0xa3, 0x94, 0xa6,
|
||||
0x43);
|
||||
private static final byte[] AEM49 = asBytes(0x7e, 0xa5, 0x20, 0x9f);
|
||||
private static final byte[] RPI50 =
|
||||
asBytes(
|
||||
0x26, 0xd1, 0xf8, 0x36, 0x55, 0x7a, 0x25, 0x9a, 0x81, 0xb5, 0xdb, 0x54, 0x19, 0xc6, 0xa7,
|
||||
0x29);
|
||||
private static final byte[] AEM50 = asBytes(0x1c, 0x92, 0x06, 0x28);
|
||||
private static final byte[] RPI51 =
|
||||
asBytes(
|
||||
0xeb, 0xc2, 0xa6, 0x06, 0x28, 0x54, 0xd1, 0xec, 0x62, 0x7b, 0x1f, 0x6e, 0x84, 0x32, 0xe1,
|
||||
0x66);
|
||||
private static final byte[] AEM51 = asBytes(0x4a, 0x76, 0x46, 0x32);
|
||||
private static final byte[] RPI52 =
|
||||
asBytes(
|
||||
0x11, 0x32, 0x74, 0xe8, 0x0c, 0x31, 0xcf, 0xcd, 0x81, 0xc2, 0xad, 0x08, 0x64, 0x44, 0x51,
|
||||
0x78);
|
||||
private static final byte[] AEM52 = asBytes(0x69, 0xa7, 0x49, 0xb6);
|
||||
private static final byte[] RPI53 =
|
||||
asBytes(
|
||||
0x45, 0x67, 0x97, 0x6c, 0x48, 0xbe, 0x72, 0x59, 0x06, 0x24, 0x7d, 0x0b, 0xd8, 0x1b, 0xb8,
|
||||
0x11);
|
||||
private static final byte[] AEM53 = asBytes(0x6f, 0x94, 0x85, 0xdb);
|
||||
private static final byte[] RPI54 =
|
||||
asBytes(
|
||||
0x74, 0x81, 0x54, 0xba, 0x52, 0x3a, 0x1a, 0xa8, 0x10, 0xb7, 0x06, 0x2a, 0x13, 0xe5, 0xaa,
|
||||
0x68);
|
||||
private static final byte[] AEM54 = asBytes(0x74, 0x78, 0x07, 0x23);
|
||||
private static final byte[] RPI55 =
|
||||
asBytes(
|
||||
0x30, 0xbc, 0xeb, 0x33, 0x45, 0x74, 0x51, 0x53, 0x35, 0x23, 0x65, 0x99, 0x85, 0x87, 0xcd,
|
||||
0x10);
|
||||
private static final byte[] AEM55 = asBytes(0x89, 0x17, 0xda, 0x61);
|
||||
private static final byte[] RPI56 =
|
||||
asBytes(
|
||||
0x8f, 0x2d, 0x7b, 0x87, 0x00, 0xa8, 0x2f, 0xd4, 0x51, 0x4d, 0xfa, 0x42, 0x02, 0xee, 0x29,
|
||||
0x8f);
|
||||
private static final byte[] AEM56 = asBytes(0xfe, 0xc4, 0xf8, 0xb1);
|
||||
private static final byte[] RPI57 =
|
||||
asBytes(
|
||||
0x0e, 0x66, 0x49, 0x53, 0x70, 0x0c, 0xdf, 0xc0, 0xd2, 0x79, 0x2f, 0xad, 0xf0, 0x73, 0x29,
|
||||
0xeb);
|
||||
private static final byte[] AEM57 = asBytes(0x78, 0x1a, 0x3e, 0xaf);
|
||||
private static final byte[] RPI58 =
|
||||
asBytes(
|
||||
0xf4, 0x49, 0x58, 0xc4, 0xdd, 0x70, 0xd9, 0x96, 0x8a, 0x26, 0xfd, 0x60, 0xba, 0x92, 0x72,
|
||||
0x90);
|
||||
private static final byte[] AEM58 = asBytes(0xb9, 0x75, 0x9b, 0x61);
|
||||
private static final byte[] RPI59 =
|
||||
asBytes(
|
||||
0x55, 0xfd, 0x2f, 0x6c, 0xbd, 0xe0, 0xe1, 0x3f, 0xd2, 0x2c, 0x0b, 0x3d, 0xb1, 0x62, 0x28,
|
||||
0xe5);
|
||||
private static final byte[] AEM59 = asBytes(0x48, 0x3c, 0x94, 0x10);
|
||||
private static final byte[] RPI60 =
|
||||
asBytes(
|
||||
0x49, 0xf3, 0xf9, 0xd1, 0x24, 0x69, 0xdc, 0xc9, 0xed, 0x35, 0x63, 0x64, 0xc3, 0x00, 0x66,
|
||||
0xe4);
|
||||
private static final byte[] AEM60 = asBytes(0x2d, 0xa6, 0xeb, 0xac);
|
||||
private static final byte[] RPI61 =
|
||||
asBytes(
|
||||
0xc5, 0x7d, 0x2d, 0x6e, 0x0d, 0x25, 0xa0, 0x65, 0x1c, 0xd7, 0x27, 0x86, 0xf8, 0xc9, 0x51,
|
||||
0xce);
|
||||
private static final byte[] AEM61 = asBytes(0x43, 0xea, 0xcf, 0x34);
|
||||
private static final byte[] RPI62 =
|
||||
asBytes(
|
||||
0x88, 0xef, 0x25, 0x63, 0x51, 0xac, 0x49, 0xdf, 0xd1, 0x5a, 0xb5, 0xa2, 0xde, 0x97, 0xc0,
|
||||
0x13);
|
||||
private static final byte[] AEM62 = asBytes(0xb9, 0xa1, 0x36, 0x53);
|
||||
private static final byte[] RPI63 =
|
||||
asBytes(
|
||||
0xd0, 0xfb, 0x6f, 0xd6, 0xdb, 0x89, 0xda, 0x52, 0x36, 0x1f, 0x1a, 0x30, 0xfb, 0x43, 0x6c,
|
||||
0xe7);
|
||||
private static final byte[] AEM63 = asBytes(0x35, 0x6d, 0xea, 0x55);
|
||||
private static final byte[] RPI64 =
|
||||
asBytes(
|
||||
0x8a, 0x42, 0xa3, 0x30, 0xf0, 0x19, 0x28, 0xe5, 0x16, 0x31, 0x23, 0x19, 0x81, 0x60, 0x3f,
|
||||
0xd5);
|
||||
private static final byte[] AEM64 = asBytes(0x35, 0x05, 0xb7, 0xf3);
|
||||
private static final byte[] RPI65 =
|
||||
asBytes(
|
||||
0x6e, 0x51, 0xb2, 0xa2, 0xae, 0xcb, 0xab, 0x1d, 0xf8, 0x08, 0x26, 0xef, 0x6d, 0x1e, 0x19,
|
||||
0x58);
|
||||
private static final byte[] AEM65 = asBytes(0x5c, 0x05, 0xcd, 0x94);
|
||||
private static final byte[] RPI66 =
|
||||
asBytes(
|
||||
0x3c, 0xe6, 0x81, 0xa2, 0x8b, 0x1b, 0xe1, 0x9c, 0x9e, 0x36, 0xb9, 0xc5, 0x80, 0xb1, 0x23,
|
||||
0xab);
|
||||
private static final byte[] AEM66 = asBytes(0x98, 0x47, 0x45, 0xd6);
|
||||
private static final byte[] RPI67 =
|
||||
asBytes(
|
||||
0x1e, 0x95, 0x8e, 0xd8, 0x9b, 0x86, 0xb9, 0x89, 0x77, 0xf7, 0x9e, 0x1b, 0x83, 0xf3, 0xd0,
|
||||
0x5f);
|
||||
private static final byte[] AEM67 = asBytes(0x93, 0xfd, 0xf7, 0x08);
|
||||
private static final byte[] RPI68 =
|
||||
asBytes(
|
||||
0x1d, 0x66, 0x7b, 0x01, 0xd6, 0x63, 0x4b, 0x5f, 0x3b, 0x6f, 0x33, 0xac, 0x4b, 0x15, 0x0d,
|
||||
0x23);
|
||||
private static final byte[] AEM68 = asBytes(0xd7, 0x0f, 0x74, 0x4c);
|
||||
private static final byte[] RPI69 =
|
||||
asBytes(
|
||||
0x67, 0xf2, 0x22, 0x15, 0x6c, 0x51, 0x7d, 0xeb, 0xc0, 0x70, 0x68, 0xcb, 0xc5, 0xee, 0xc1,
|
||||
0xdd);
|
||||
private static final byte[] AEM69 = asBytes(0x60, 0x57, 0x8c, 0x31);
|
||||
private static final byte[] RPI70 =
|
||||
asBytes(
|
||||
0xa8, 0x45, 0x4b, 0x9c, 0x94, 0x7d, 0x16, 0x25, 0xee, 0x3f, 0xba, 0x26, 0x07, 0xc2, 0x3a,
|
||||
0xff);
|
||||
private static final byte[] AEM70 = asBytes(0x79, 0x00, 0xee, 0xad);
|
||||
private static final byte[] RPI71 =
|
||||
asBytes(
|
||||
0x41, 0x6f, 0xfc, 0x7a, 0x32, 0xfc, 0xfd, 0xa9, 0xa3, 0x16, 0xd0, 0x17, 0x90, 0xe3, 0x19,
|
||||
0x45);
|
||||
private static final byte[] AEM71 = asBytes(0xc1, 0x22, 0xad, 0x68);
|
||||
private static final byte[] RPI72 =
|
||||
asBytes(
|
||||
0xc1, 0x9a, 0x30, 0xc3, 0x9c, 0x9c, 0x3a, 0x08, 0x9b, 0xca, 0xdd, 0xe1, 0xc6, 0x69, 0x94,
|
||||
0x47);
|
||||
private static final byte[] AEM72 = asBytes(0x34, 0x0a, 0xa3, 0x82);
|
||||
private static final byte[] RPI73 =
|
||||
asBytes(
|
||||
0x78, 0x6d, 0xdf, 0xae, 0x6f, 0xc7, 0x7c, 0x4c, 0x41, 0x0c, 0x4e, 0xc3, 0x2d, 0x34, 0x24,
|
||||
0x7d);
|
||||
private static final byte[] AEM73 = asBytes(0x67, 0xc6, 0x0d, 0xfb);
|
||||
private static final byte[] RPI74 =
|
||||
asBytes(
|
||||
0xef, 0x0f, 0xd3, 0xa9, 0x5b, 0x96, 0x61, 0xe1, 0xfc, 0xcb, 0x4e, 0x30, 0xcd, 0xe3, 0x2c,
|
||||
0x51);
|
||||
private static final byte[] AEM74 = asBytes(0x45, 0x56, 0xb6, 0x73);
|
||||
private static final byte[] RPI75 =
|
||||
asBytes(
|
||||
0xfc, 0x1f, 0x8a, 0x66, 0xf4, 0x05, 0xcc, 0xb6, 0x3d, 0xc3, 0xe4, 0x82, 0x07, 0xda, 0x77,
|
||||
0x88);
|
||||
private static final byte[] AEM75 = asBytes(0x9e, 0x4f, 0x1d, 0xb4);
|
||||
private static final byte[] RPI76 =
|
||||
asBytes(
|
||||
0x0e, 0xac, 0xc2, 0x86, 0x31, 0xb1, 0x0f, 0x44, 0x98, 0x36, 0x86, 0x66, 0x13, 0x0f, 0xf0,
|
||||
0xc9);
|
||||
private static final byte[] AEM76 = asBytes(0x5b, 0xe0, 0x4e, 0x9d);
|
||||
private static final byte[] RPI77 =
|
||||
asBytes(
|
||||
0xe8, 0xdb, 0x4a, 0x46, 0x26, 0x38, 0x5a, 0xe6, 0xe3, 0xb2, 0x45, 0x1d, 0x0a, 0x66, 0xed,
|
||||
0xbf);
|
||||
private static final byte[] AEM77 = asBytes(0x80, 0x6a, 0xf2, 0xf9);
|
||||
private static final byte[] RPI78 =
|
||||
asBytes(
|
||||
0xc6, 0x00, 0x67, 0x8d, 0x4f, 0xbe, 0x92, 0x45, 0xad, 0x49, 0x73, 0xb1, 0xc8, 0x97, 0x1b,
|
||||
0xc5);
|
||||
private static final byte[] AEM78 = asBytes(0x7a, 0xf8, 0xd4, 0xfd);
|
||||
private static final byte[] RPI79 =
|
||||
asBytes(
|
||||
0x08, 0x19, 0x26, 0xc3, 0x61, 0x83, 0x4c, 0x5c, 0x1d, 0x43, 0x19, 0xb8, 0x40, 0xf3, 0x15,
|
||||
0xae);
|
||||
private static final byte[] AEM79 = asBytes(0xfc, 0x8d, 0xdd, 0xd0);
|
||||
private static final byte[] RPI80 =
|
||||
asBytes(
|
||||
0x1d, 0x82, 0x9e, 0xaf, 0xa0, 0x42, 0x32, 0xa6, 0xbb, 0x4d, 0x3c, 0x20, 0x22, 0xac, 0x3d,
|
||||
0x0f);
|
||||
private static final byte[] AEM80 = asBytes(0xda, 0x88, 0x15, 0x68);
|
||||
private static final byte[] RPI81 =
|
||||
asBytes(
|
||||
0x79, 0x8a, 0xbc, 0xe8, 0xc8, 0xf6, 0x25, 0x10, 0xde, 0x59, 0x5a, 0x99, 0x73, 0xfb, 0x21,
|
||||
0x8e);
|
||||
private static final byte[] AEM81 = asBytes(0x13, 0x95, 0xcf, 0x7b);
|
||||
private static final byte[] RPI82 =
|
||||
asBytes(
|
||||
0x61, 0xfc, 0x0d, 0xeb, 0x47, 0x08, 0x4f, 0xda, 0xf1, 0x48, 0x3e, 0x34, 0x2d, 0x73, 0xb1,
|
||||
0x48);
|
||||
private static final byte[] AEM82 = asBytes(0xd9, 0xe2, 0x5d, 0xb6);
|
||||
private static final byte[] RPI83 =
|
||||
asBytes(
|
||||
0x49, 0x69, 0xed, 0xd4, 0x0f, 0x3e, 0xab, 0x46, 0x8b, 0x8a, 0x8d, 0x49, 0x68, 0x5a, 0x4e,
|
||||
0xdd);
|
||||
private static final byte[] AEM83 = asBytes(0xc1, 0xb2, 0x05, 0x97);
|
||||
private static final byte[] RPI84 =
|
||||
asBytes(
|
||||
0x1d, 0x69, 0xd6, 0xd4, 0x15, 0x8a, 0x31, 0x8f, 0x1d, 0x9c, 0xaf, 0xba, 0x13, 0x58, 0x70,
|
||||
0x17);
|
||||
private static final byte[] AEM84 = asBytes(0xeb, 0x53, 0x91, 0x99);
|
||||
private static final byte[] RPI85 =
|
||||
asBytes(
|
||||
0xab, 0x7c, 0x61, 0xf1, 0xcc, 0xa8, 0x13, 0xfd, 0x36, 0xe8, 0xf1, 0xb1, 0xe5, 0xdf, 0x6a,
|
||||
0x0f);
|
||||
private static final byte[] AEM85 = asBytes(0xc8, 0x1a, 0xb8, 0x54);
|
||||
private static final byte[] RPI86 =
|
||||
asBytes(
|
||||
0x94, 0xf2, 0x4f, 0xde, 0xc1, 0x7a, 0xa3, 0x1f, 0x74, 0xf2, 0x02, 0xae, 0x4a, 0x68, 0x74,
|
||||
0xbe);
|
||||
private static final byte[] AEM86 = asBytes(0x46, 0xee, 0x82, 0xdc);
|
||||
private static final byte[] RPI87 =
|
||||
asBytes(
|
||||
0x6e, 0x5d, 0xe0, 0x25, 0x79, 0xd3, 0xdf, 0xb1, 0x94, 0xcc, 0x7b, 0xd4, 0x92, 0x70, 0x25,
|
||||
0x3d);
|
||||
private static final byte[] AEM87 = asBytes(0x8a, 0x05, 0x28, 0xbd);
|
||||
private static final byte[] RPI88 =
|
||||
asBytes(
|
||||
0xfe, 0x3e, 0x1e, 0x36, 0x21, 0x77, 0x3f, 0x18, 0x80, 0x40, 0xaa, 0x5d, 0xb3, 0xff, 0x1d,
|
||||
0x4e);
|
||||
private static final byte[] AEM88 = asBytes(0x28, 0x03, 0x3a, 0xae);
|
||||
private static final byte[] RPI89 =
|
||||
asBytes(
|
||||
0xd7, 0x37, 0x6e, 0x0d, 0x77, 0x25, 0x5d, 0xe2, 0x3d, 0x54, 0x0f, 0x02, 0x71, 0x83, 0xf1,
|
||||
0xba);
|
||||
private static final byte[] AEM89 = asBytes(0xa0, 0x1c, 0xe7, 0x12);
|
||||
private static final byte[] RPI90 =
|
||||
asBytes(
|
||||
0x64, 0xa7, 0x1e, 0x48, 0xa5, 0x0e, 0x7b, 0x5a, 0x37, 0xac, 0x91, 0x81, 0x6e, 0x2b, 0x0f,
|
||||
0x53);
|
||||
private static final byte[] AEM90 = asBytes(0xc9, 0xcb, 0x8c, 0x70);
|
||||
private static final byte[] RPI91 =
|
||||
asBytes(
|
||||
0x0f, 0x22, 0xa2, 0xc0, 0xb6, 0x99, 0xe1, 0x89, 0xd5, 0x9e, 0x30, 0xd1, 0x74, 0x5d, 0x67,
|
||||
0xd3);
|
||||
private static final byte[] AEM91 = asBytes(0xdb, 0xe6, 0x8f, 0x47);
|
||||
private static final byte[] RPI92 =
|
||||
asBytes(
|
||||
0xde, 0x87, 0x6b, 0xaf, 0x31, 0x22, 0x8e, 0x3b, 0x7f, 0xe0, 0xf0, 0x8e, 0x1f, 0x38, 0xea,
|
||||
0x7b);
|
||||
private static final byte[] AEM92 = asBytes(0x4c, 0xb1, 0xd9, 0x4f);
|
||||
private static final byte[] RPI93 =
|
||||
asBytes(
|
||||
0x8c, 0x69, 0x27, 0xbc, 0xf5, 0xf7, 0xae, 0xe1, 0xee, 0xd8, 0xab, 0xbe, 0x43, 0xe2, 0xe2,
|
||||
0xd1);
|
||||
private static final byte[] AEM93 = asBytes(0x27, 0x74, 0x06, 0x32);
|
||||
private static final byte[] RPI94 =
|
||||
asBytes(
|
||||
0xbc, 0x96, 0x83, 0x0f, 0x18, 0x2a, 0x72, 0xc8, 0x9e, 0x65, 0xce, 0xa9, 0xc4, 0x7d, 0x88,
|
||||
0xc0);
|
||||
private static final byte[] AEM94 = asBytes(0xe8, 0xad, 0xeb, 0x6d);
|
||||
private static final byte[] RPI95 =
|
||||
asBytes(
|
||||
0x7b, 0x2f, 0xbe, 0x74, 0x6d, 0xd2, 0xda, 0x86, 0xe9, 0x86, 0x6a, 0x0e, 0x6a, 0xad, 0xbc,
|
||||
0x4d);
|
||||
private static final byte[] AEM95 = asBytes(0xe5, 0x3a, 0x5a, 0xc7);
|
||||
private static final byte[] RPI96 =
|
||||
asBytes(
|
||||
0x93, 0xe2, 0x0f, 0x14, 0xa1, 0x3d, 0x56, 0x56, 0x75, 0x94, 0xaa, 0x96, 0x23, 0x50, 0xf1,
|
||||
0x70);
|
||||
private static final byte[] AEM96 = asBytes(0x94, 0x32, 0x42, 0xa4);
|
||||
private static final byte[] RPI97 =
|
||||
asBytes(
|
||||
0x9e, 0x38, 0x14, 0xf9, 0x51, 0xfa, 0x03, 0x79, 0x6b, 0x9a, 0x66, 0xf8, 0x9a, 0x9f, 0x40,
|
||||
0x0d);
|
||||
private static final byte[] AEM97 = asBytes(0x06, 0x48, 0xdc, 0x89);
|
||||
private static final byte[] RPI98 =
|
||||
asBytes(
|
||||
0x95, 0xfa, 0x09, 0x84, 0x5a, 0xa8, 0xd4, 0xb6, 0x00, 0x47, 0xfa, 0xf9, 0x9a, 0xeb, 0xca,
|
||||
0x0c);
|
||||
private static final byte[] AEM98 = asBytes(0x85, 0x5e, 0x31, 0xb3);
|
||||
private static final byte[] RPI99 =
|
||||
asBytes(
|
||||
0xef, 0x0a, 0x75, 0x79, 0x33, 0x18, 0x53, 0xb9, 0xeb, 0xc2, 0x50, 0xb4, 0xd6, 0xf3, 0xeb,
|
||||
0xcc);
|
||||
private static final byte[] AEM99 = asBytes(0x9c, 0x1f, 0x07, 0xc2);
|
||||
private static final byte[] RPI100 =
|
||||
asBytes(
|
||||
0x7f, 0xe9, 0xa9, 0x0d, 0xe0, 0x0c, 0x9f, 0x07, 0x37, 0xd3, 0xb4, 0x5f, 0xda, 0x65, 0x11,
|
||||
0x15);
|
||||
private static final byte[] AEM100 = asBytes(0x98, 0x4e, 0x1f, 0xf3);
|
||||
private static final byte[] RPI101 =
|
||||
asBytes(
|
||||
0x44, 0x3b, 0x7b, 0x5a, 0xb9, 0xa8, 0x6a, 0x1f, 0xee, 0x67, 0xe1, 0x8c, 0xb8, 0xc4, 0x07,
|
||||
0x64);
|
||||
private static final byte[] AEM101 = asBytes(0xb3, 0xfb, 0xa7, 0xe1);
|
||||
private static final byte[] RPI102 =
|
||||
asBytes(
|
||||
0xe8, 0xa6, 0xfa, 0x9a, 0x5c, 0xa9, 0xfb, 0x06, 0x1c, 0x4c, 0xdb, 0xe2, 0x17, 0xc6, 0x1d,
|
||||
0x59);
|
||||
private static final byte[] AEM102 = asBytes(0x3b, 0x6d, 0x9d, 0xe8);
|
||||
private static final byte[] RPI103 =
|
||||
asBytes(
|
||||
0x08, 0x7a, 0x08, 0x04, 0x06, 0x86, 0xfd, 0x63, 0x5e, 0xf3, 0x89, 0x75, 0x27, 0x41, 0xcc,
|
||||
0x1f);
|
||||
private static final byte[] AEM103 = asBytes(0xf0, 0x85, 0x55, 0x1c);
|
||||
private static final byte[] RPI104 =
|
||||
asBytes(
|
||||
0x58, 0x7c, 0x04, 0x86, 0x64, 0x4c, 0xeb, 0x2d, 0x0b, 0x7e, 0xbd, 0xd3, 0x9d, 0xd3, 0xa8,
|
||||
0x60);
|
||||
private static final byte[] AEM104 = asBytes(0x0a, 0x6b, 0x32, 0x6e);
|
||||
private static final byte[] RPI105 =
|
||||
asBytes(
|
||||
0xdd, 0x82, 0x7b, 0xa6, 0x0f, 0x8a, 0x35, 0xb1, 0xdd, 0x4e, 0x4c, 0xdf, 0xe4, 0x9c, 0x42,
|
||||
0x63);
|
||||
private static final byte[] AEM105 = asBytes(0x81, 0xeb, 0x20, 0xe2);
|
||||
private static final byte[] RPI106 =
|
||||
asBytes(
|
||||
0xcf, 0x23, 0x40, 0x00, 0x08, 0x0a, 0x4e, 0x8d, 0xa8, 0xfe, 0xb5, 0x33, 0xaa, 0x59, 0x04,
|
||||
0xd3);
|
||||
private static final byte[] AEM106 = asBytes(0x34, 0xd8, 0x6e, 0xe5);
|
||||
private static final byte[] RPI107 =
|
||||
asBytes(
|
||||
0xc5, 0x0f, 0xb1, 0xec, 0x3e, 0xf5, 0x4e, 0x91, 0x61, 0x78, 0xca, 0x9d, 0x56, 0xee, 0x4f,
|
||||
0x5c);
|
||||
private static final byte[] AEM107 = asBytes(0xea, 0xea, 0xc3, 0xd2);
|
||||
private static final byte[] RPI108 =
|
||||
asBytes(
|
||||
0xd4, 0x5f, 0xde, 0x46, 0xf4, 0x67, 0xd7, 0x6e, 0xd2, 0x8d, 0xd4, 0xd2, 0x49, 0x6d, 0xcb,
|
||||
0x7f);
|
||||
private static final byte[] AEM108 = asBytes(0xea, 0xa6, 0x4a, 0x8e);
|
||||
private static final byte[] RPI109 =
|
||||
asBytes(
|
||||
0xe9, 0xba, 0xf8, 0x1c, 0x96, 0x1f, 0x51, 0x0d, 0x08, 0xa6, 0x63, 0xc7, 0x52, 0x4f, 0x36,
|
||||
0xdf);
|
||||
private static final byte[] AEM109 = asBytes(0x1e, 0x2c, 0xa3, 0x7b);
|
||||
private static final byte[] RPI110 =
|
||||
asBytes(
|
||||
0xe3, 0xb0, 0x2c, 0xc0, 0x31, 0xe1, 0x44, 0xfa, 0xe6, 0x1a, 0x38, 0x99, 0x50, 0x1b, 0x49,
|
||||
0x21);
|
||||
private static final byte[] AEM110 = asBytes(0x44, 0xc0, 0xd7, 0x06);
|
||||
private static final byte[] RPI111 =
|
||||
asBytes(
|
||||
0xa7, 0x5e, 0xea, 0x58, 0x23, 0x2e, 0x73, 0x66, 0xce, 0xa1, 0xa0, 0xe7, 0x2d, 0xa0, 0xce,
|
||||
0xc5);
|
||||
private static final byte[] AEM111 = asBytes(0x5a, 0x8c, 0x79, 0xb7);
|
||||
private static final byte[] RPI112 =
|
||||
asBytes(
|
||||
0x6a, 0xd7, 0x62, 0x1f, 0xe1, 0xda, 0x01, 0x39, 0xff, 0x8b, 0xad, 0x7f, 0x37, 0x9c, 0xab,
|
||||
0xf6);
|
||||
private static final byte[] AEM112 = asBytes(0x27, 0x9f, 0x16, 0xb1);
|
||||
private static final byte[] RPI113 =
|
||||
asBytes(
|
||||
0x6f, 0xe2, 0xac, 0x45, 0xf6, 0x5c, 0x8a, 0xc6, 0x9f, 0xdc, 0x5e, 0xf7, 0xfa, 0x9f, 0xf7,
|
||||
0xf0);
|
||||
private static final byte[] AEM113 = asBytes(0x4b, 0xd9, 0x07, 0xaa);
|
||||
private static final byte[] RPI114 =
|
||||
asBytes(
|
||||
0x2f, 0xbe, 0xc6, 0x8f, 0xd2, 0x7d, 0xdd, 0xdb, 0x42, 0x23, 0x04, 0x4e, 0xfc, 0x77, 0x98,
|
||||
0x51);
|
||||
private static final byte[] AEM114 = asBytes(0x2d, 0xf6, 0xc5, 0xeb);
|
||||
private static final byte[] RPI115 =
|
||||
asBytes(
|
||||
0x32, 0xbf, 0x68, 0x8a, 0x7c, 0x83, 0x4b, 0xe1, 0xbf, 0xab, 0x7c, 0x8e, 0x0e, 0x58, 0x0a,
|
||||
0xdb);
|
||||
private static final byte[] AEM115 = asBytes(0x66, 0x85, 0x2d, 0x43);
|
||||
private static final byte[] RPI116 =
|
||||
asBytes(
|
||||
0xda, 0xe3, 0xa7, 0xd8, 0xc6, 0x24, 0x27, 0xb0, 0x9c, 0x0e, 0x7b, 0xbf, 0x48, 0x9d, 0x34,
|
||||
0xbd);
|
||||
private static final byte[] AEM116 = asBytes(0x83, 0x6d, 0x3b, 0x95);
|
||||
private static final byte[] RPI117 =
|
||||
asBytes(
|
||||
0x3c, 0x4b, 0x02, 0xbd, 0x5e, 0xd2, 0x8c, 0x67, 0x82, 0x9c, 0x97, 0x79, 0x10, 0x79, 0xaf,
|
||||
0xd2);
|
||||
private static final byte[] AEM117 = asBytes(0x27, 0x35, 0xb9, 0x97);
|
||||
private static final byte[] RPI118 =
|
||||
asBytes(
|
||||
0xe2, 0xfa, 0xea, 0xc3, 0xdb, 0xd1, 0x50, 0xec, 0x8e, 0xa8, 0xe7, 0xb3, 0xe5, 0xbb, 0x84,
|
||||
0x54);
|
||||
private static final byte[] AEM118 = asBytes(0xd7, 0x1f, 0x97, 0xc2);
|
||||
private static final byte[] RPI119 =
|
||||
asBytes(
|
||||
0x69, 0x94, 0x2a, 0x72, 0x13, 0xea, 0xf3, 0xc1, 0x4a, 0x69, 0x99, 0x6b, 0xa6, 0xc6, 0xbf,
|
||||
0xeb);
|
||||
private static final byte[] AEM119 = asBytes(0x53, 0xbc, 0x4d, 0xb5);
|
||||
private static final byte[] RPI120 =
|
||||
asBytes(
|
||||
0x1c, 0x5c, 0x4d, 0xd2, 0x54, 0x52, 0xe9, 0x7d, 0xd1, 0x87, 0xdd, 0x7c, 0xe1, 0xd1, 0xee,
|
||||
0x81);
|
||||
private static final byte[] AEM120 = asBytes(0x48, 0xa4, 0xd3, 0x79);
|
||||
private static final byte[] RPI121 =
|
||||
asBytes(
|
||||
0xfb, 0xf5, 0x60, 0x7a, 0x7c, 0x61, 0x2a, 0xce, 0xd1, 0x60, 0xe7, 0x55, 0xa9, 0x87, 0x26,
|
||||
0x2d);
|
||||
private static final byte[] AEM121 = asBytes(0xb7, 0x8d, 0xc1, 0xf5);
|
||||
private static final byte[] RPI122 =
|
||||
asBytes(
|
||||
0x3e, 0x2d, 0xe1, 0x30, 0x70, 0xf2, 0x74, 0x43, 0xd9, 0xba, 0x3e, 0xb4, 0x3f, 0x9a, 0x71,
|
||||
0xea);
|
||||
private static final byte[] AEM122 = asBytes(0x58, 0x21, 0x70, 0xca);
|
||||
private static final byte[] RPI123 =
|
||||
asBytes(
|
||||
0x8a, 0x12, 0xd2, 0x5f, 0x00, 0x6f, 0xab, 0x5a, 0x27, 0x07, 0xda, 0x9e, 0x6c, 0x4e, 0x96,
|
||||
0xbe);
|
||||
private static final byte[] AEM123 = asBytes(0x93, 0x95, 0x94, 0xcc);
|
||||
private static final byte[] RPI124 =
|
||||
asBytes(
|
||||
0x6f, 0xd9, 0x8c, 0x22, 0xe2, 0x27, 0x83, 0x8e, 0x6f, 0x67, 0x36, 0x97, 0x64, 0x43, 0x77,
|
||||
0x25);
|
||||
private static final byte[] AEM124 = asBytes(0xc1, 0x4f, 0x5b, 0x11);
|
||||
private static final byte[] RPI125 =
|
||||
asBytes(
|
||||
0x3d, 0xa2, 0x12, 0xae, 0xbd, 0xb7, 0x8b, 0xa8, 0x19, 0x80, 0x9d, 0x03, 0xc6, 0xcf, 0x56,
|
||||
0xe2);
|
||||
private static final byte[] AEM125 = asBytes(0x30, 0x09, 0x12, 0xda);
|
||||
private static final byte[] RPI126 =
|
||||
asBytes(
|
||||
0x8c, 0x48, 0xda, 0x73, 0xe2, 0x9e, 0xff, 0xc9, 0xb7, 0x4b, 0xb0, 0x97, 0x09, 0x6e, 0x0a,
|
||||
0x0a);
|
||||
private static final byte[] AEM126 = asBytes(0xce, 0x79, 0xc5, 0x0a);
|
||||
private static final byte[] RPI127 =
|
||||
asBytes(
|
||||
0xe5, 0x3c, 0x68, 0xb4, 0xb0, 0x1c, 0x68, 0xf3, 0x7e, 0x65, 0xa0, 0xdc, 0x8e, 0x67, 0xf4,
|
||||
0x5d);
|
||||
private static final byte[] AEM127 = asBytes(0xe0, 0x4f, 0x38, 0x67);
|
||||
private static final byte[] RPI128 =
|
||||
asBytes(
|
||||
0x83, 0x31, 0xdd, 0xe6, 0x36, 0x4b, 0x11, 0x95, 0x27, 0xaf, 0x76, 0xfe, 0xe1, 0x7a, 0xab,
|
||||
0xcf);
|
||||
private static final byte[] AEM128 = asBytes(0x64, 0x18, 0x7b, 0xdf);
|
||||
private static final byte[] RPI129 =
|
||||
asBytes(
|
||||
0x8c, 0x14, 0x47, 0x1f, 0x55, 0x71, 0x92, 0x63, 0x96, 0xdd, 0xe6, 0xf7, 0xb7, 0xb3, 0x5b,
|
||||
0x56);
|
||||
private static final byte[] AEM129 = asBytes(0xe8, 0x7c, 0x05, 0xfd);
|
||||
private static final byte[] RPI130 =
|
||||
asBytes(
|
||||
0x4e, 0xb6, 0xb2, 0xde, 0xb4, 0x0e, 0x5e, 0xc9, 0xbc, 0x39, 0x83, 0x81, 0x02, 0xa4, 0xf4,
|
||||
0xf9);
|
||||
private static final byte[] AEM130 = asBytes(0x4e, 0x70, 0x83, 0x25);
|
||||
private static final byte[] RPI131 =
|
||||
asBytes(
|
||||
0x77, 0xf2, 0x14, 0x1c, 0xef, 0xfd, 0x0a, 0xa3, 0xbe, 0xe4, 0xb6, 0x7c, 0x45, 0x0d, 0x9a,
|
||||
0xa6);
|
||||
private static final byte[] AEM131 = asBytes(0xa1, 0x57, 0xeb, 0x59);
|
||||
private static final byte[] RPI132 =
|
||||
asBytes(
|
||||
0x04, 0x3d, 0x78, 0xe2, 0x0c, 0xb5, 0x9c, 0x0b, 0xcb, 0x15, 0x78, 0xff, 0x93, 0xea, 0x54,
|
||||
0x4a);
|
||||
private static final byte[] AEM132 = asBytes(0x8d, 0x30, 0x43, 0x2a);
|
||||
private static final byte[] RPI133 =
|
||||
asBytes(
|
||||
0x65, 0xb8, 0xec, 0xc4, 0x56, 0x1c, 0x1c, 0xca, 0x05, 0x3d, 0x81, 0x4f, 0xfd, 0x89, 0x61,
|
||||
0xd4);
|
||||
private static final byte[] AEM133 = asBytes(0x5b, 0x24, 0x38, 0x90);
|
||||
private static final byte[] RPI134 =
|
||||
asBytes(
|
||||
0x32, 0xf2, 0x5a, 0x17, 0x24, 0xf2, 0xbd, 0xca, 0xd0, 0x5a, 0xbc, 0x14, 0x82, 0xe1, 0x32,
|
||||
0x9e);
|
||||
private static final byte[] AEM134 = asBytes(0x74, 0x90, 0xd2, 0x11);
|
||||
private static final byte[] RPI135 =
|
||||
asBytes(
|
||||
0x20, 0x3b, 0xa3, 0xf3, 0xf7, 0x23, 0x02, 0x66, 0xb9, 0x93, 0xb3, 0xee, 0x7b, 0x2d, 0x86,
|
||||
0x08);
|
||||
private static final byte[] AEM135 = asBytes(0x1f, 0x01, 0x9d, 0xf2);
|
||||
private static final byte[] RPI136 =
|
||||
asBytes(
|
||||
0xe5, 0xe7, 0xa4, 0x70, 0x69, 0x21, 0x6e, 0x1a, 0x88, 0x7b, 0x90, 0xef, 0x03, 0x94, 0xa3,
|
||||
0x5c);
|
||||
private static final byte[] AEM136 = asBytes(0x99, 0xe6, 0x12, 0xb7);
|
||||
private static final byte[] RPI137 =
|
||||
asBytes(
|
||||
0x3f, 0xfc, 0x8b, 0xb9, 0x1d, 0xbc, 0xd8, 0xee, 0x92, 0x49, 0x48, 0xf5, 0x08, 0x0b, 0x19,
|
||||
0x0d);
|
||||
private static final byte[] AEM137 = asBytes(0x26, 0x4a, 0x57, 0x7e);
|
||||
private static final byte[] RPI138 =
|
||||
asBytes(
|
||||
0x32, 0x37, 0x53, 0x91, 0x07, 0x7f, 0xbf, 0x76, 0x86, 0xba, 0xfa, 0x7d, 0xc1, 0x56, 0xbe,
|
||||
0x1c);
|
||||
private static final byte[] AEM138 = asBytes(0xa8, 0x11, 0xba, 0x62);
|
||||
private static final byte[] RPI139 =
|
||||
asBytes(
|
||||
0xa8, 0x90, 0x49, 0x65, 0xae, 0xc5, 0xdd, 0xb6, 0x55, 0xe9, 0x70, 0x07, 0xd2, 0x23, 0xdb,
|
||||
0x48);
|
||||
private static final byte[] AEM139 = asBytes(0x2b, 0x48, 0x33, 0x21);
|
||||
private static final byte[] RPI140 =
|
||||
asBytes(
|
||||
0x41, 0x5c, 0xf7, 0xaf, 0x1d, 0xc9, 0xfe, 0xac, 0xb3, 0x97, 0x84, 0x88, 0xf5, 0x04, 0x68,
|
||||
0x93);
|
||||
private static final byte[] AEM140 = asBytes(0xe2, 0xef, 0x53, 0x7e);
|
||||
private static final byte[] RPI141 =
|
||||
asBytes(
|
||||
0x86, 0xf8, 0xdd, 0xc0, 0xc9, 0x3e, 0x53, 0xe3, 0xa5, 0x82, 0xe6, 0x1f, 0x01, 0xf7, 0xdf,
|
||||
0x2f);
|
||||
private static final byte[] AEM141 = asBytes(0x71, 0x1d, 0xbf, 0x6d);
|
||||
private static final byte[] RPI142 =
|
||||
asBytes(
|
||||
0xa6, 0x5e, 0xf7, 0xba, 0x97, 0x52, 0xc4, 0x17, 0x3b, 0xa4, 0x8a, 0x33, 0x84, 0x9c, 0x5e,
|
||||
0x52);
|
||||
private static final byte[] AEM142 = asBytes(0x59, 0x2d, 0xbc, 0xa8);
|
||||
private static final byte[] RPI143 =
|
||||
asBytes(
|
||||
0xf4, 0x31, 0xb6, 0x2e, 0xcf, 0x44, 0x31, 0x02, 0xce, 0x4e, 0xd0, 0x40, 0x7d, 0xe5, 0x4b,
|
||||
0xd4);
|
||||
private static final byte[] AEM143 = asBytes(0x12, 0x15, 0xe5, 0x7e);
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
public static final List<AdvertisedData> ADVERTISED_DATA =
|
||||
Collections.unmodifiableList(Arrays.asList(
|
||||
new AdvertisedData(RPI0, AEM0),
|
||||
new AdvertisedData(RPI1, AEM1),
|
||||
new AdvertisedData(RPI2, AEM2),
|
||||
new AdvertisedData(RPI3, AEM3),
|
||||
new AdvertisedData(RPI4, AEM4),
|
||||
new AdvertisedData(RPI5, AEM5),
|
||||
new AdvertisedData(RPI6, AEM6),
|
||||
new AdvertisedData(RPI7, AEM7),
|
||||
new AdvertisedData(RPI8, AEM8),
|
||||
new AdvertisedData(RPI9, AEM9),
|
||||
new AdvertisedData(RPI10, AEM10),
|
||||
new AdvertisedData(RPI11, AEM11),
|
||||
new AdvertisedData(RPI12, AEM12),
|
||||
new AdvertisedData(RPI13, AEM13),
|
||||
new AdvertisedData(RPI14, AEM14),
|
||||
new AdvertisedData(RPI15, AEM15),
|
||||
new AdvertisedData(RPI16, AEM16),
|
||||
new AdvertisedData(RPI17, AEM17),
|
||||
new AdvertisedData(RPI18, AEM18),
|
||||
new AdvertisedData(RPI19, AEM19),
|
||||
new AdvertisedData(RPI20, AEM20),
|
||||
new AdvertisedData(RPI21, AEM21),
|
||||
new AdvertisedData(RPI22, AEM22),
|
||||
new AdvertisedData(RPI23, AEM23),
|
||||
new AdvertisedData(RPI24, AEM24),
|
||||
new AdvertisedData(RPI25, AEM25),
|
||||
new AdvertisedData(RPI26, AEM26),
|
||||
new AdvertisedData(RPI27, AEM27),
|
||||
new AdvertisedData(RPI28, AEM28),
|
||||
new AdvertisedData(RPI29, AEM29),
|
||||
new AdvertisedData(RPI30, AEM30),
|
||||
new AdvertisedData(RPI31, AEM31),
|
||||
new AdvertisedData(RPI32, AEM32),
|
||||
new AdvertisedData(RPI33, AEM33),
|
||||
new AdvertisedData(RPI34, AEM34),
|
||||
new AdvertisedData(RPI35, AEM35),
|
||||
new AdvertisedData(RPI36, AEM36),
|
||||
new AdvertisedData(RPI37, AEM37),
|
||||
new AdvertisedData(RPI38, AEM38),
|
||||
new AdvertisedData(RPI39, AEM39),
|
||||
new AdvertisedData(RPI40, AEM40),
|
||||
new AdvertisedData(RPI41, AEM41),
|
||||
new AdvertisedData(RPI42, AEM42),
|
||||
new AdvertisedData(RPI43, AEM43),
|
||||
new AdvertisedData(RPI44, AEM44),
|
||||
new AdvertisedData(RPI45, AEM45),
|
||||
new AdvertisedData(RPI46, AEM46),
|
||||
new AdvertisedData(RPI47, AEM47),
|
||||
new AdvertisedData(RPI48, AEM48),
|
||||
new AdvertisedData(RPI49, AEM49),
|
||||
new AdvertisedData(RPI50, AEM50),
|
||||
new AdvertisedData(RPI51, AEM51),
|
||||
new AdvertisedData(RPI52, AEM52),
|
||||
new AdvertisedData(RPI53, AEM53),
|
||||
new AdvertisedData(RPI54, AEM54),
|
||||
new AdvertisedData(RPI55, AEM55),
|
||||
new AdvertisedData(RPI56, AEM56),
|
||||
new AdvertisedData(RPI57, AEM57),
|
||||
new AdvertisedData(RPI58, AEM58),
|
||||
new AdvertisedData(RPI59, AEM59),
|
||||
new AdvertisedData(RPI60, AEM60),
|
||||
new AdvertisedData(RPI61, AEM61),
|
||||
new AdvertisedData(RPI62, AEM62),
|
||||
new AdvertisedData(RPI63, AEM63),
|
||||
new AdvertisedData(RPI64, AEM64),
|
||||
new AdvertisedData(RPI65, AEM65),
|
||||
new AdvertisedData(RPI66, AEM66),
|
||||
new AdvertisedData(RPI67, AEM67),
|
||||
new AdvertisedData(RPI68, AEM68),
|
||||
new AdvertisedData(RPI69, AEM69),
|
||||
new AdvertisedData(RPI70, AEM70),
|
||||
new AdvertisedData(RPI71, AEM71),
|
||||
new AdvertisedData(RPI72, AEM72),
|
||||
new AdvertisedData(RPI73, AEM73),
|
||||
new AdvertisedData(RPI74, AEM74),
|
||||
new AdvertisedData(RPI75, AEM75),
|
||||
new AdvertisedData(RPI76, AEM76),
|
||||
new AdvertisedData(RPI77, AEM77),
|
||||
new AdvertisedData(RPI78, AEM78),
|
||||
new AdvertisedData(RPI79, AEM79),
|
||||
new AdvertisedData(RPI80, AEM80),
|
||||
new AdvertisedData(RPI81, AEM81),
|
||||
new AdvertisedData(RPI82, AEM82),
|
||||
new AdvertisedData(RPI83, AEM83),
|
||||
new AdvertisedData(RPI84, AEM84),
|
||||
new AdvertisedData(RPI85, AEM85),
|
||||
new AdvertisedData(RPI86, AEM86),
|
||||
new AdvertisedData(RPI87, AEM87),
|
||||
new AdvertisedData(RPI88, AEM88),
|
||||
new AdvertisedData(RPI89, AEM89),
|
||||
new AdvertisedData(RPI90, AEM90),
|
||||
new AdvertisedData(RPI91, AEM91),
|
||||
new AdvertisedData(RPI92, AEM92),
|
||||
new AdvertisedData(RPI93, AEM93),
|
||||
new AdvertisedData(RPI94, AEM94),
|
||||
new AdvertisedData(RPI95, AEM95),
|
||||
new AdvertisedData(RPI96, AEM96),
|
||||
new AdvertisedData(RPI97, AEM97),
|
||||
new AdvertisedData(RPI98, AEM98),
|
||||
new AdvertisedData(RPI99, AEM99),
|
||||
new AdvertisedData(RPI100, AEM100),
|
||||
new AdvertisedData(RPI101, AEM101),
|
||||
new AdvertisedData(RPI102, AEM102),
|
||||
new AdvertisedData(RPI103, AEM103),
|
||||
new AdvertisedData(RPI104, AEM104),
|
||||
new AdvertisedData(RPI105, AEM105),
|
||||
new AdvertisedData(RPI106, AEM106),
|
||||
new AdvertisedData(RPI107, AEM107),
|
||||
new AdvertisedData(RPI108, AEM108),
|
||||
new AdvertisedData(RPI109, AEM109),
|
||||
new AdvertisedData(RPI110, AEM110),
|
||||
new AdvertisedData(RPI111, AEM111),
|
||||
new AdvertisedData(RPI112, AEM112),
|
||||
new AdvertisedData(RPI113, AEM113),
|
||||
new AdvertisedData(RPI114, AEM114),
|
||||
new AdvertisedData(RPI115, AEM115),
|
||||
new AdvertisedData(RPI116, AEM116),
|
||||
new AdvertisedData(RPI117, AEM117),
|
||||
new AdvertisedData(RPI118, AEM118),
|
||||
new AdvertisedData(RPI119, AEM119),
|
||||
new AdvertisedData(RPI120, AEM120),
|
||||
new AdvertisedData(RPI121, AEM121),
|
||||
new AdvertisedData(RPI122, AEM122),
|
||||
new AdvertisedData(RPI123, AEM123),
|
||||
new AdvertisedData(RPI124, AEM124),
|
||||
new AdvertisedData(RPI125, AEM125),
|
||||
new AdvertisedData(RPI126, AEM126),
|
||||
new AdvertisedData(RPI127, AEM127),
|
||||
new AdvertisedData(RPI128, AEM128),
|
||||
new AdvertisedData(RPI129, AEM129),
|
||||
new AdvertisedData(RPI130, AEM130),
|
||||
new AdvertisedData(RPI131, AEM131),
|
||||
new AdvertisedData(RPI132, AEM132),
|
||||
new AdvertisedData(RPI133, AEM133),
|
||||
new AdvertisedData(RPI134, AEM134),
|
||||
new AdvertisedData(RPI135, AEM135),
|
||||
new AdvertisedData(RPI136, AEM136),
|
||||
new AdvertisedData(RPI137, AEM137),
|
||||
new AdvertisedData(RPI138, AEM138),
|
||||
new AdvertisedData(RPI139, AEM139),
|
||||
new AdvertisedData(RPI140, AEM140),
|
||||
new AdvertisedData(RPI141, AEM141),
|
||||
new AdvertisedData(RPI142, AEM142),
|
||||
new AdvertisedData(RPI143, AEM143)));
|
||||
|
||||
private TestVectors() {
|
||||
}
|
||||
}
|
||||
|
||||
13
play-services-nearby/src/main/AndroidManifest.xml
Normal file
13
play-services-nearby/src/main/AndroidManifest.xml
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ SPDX-FileCopyrightText: 2020 microG Project Team
|
||||
~ SPDX-License-Identifier: Apache-2.0
|
||||
-->
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<application>
|
||||
<service
|
||||
android:name="com.google.android.gms.nearby.exposurenotification.WakeUpService"
|
||||
android:exported="true"
|
||||
android:permission="com.google.android.gms.nearby.exposurenotification.EXPOSURE_CALLBACK"/>
|
||||
</application>
|
||||
</manifest>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2020, microG Project Team
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package com.google.android.gms.nearby.exposurenotification;
|
||||
|
||||
parcelable DailySummary;
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2020, microG Project Team
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package com.google.android.gms.nearby.exposurenotification;
|
||||
|
||||
parcelable DiagnosisKeysDataMapping;
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2020, microG Project Team
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package com.google.android.gms.nearby.exposurenotification;
|
||||
|
||||
parcelable ExposureInformation;
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2020, microG Project Team
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package com.google.android.gms.nearby.exposurenotification;
|
||||
|
||||
parcelable ExposureSummary;
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2020, microG Project Team
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package com.google.android.gms.nearby.exposurenotification;
|
||||
|
||||
parcelable ExposureWindow;
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2020, microG Project Team
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package com.google.android.gms.nearby.exposurenotification;
|
||||
|
||||
parcelable PackageConfiguration;
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2020, microG Project Team
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package com.google.android.gms.nearby.exposurenotification;
|
||||
|
||||
parcelable TemporaryExposureKey;
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2020, microG Project Team
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package com.google.android.gms.nearby.exposurenotification.internal;
|
||||
|
||||
parcelable GetCalibrationConfidenceParams;
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2020, microG Project Team
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package com.google.android.gms.nearby.exposurenotification.internal;
|
||||
|
||||
parcelable GetDailySummariesParams;
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2020, microG Project Team
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package com.google.android.gms.nearby.exposurenotification.internal;
|
||||
|
||||
parcelable GetDiagnosisKeysDataMappingParams;
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue