mirror of
https://codeberg.org/timelimit/timelimit-android.git
synced 2025-10-03 09:49:25 +02:00
Add option to annoy user after manipulation
This commit is contained in:
parent
31c49c8195
commit
1ff5ab6575
14 changed files with 311 additions and 9 deletions
|
@ -75,6 +75,15 @@
|
||||||
android:exported="false"
|
android:exported="false"
|
||||||
android:name=".ui.manipulation.UnlockAfterManipulationActivity" />
|
android:name=".ui.manipulation.UnlockAfterManipulationActivity" />
|
||||||
|
|
||||||
|
<activity
|
||||||
|
tools:ignore="UnusedAttribute"
|
||||||
|
android:excludeFromRecents="true"
|
||||||
|
android:autoRemoveFromRecents="true"
|
||||||
|
android:taskAffinity=":annoy"
|
||||||
|
android:showOnLockScreen="true"
|
||||||
|
android:exported="false"
|
||||||
|
android:name=".ui.manipulation.AnnoyActivity" />
|
||||||
|
|
||||||
<!-- system integration -->
|
<!-- system integration -->
|
||||||
|
|
||||||
<receiver android:name=".integration.platform.android.receiver.BootReceiver">
|
<receiver android:name=".integration.platform.android.receiver.BootReceiver">
|
||||||
|
|
|
@ -192,4 +192,6 @@ object HintsToShow {
|
||||||
object ExperimentalFlags {
|
object ExperimentalFlags {
|
||||||
const val DISABLE_BLOCK_ON_MANIPULATION = 1L
|
const val DISABLE_BLOCK_ON_MANIPULATION = 1L
|
||||||
const val SYSTEM_LEVEL_BLOCKING = 2L
|
const val SYSTEM_LEVEL_BLOCKING = 2L
|
||||||
|
const val MANIPULATION_ANNOY_USER_ONLY = 4L
|
||||||
|
const val MANIPULATION_ANNOY_USER = MANIPULATION_ANNOY_USER_ONLY or DISABLE_BLOCK_ON_MANIPULATION // otherwise there would be a conflict between both features
|
||||||
}
|
}
|
|
@ -42,6 +42,7 @@ abstract class PlatformIntegration(
|
||||||
abstract fun showOverlayMessage(text: String)
|
abstract fun showOverlayMessage(text: String)
|
||||||
|
|
||||||
abstract fun showAppLockScreen(currentPackageName: String, currentActivityName: String?)
|
abstract fun showAppLockScreen(currentPackageName: String, currentActivityName: String?)
|
||||||
|
abstract fun showAnnoyScreen(annoyDuration: Long)
|
||||||
abstract fun muteAudioIfPossible(packageName: String)
|
abstract fun muteAudioIfPossible(packageName: String)
|
||||||
abstract fun setShowBlockingOverlay(show: Boolean)
|
abstract fun setShowBlockingOverlay(show: Boolean)
|
||||||
// this should throw an SecurityException if the permission is missing
|
// this should throw an SecurityException if the permission is missing
|
||||||
|
|
|
@ -46,6 +46,7 @@ import io.timelimit.android.data.model.AppActivity
|
||||||
import io.timelimit.android.integration.platform.*
|
import io.timelimit.android.integration.platform.*
|
||||||
import io.timelimit.android.integration.platform.android.foregroundapp.ForegroundAppHelper
|
import io.timelimit.android.integration.platform.android.foregroundapp.ForegroundAppHelper
|
||||||
import io.timelimit.android.ui.lock.LockActivity
|
import io.timelimit.android.ui.lock.LockActivity
|
||||||
|
import io.timelimit.android.ui.manipulation.AnnoyActivity
|
||||||
import kotlinx.coroutines.channels.Channel
|
import kotlinx.coroutines.channels.Channel
|
||||||
import kotlinx.coroutines.channels.consumeEach
|
import kotlinx.coroutines.channels.consumeEach
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
|
@ -225,6 +226,10 @@ class AndroidIntegration(context: Context): PlatformIntegration(maximumProtectio
|
||||||
LockActivity.start(context, currentPackageName, currentActivityName)
|
LockActivity.start(context, currentPackageName, currentActivityName)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun showAnnoyScreen(annoyDuration: Long) {
|
||||||
|
AnnoyActivity.start(context, annoyDuration)
|
||||||
|
}
|
||||||
|
|
||||||
override fun muteAudioIfPossible(packageName: String) {
|
override fun muteAudioIfPossible(packageName: String) {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||||
if (getNotificationAccessPermissionStatus() == NewPermissionStatus.Granted) {
|
if (getNotificationAccessPermissionStatus() == NewPermissionStatus.Granted) {
|
||||||
|
|
|
@ -87,6 +87,10 @@ class DummyIntegration(
|
||||||
launchLockScreenForPackage = currentPackageName
|
launchLockScreenForPackage = currentPackageName
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun showAnnoyScreen(annoyDuration: Long) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
|
||||||
override fun muteAudioIfPossible(packageName: String) {
|
override fun muteAudioIfPossible(packageName: String) {
|
||||||
// ignore
|
// ignore
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ import android.util.Log
|
||||||
import android.util.SparseArray
|
import android.util.SparseArray
|
||||||
import android.util.SparseLongArray
|
import android.util.SparseLongArray
|
||||||
import androidx.lifecycle.LiveData
|
import androidx.lifecycle.LiveData
|
||||||
|
import androidx.lifecycle.MutableLiveData
|
||||||
import io.timelimit.android.BuildConfig
|
import io.timelimit.android.BuildConfig
|
||||||
import io.timelimit.android.R
|
import io.timelimit.android.R
|
||||||
import io.timelimit.android.async.Threads
|
import io.timelimit.android.async.Threads
|
||||||
|
@ -37,6 +38,7 @@ import io.timelimit.android.integration.platform.android.AndroidIntegrationApps
|
||||||
import io.timelimit.android.livedata.*
|
import io.timelimit.android.livedata.*
|
||||||
import io.timelimit.android.sync.actions.UpdateDeviceStatusAction
|
import io.timelimit.android.sync.actions.UpdateDeviceStatusAction
|
||||||
import io.timelimit.android.sync.actions.apply.ApplyActionUtil
|
import io.timelimit.android.sync.actions.apply.ApplyActionUtil
|
||||||
|
import io.timelimit.android.ui.IsAppInForeground
|
||||||
import io.timelimit.android.util.AndroidVersion
|
import io.timelimit.android.util.AndroidVersion
|
||||||
import io.timelimit.android.util.TimeTextUtil
|
import io.timelimit.android.util.TimeTextUtil
|
||||||
import io.timelimit.android.work.PeriodicSyncInBackgroundWorker
|
import io.timelimit.android.work.PeriodicSyncInBackgroundWorker
|
||||||
|
@ -67,6 +69,7 @@ class BackgroundTaskLogic(val appLogic: AppLogic) {
|
||||||
runAsyncExpectForever { backgroundServiceLoop() }
|
runAsyncExpectForever { backgroundServiceLoop() }
|
||||||
runAsyncExpectForever { syncDeviceStatusLoop() }
|
runAsyncExpectForever { syncDeviceStatusLoop() }
|
||||||
runAsyncExpectForever { backupDatabaseLoop() }
|
runAsyncExpectForever { backupDatabaseLoop() }
|
||||||
|
runAsyncExpectForever { annoyUserOnManipulationLoop() }
|
||||||
runAsync {
|
runAsync {
|
||||||
// this is effective after an reboot
|
// this is effective after an reboot
|
||||||
|
|
||||||
|
@ -691,4 +694,66 @@ class BackgroundTaskLogic(val appLogic: AppLogic) {
|
||||||
appLogic.timeApi.sleep(1000 * 60 * 60 * 3 /* 3 hours */)
|
appLogic.timeApi.sleep(1000 * 60 * 60 * 3 /* 3 hours */)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// first time: annoy for 20 seconds; free for 5 minutes
|
||||||
|
// second time: annoy for 30 seconds; free for 2 minutes
|
||||||
|
// third time: annoy for 1 minute; free for 1 minute
|
||||||
|
// then: annoy for 2 minutes; free for 1 minute
|
||||||
|
private suspend fun annoyUserOnManipulationLoop() {
|
||||||
|
val isManipulated = appLogic.deviceEntryIfEnabled.map { it?.hasActiveManipulationWarning ?: false }
|
||||||
|
val enableAnnoy = appLogic.database.config().isExperimentalFlagsSetAsync(ExperimentalFlags.MANIPULATION_ANNOY_USER)
|
||||||
|
val timeLimitNotActive = IsAppInForeground.isRunning.invert()
|
||||||
|
|
||||||
|
var counter = 0
|
||||||
|
var globalCounter = 0
|
||||||
|
|
||||||
|
val shouldAnnoyNow = isManipulated.and(enableAnnoy).and(timeLimitNotActive)
|
||||||
|
|
||||||
|
if (BuildConfig.DEBUG) {
|
||||||
|
Log.d(LOG_TAG, "delay before enabling annoying")
|
||||||
|
}
|
||||||
|
|
||||||
|
delay(1000 * 15)
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
if (BuildConfig.DEBUG) {
|
||||||
|
Log.d(LOG_TAG, "wait until should annoy")
|
||||||
|
}
|
||||||
|
|
||||||
|
shouldAnnoyNow.waitUntilValueMatches { it == true }
|
||||||
|
|
||||||
|
val annoyDurationInSeconds = when (counter) {
|
||||||
|
0 -> 20
|
||||||
|
1 -> 30
|
||||||
|
2 -> 60
|
||||||
|
else -> 120
|
||||||
|
}
|
||||||
|
|
||||||
|
val freeDurationInSeconds = when (counter) {
|
||||||
|
0 -> 5 * 60
|
||||||
|
1 -> 2 * 60
|
||||||
|
else -> 60
|
||||||
|
}
|
||||||
|
|
||||||
|
if (BuildConfig.DEBUG) {
|
||||||
|
Log.d(LOG_TAG, "annoy for $annoyDurationInSeconds seconds; free for $freeDurationInSeconds seconds")
|
||||||
|
}
|
||||||
|
|
||||||
|
appLogic.platformIntegration.showAnnoyScreen(annoyDurationInSeconds.toLong())
|
||||||
|
|
||||||
|
counter++
|
||||||
|
globalCounter++
|
||||||
|
|
||||||
|
// reset counter if there was nothing for one hour
|
||||||
|
val globalCounterBackup = globalCounter
|
||||||
|
appLogic.timeApi.runDelayed(Runnable {
|
||||||
|
if (globalCounter == globalCounterBackup) {
|
||||||
|
counter = 0
|
||||||
|
}
|
||||||
|
}, 1000 * 60 * 60 /* 1 hour */)
|
||||||
|
|
||||||
|
// wait before annoying next time
|
||||||
|
delay((annoyDurationInSeconds + freeDurationInSeconds) * 1000L)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,7 +54,6 @@ class DiagnoseExperimentalFlagFragment : Fragment() {
|
||||||
val checkboxes = flags.map {
|
val checkboxes = flags.map {
|
||||||
CheckBox(context).apply {
|
CheckBox(context).apply {
|
||||||
setText(it.label)
|
setText(it.label)
|
||||||
isEnabled = it.enable
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,15 +62,20 @@ class DiagnoseExperimentalFlagFragment : Fragment() {
|
||||||
database.config().experimentalFlags.observe(this, Observer { setFlags ->
|
database.config().experimentalFlags.observe(this, Observer { setFlags ->
|
||||||
flags.forEachIndexed { index, flag ->
|
flags.forEachIndexed { index, flag ->
|
||||||
val checkbox = checkboxes[index]
|
val checkbox = checkboxes[index]
|
||||||
val isFlagSet = (setFlags and flag.flag) == flag.flag
|
val isFlagSet = (setFlags and flag.enableFlags) == flag.enableFlags
|
||||||
|
|
||||||
checkbox.setOnCheckedChangeListener { _, _ -> }
|
checkbox.setOnCheckedChangeListener { _, _ -> }
|
||||||
checkbox.isChecked = isFlagSet
|
checkbox.isChecked = isFlagSet
|
||||||
|
checkbox.isEnabled = flag.enable(setFlags)
|
||||||
checkbox.setOnCheckedChangeListener { _, didCheck ->
|
checkbox.setOnCheckedChangeListener { _, didCheck ->
|
||||||
if (didCheck != isFlagSet) {
|
if (didCheck != isFlagSet) {
|
||||||
if (auth.requestAuthenticationOrReturnTrue()) {
|
if (auth.requestAuthenticationOrReturnTrue()) {
|
||||||
Threads.database.execute {
|
Threads.database.execute {
|
||||||
database.config().setExperimentalFlag(flag.flag, didCheck)
|
if (didCheck) {
|
||||||
|
database.config().setExperimentalFlag(flag.enableFlags, true)
|
||||||
|
} else {
|
||||||
|
database.config().setExperimentalFlag(flag.disableFlags, false)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
checkbox.isChecked = isFlagSet
|
checkbox.isChecked = isFlagSet
|
||||||
|
@ -87,20 +91,31 @@ class DiagnoseExperimentalFlagFragment : Fragment() {
|
||||||
|
|
||||||
data class DiagnoseExperimentalFlagItem(
|
data class DiagnoseExperimentalFlagItem(
|
||||||
val label: Int,
|
val label: Int,
|
||||||
val flag: Long,
|
val enableFlags: Long,
|
||||||
val enable: Boolean
|
val disableFlags: Long,
|
||||||
|
val enable: (flags: Long) -> Boolean
|
||||||
) {
|
) {
|
||||||
companion object {
|
companion object {
|
||||||
val items = listOf(
|
val items = listOf(
|
||||||
DiagnoseExperimentalFlagItem(
|
DiagnoseExperimentalFlagItem(
|
||||||
label = R.string.diagnose_exf_lom,
|
label = R.string.diagnose_exf_lom,
|
||||||
flag = ExperimentalFlags.DISABLE_BLOCK_ON_MANIPULATION,
|
enableFlags = ExperimentalFlags.DISABLE_BLOCK_ON_MANIPULATION,
|
||||||
enable = !BuildConfig.storeCompilant
|
disableFlags = ExperimentalFlags.DISABLE_BLOCK_ON_MANIPULATION,
|
||||||
|
enable = { flags ->
|
||||||
|
(!BuildConfig.storeCompilant) and ((flags and ExperimentalFlags.MANIPULATION_ANNOY_USER_ONLY) == 0L)
|
||||||
|
}
|
||||||
),
|
),
|
||||||
DiagnoseExperimentalFlagItem(
|
DiagnoseExperimentalFlagItem(
|
||||||
label = R.string.diagnose_exf_slb,
|
label = R.string.diagnose_exf_slb,
|
||||||
flag = ExperimentalFlags.SYSTEM_LEVEL_BLOCKING,
|
enableFlags = ExperimentalFlags.SYSTEM_LEVEL_BLOCKING,
|
||||||
enable = !BuildConfig.storeCompilant
|
disableFlags = ExperimentalFlags.SYSTEM_LEVEL_BLOCKING,
|
||||||
|
enable = { !BuildConfig.storeCompilant }
|
||||||
|
),
|
||||||
|
DiagnoseExperimentalFlagItem(
|
||||||
|
label = R.string.diagnose_exf_mau,
|
||||||
|
enableFlags = ExperimentalFlags.MANIPULATION_ANNOY_USER,
|
||||||
|
disableFlags = ExperimentalFlags.MANIPULATION_ANNOY_USER_ONLY,
|
||||||
|
enable = { !BuildConfig.storeCompilant }
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,79 @@
|
||||||
|
/*
|
||||||
|
* TimeLimit Copyright <C> 2019 Jonas Lochmann
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation version 3 of the License.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package io.timelimit.android.ui.manipulation
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.os.Build
|
||||||
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
import android.os.Bundle
|
||||||
|
import androidx.lifecycle.Observer
|
||||||
|
import androidx.lifecycle.ViewModelProviders
|
||||||
|
import io.timelimit.android.R
|
||||||
|
import io.timelimit.android.util.TimeTextUtil
|
||||||
|
import kotlinx.android.synthetic.main.annoy_activity.*
|
||||||
|
|
||||||
|
class AnnoyActivity : AppCompatActivity() {
|
||||||
|
companion object {
|
||||||
|
private const val EXTRA_DURATION = "duration"
|
||||||
|
|
||||||
|
fun start(context: Context, duration: Long) {
|
||||||
|
context.startActivity(
|
||||||
|
Intent(context, AnnoyActivity::class.java)
|
||||||
|
.putExtra(EXTRA_DURATION, duration)
|
||||||
|
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
|
||||||
|
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||||
|
.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
|
val duration = intent!!.getLongExtra(EXTRA_DURATION, 10)
|
||||||
|
val model = ViewModelProviders.of(this).get(AnnoyModel::class.java)
|
||||||
|
|
||||||
|
setContentView(R.layout.annoy_activity)
|
||||||
|
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||||
|
startLockTask()
|
||||||
|
}
|
||||||
|
|
||||||
|
model.init(duration = duration)
|
||||||
|
model.countdown.observe(this, Observer {
|
||||||
|
if (it == 0L) {
|
||||||
|
shutdown()
|
||||||
|
}
|
||||||
|
|
||||||
|
annoy_timer.setText(
|
||||||
|
getString(R.string.annoy_timer, TimeTextUtil.seconds(it.toInt(), this@AnnoyActivity))
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun shutdown() {
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||||
|
stopLockTask()
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onBackPressed() {
|
||||||
|
// super.onBackPressed()
|
||||||
|
// just ignore it
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,48 @@
|
||||||
|
/*
|
||||||
|
* TimeLimit Copyright <C> 2019 Jonas Lochmann
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation version 3 of the License.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package io.timelimit.android.ui.manipulation
|
||||||
|
|
||||||
|
import androidx.lifecycle.MutableLiveData
|
||||||
|
import androidx.lifecycle.ViewModel
|
||||||
|
import io.timelimit.android.coroutines.runAsync
|
||||||
|
import io.timelimit.android.livedata.castDown
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
|
|
||||||
|
class AnnoyModel: ViewModel() {
|
||||||
|
private val countdownInternal = MutableLiveData<Long>()
|
||||||
|
private var hadInit = false
|
||||||
|
|
||||||
|
val countdown = countdownInternal.castDown()
|
||||||
|
|
||||||
|
fun init(duration: Long) {
|
||||||
|
if (!hadInit) {
|
||||||
|
hadInit = true
|
||||||
|
|
||||||
|
countdownInternal.value = duration
|
||||||
|
|
||||||
|
runAsync {
|
||||||
|
var timer = duration
|
||||||
|
|
||||||
|
while (timer >= 0) {
|
||||||
|
delay(1000)
|
||||||
|
timer--
|
||||||
|
|
||||||
|
countdownInternal.value = timer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
26
app/src/main/res/layout/annoy_activity.xml
Normal file
26
app/src/main/res/layout/annoy_activity.xml
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
tools:context="io.timelimit.android.ui.manipulation.AnnoyActivity">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:gravity="center_horizontal"
|
||||||
|
android:layout_margin="16dp"
|
||||||
|
android:textAppearance="?android:textAppearanceLarge"
|
||||||
|
android:text="@string/annoy_info"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:textAppearance="?android:textAppearanceMedium"
|
||||||
|
android:layout_margin="16dp"
|
||||||
|
android:gravity="center"
|
||||||
|
android:id="@+id/annoy_timer"
|
||||||
|
android:text="@string/annoy_timer"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
23
app/src/main/res/values-de/strings-annoy.xml
Normal file
23
app/src/main/res/values-de/strings-annoy.xml
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
TimeLimit Copyright <C> 2019 Jonas Lochmann
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation version 3 of the License.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
-->
|
||||||
|
<resources>
|
||||||
|
<string name="annoy_info">
|
||||||
|
TimeLimit wurde manipuliert. Deshalb wird das Gerät für einen Moment gesperrt.
|
||||||
|
</string>
|
||||||
|
<string name="annoy_timer">
|
||||||
|
Das Gerät wird in %s entsperrt.
|
||||||
|
</string>
|
||||||
|
</resources>
|
|
@ -55,4 +55,5 @@
|
||||||
<string name="diagnose_exf_title">Experimentelle Parameter</string>
|
<string name="diagnose_exf_title">Experimentelle Parameter</string>
|
||||||
<string name="diagnose_exf_lom">Sperrung nach Manipulationen deaktivieren</string>
|
<string name="diagnose_exf_lom">Sperrung nach Manipulationen deaktivieren</string>
|
||||||
<string name="diagnose_exf_slb">Apps auf Systemebene sperren</string>
|
<string name="diagnose_exf_slb">Apps auf Systemebene sperren</string>
|
||||||
|
<string name="diagnose_exf_mau">Nutzer nach Manipulation nerven</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
23
app/src/main/res/values/strings-annoy.xml
Normal file
23
app/src/main/res/values/strings-annoy.xml
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
TimeLimit Copyright <C> 2019 Jonas Lochmann
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation version 3 of the License.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
-->
|
||||||
|
<resources>
|
||||||
|
<string name="annoy_info">
|
||||||
|
There was a manipulation of TimeLimit. Due to that, this device is locked for a moment.
|
||||||
|
</string>
|
||||||
|
<string name="annoy_timer">
|
||||||
|
The device will be unlocked in %s.
|
||||||
|
</string>
|
||||||
|
</resources>
|
|
@ -55,4 +55,5 @@
|
||||||
<string name="diagnose_exf_title">Experimental flags</string>
|
<string name="diagnose_exf_title">Experimental flags</string>
|
||||||
<string name="diagnose_exf_lom">Disable locking after manipulations</string>
|
<string name="diagnose_exf_lom">Disable locking after manipulations</string>
|
||||||
<string name="diagnose_exf_slb">Block Apps at system level</string>
|
<string name="diagnose_exf_slb">Block Apps at system level</string>
|
||||||
|
<string name="diagnose_exf_mau">Annoy user after manipulation</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue