mirror of
https://codeberg.org/timelimit/timelimit-android.git
synced 2025-10-05 19:42:20 +02:00
Allow disabling locking with the device owner permission
This commit is contained in:
parent
24710aa21e
commit
3fbf598eb5
10 changed files with 250 additions and 11 deletions
|
@ -223,4 +223,39 @@ abstract class ConfigDao {
|
|||
|
||||
fun getEnableAlternativeDurationSelectionAsync() = getValueOfKeyAsync(ConfigurationItemType.EnableAlternativeDurationSelection).map { it == "1" }
|
||||
fun setEnableAlternativeDurationSelectionSync(enable: Boolean) = updateValueSync(ConfigurationItemType.EnableAlternativeDurationSelection, if (enable) "1" else "0")
|
||||
fun getExperimentalFlagsLive(): LiveData<Long> {
|
||||
return getValueOfKeyAsync(ConfigurationItemType.ExperimentalFlags).map {
|
||||
if (it == null) {
|
||||
0
|
||||
} else {
|
||||
it.toLong(16)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getExperimentalFlagsSync(): Long {
|
||||
val v = getValueOfKeySync(ConfigurationItemType.ExperimentalFlags)
|
||||
|
||||
if (v == null) {
|
||||
return 0
|
||||
} else {
|
||||
return v.toLong(16)
|
||||
}
|
||||
}
|
||||
|
||||
fun isExperimentalFlagsSetAsync(flags: Long) = getExperimentalFlagsLive().map {
|
||||
(it and flags) == flags
|
||||
}.ignoreUnchanged()
|
||||
|
||||
fun isExperimentalFlagsSetSync(flags: Long) = (getExperimentalFlagsSync() and flags) == flags
|
||||
|
||||
fun setExperimentalFlag(flags: Long, enable: Boolean) {
|
||||
updateValueSync(
|
||||
ConfigurationItemType.ExperimentalFlags,
|
||||
if (enable)
|
||||
(getShownHintsSync() or flags).toString(16)
|
||||
else
|
||||
(getShownHintsSync() and (flags.inv())).toString(16)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -91,7 +91,8 @@ enum class ConfigurationItemType {
|
|||
CustomServerUrl,
|
||||
ForegroundAppQueryRange,
|
||||
EnableBackgroundSync,
|
||||
EnableAlternativeDurationSelection
|
||||
EnableAlternativeDurationSelection,
|
||||
ExperimentalFlags
|
||||
}
|
||||
|
||||
object ConfigurationItemTypeUtil {
|
||||
|
@ -110,6 +111,7 @@ object ConfigurationItemTypeUtil {
|
|||
private const val FOREGROUND_APP_QUERY_RANGE = 14
|
||||
private const val ENABLE_BACKGROUND_SYNC = 15
|
||||
private const val ENABLE_ALTERNATIVE_DURATION_SELECTION = 16
|
||||
private const val EXPERIMENTAL_FLAGS = 17
|
||||
|
||||
val TYPES = listOf(
|
||||
ConfigurationItemType.OwnDeviceId,
|
||||
|
@ -126,7 +128,8 @@ object ConfigurationItemTypeUtil {
|
|||
ConfigurationItemType.CustomServerUrl,
|
||||
ConfigurationItemType.ForegroundAppQueryRange,
|
||||
ConfigurationItemType.EnableBackgroundSync,
|
||||
ConfigurationItemType.EnableAlternativeDurationSelection
|
||||
ConfigurationItemType.EnableAlternativeDurationSelection,
|
||||
ConfigurationItemType.ExperimentalFlags
|
||||
)
|
||||
|
||||
fun serialize(value: ConfigurationItemType) = when(value) {
|
||||
|
@ -145,6 +148,7 @@ object ConfigurationItemTypeUtil {
|
|||
ConfigurationItemType.ForegroundAppQueryRange -> FOREGROUND_APP_QUERY_RANGE
|
||||
ConfigurationItemType.EnableBackgroundSync -> ENABLE_BACKGROUND_SYNC
|
||||
ConfigurationItemType.EnableAlternativeDurationSelection -> ENABLE_ALTERNATIVE_DURATION_SELECTION
|
||||
ConfigurationItemType.ExperimentalFlags -> EXPERIMENTAL_FLAGS
|
||||
}
|
||||
|
||||
fun parse(value: Int) = when(value) {
|
||||
|
@ -163,6 +167,7 @@ object ConfigurationItemTypeUtil {
|
|||
FOREGROUND_APP_QUERY_RANGE -> ConfigurationItemType.ForegroundAppQueryRange
|
||||
ENABLE_BACKGROUND_SYNC -> ConfigurationItemType.EnableBackgroundSync
|
||||
ENABLE_ALTERNATIVE_DURATION_SELECTION -> ConfigurationItemType.EnableAlternativeDurationSelection
|
||||
EXPERIMENTAL_FLAGS -> ConfigurationItemType.ExperimentalFlags
|
||||
else -> throw IllegalArgumentException()
|
||||
}
|
||||
}
|
||||
|
@ -183,3 +188,7 @@ object HintsToShow {
|
|||
const val CONTACTS_INTRO = 16L
|
||||
const val TIMELIMIT_RULE_MUSTREAD = 32L
|
||||
}
|
||||
|
||||
object ExperimentalFlags {
|
||||
const val DISABLE_BLOCK_ON_MANIPULATION = 1L
|
||||
}
|
|
@ -20,6 +20,7 @@ import android.os.Build
|
|||
import io.timelimit.android.async.Threads
|
||||
import io.timelimit.android.coroutines.executeAndWait
|
||||
import io.timelimit.android.coroutines.runAsync
|
||||
import io.timelimit.android.data.model.ExperimentalFlags
|
||||
import io.timelimit.android.data.transaction
|
||||
import io.timelimit.android.ui.MainActivity
|
||||
import io.timelimit.android.ui.manipulation.UnlockAfterManipulationActivity
|
||||
|
@ -40,17 +41,19 @@ class ManipulationLogic(val appLogic: AppLogic) {
|
|||
}
|
||||
|
||||
fun lockDeviceSync() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
if (appLogic.platformIntegration.setLockTaskPackages(listOf(appLogic.context.packageName))) {
|
||||
appLogic.database.config().setWasDeviceLockedSync(true)
|
||||
if (!appLogic.database.config().isExperimentalFlagsSetSync(ExperimentalFlags.DISABLE_BLOCK_ON_MANIPULATION)) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
if (appLogic.platformIntegration.setLockTaskPackages(listOf(appLogic.context.packageName))) {
|
||||
appLogic.database.config().setWasDeviceLockedSync(true)
|
||||
|
||||
showManipulationScreen()
|
||||
}
|
||||
} else {
|
||||
if (lockDeviceSync("12timelimit34")) {
|
||||
appLogic.database.config().setWasDeviceLockedSync(true)
|
||||
showManipulationScreen()
|
||||
}
|
||||
} else {
|
||||
if (lockDeviceSync("12timelimit34")) {
|
||||
appLogic.database.config().setWasDeviceLockedSync(true)
|
||||
|
||||
showManipulationScreen()
|
||||
showManipulationScreen()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,102 @@
|
|||
/*
|
||||
* 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.diagnose
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.fragment.app.Fragment
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.CheckBox
|
||||
import androidx.lifecycle.Observer
|
||||
import io.timelimit.android.BuildConfig
|
||||
import io.timelimit.android.R
|
||||
import io.timelimit.android.async.Threads
|
||||
import io.timelimit.android.data.model.ExperimentalFlags
|
||||
import io.timelimit.android.databinding.DiagnoseExperimentalFlagFragmentBinding
|
||||
import io.timelimit.android.livedata.liveDataFromValue
|
||||
import io.timelimit.android.logic.DefaultAppLogic
|
||||
import io.timelimit.android.ui.main.ActivityViewModelHolder
|
||||
import io.timelimit.android.ui.main.AuthenticationFab
|
||||
|
||||
class DiagnoseExperimentalFlagFragment : Fragment() {
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
val activity: ActivityViewModelHolder = activity as ActivityViewModelHolder
|
||||
val database = DefaultAppLogic.with(context!!).database
|
||||
val auth = activity.getActivityViewModel()
|
||||
|
||||
val binding = DiagnoseExperimentalFlagFragmentBinding.inflate(inflater, container, false)
|
||||
|
||||
AuthenticationFab.manageAuthenticationFab(
|
||||
fab = binding.fab,
|
||||
shouldHighlight = auth.shouldHighlightAuthenticationButton,
|
||||
authenticatedUser = auth.authenticatedUser,
|
||||
doesSupportAuth = liveDataFromValue(true),
|
||||
fragment = this
|
||||
)
|
||||
|
||||
binding.fab.setOnClickListener { activity.showAuthenticationScreen() }
|
||||
|
||||
val flags = DiagnoseExperimentalFlagItem.items
|
||||
val checkboxes = flags.map {
|
||||
CheckBox(context).apply {
|
||||
setText(it.label)
|
||||
isEnabled = it.enable
|
||||
}
|
||||
}
|
||||
|
||||
checkboxes.forEach { binding.container.addView(it) }
|
||||
|
||||
database.config().getExperimentalFlagsLive().observe(this, Observer { setFlags ->
|
||||
flags.forEachIndexed { index, flag ->
|
||||
val checkbox = checkboxes[index]
|
||||
val isFlagSet = (setFlags and flag.flag) == flag.flag
|
||||
|
||||
checkbox.setOnCheckedChangeListener { _, _ -> }
|
||||
checkbox.isChecked = isFlagSet
|
||||
checkbox.setOnCheckedChangeListener { _, didCheck ->
|
||||
if (didCheck != isFlagSet) {
|
||||
if (auth.requestAuthenticationOrReturnTrue()) {
|
||||
Threads.database.execute {
|
||||
database.config().setExperimentalFlag(flag.flag, didCheck)
|
||||
}
|
||||
} else {
|
||||
checkbox.isChecked = isFlagSet
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
return binding.root
|
||||
}
|
||||
}
|
||||
|
||||
data class DiagnoseExperimentalFlagItem(
|
||||
val label: Int,
|
||||
val flag: Long,
|
||||
val enable: Boolean
|
||||
) {
|
||||
companion object {
|
||||
val items = listOf(
|
||||
DiagnoseExperimentalFlagItem(
|
||||
label = R.string.diagnose_exf_lom,
|
||||
flag = ExperimentalFlags.DISABLE_BLOCK_ON_MANIPULATION,
|
||||
enable = !BuildConfig.storeCompilant
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
|
@ -58,6 +58,13 @@ class DiagnoseMainFragment : Fragment() {
|
|||
)
|
||||
}
|
||||
|
||||
binding.diagnoseExfButton.setOnClickListener {
|
||||
navigation.safeNavigate(
|
||||
DiagnoseMainFragmentDirections.actionDiagnoseMainFragmentToDiagnoseExperimentalFlagFragment(),
|
||||
R.id.diagnoseMainFragment
|
||||
)
|
||||
}
|
||||
|
||||
return binding.root
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
<!--
|
||||
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/>.
|
||||
-->
|
||||
<layout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
tools:context="io.timelimit.android.ui.diagnose.DiagnoseExperimentalFlagFragment">
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<ScrollView
|
||||
android:id="@+id/scroll"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
<androidx.cardview.widget.CardView
|
||||
android:layout_margin="8dp"
|
||||
app:cardUseCompatPadding="true"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
<LinearLayout
|
||||
android:id="@+id/container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="8dp">
|
||||
|
||||
<TextView
|
||||
android:textAppearance="?android:textAppearanceLarge"
|
||||
android:text="@string/diagnose_exf_title"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
</LinearLayout>
|
||||
</androidx.cardview.widget.CardView>
|
||||
</ScrollView>
|
||||
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/fab"
|
||||
app:fabSize="normal"
|
||||
android:src="@drawable/ic_lock_open_white_24dp"
|
||||
android:layout_margin="16dp"
|
||||
android:layout_gravity="end|bottom"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
</layout>
|
|
@ -50,6 +50,12 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/diagnose_exf_button"
|
||||
android:text="@string/diagnose_exf_title"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
|
||||
|
|
|
@ -332,6 +332,13 @@
|
|||
app:exitAnim="@anim/nav_default_exit_anim"
|
||||
app:popEnterAnim="@anim/nav_default_pop_enter_anim"
|
||||
app:popExitAnim="@anim/nav_default_pop_exit_anim" />
|
||||
<action
|
||||
android:id="@+id/action_diagnoseMainFragment_to_diagnoseExperimentalFlagFragment"
|
||||
app:destination="@id/diagnoseExperimentalFlagFragment"
|
||||
app:enterAnim="@anim/nav_default_enter_anim"
|
||||
app:exitAnim="@anim/nav_default_exit_anim"
|
||||
app:popEnterAnim="@anim/nav_default_pop_enter_anim"
|
||||
app:popExitAnim="@anim/nav_default_pop_exit_anim" />
|
||||
</fragment>
|
||||
<fragment
|
||||
android:id="@+id/diagnoseClockFragment"
|
||||
|
@ -403,4 +410,9 @@
|
|||
android:name="parentUserId"
|
||||
app:argType="string" />
|
||||
</fragment>
|
||||
<fragment
|
||||
android:id="@+id/diagnoseExperimentalFlagFragment"
|
||||
android:name="io.timelimit.android.ui.diagnose.DiagnoseExperimentalFlagFragment"
|
||||
android:label="diagnose_experimental_flag_fragment"
|
||||
tools:layout="@layout/diagnose_experimental_flag_fragment" />
|
||||
</navigation>
|
||||
|
|
|
@ -51,4 +51,7 @@
|
|||
<string name="diagnose_fga_title">Erkennung der aktiven App</string>
|
||||
<string name="diagnose_fga_query_range">Abfragezeitraum</string>
|
||||
<string name="diagnose_fga_query_range_min">Minimal (Standard)</string>
|
||||
|
||||
<string name="diagnose_exf_title">Experimentelle Parameter</string>
|
||||
<string name="diagnose_exf_lom">Sperrung nach Manipulationen deaktivieren</string>
|
||||
</resources>
|
||||
|
|
|
@ -51,4 +51,7 @@
|
|||
<string name="diagnose_fga_title">Foreground-App-Detection</string>
|
||||
<string name="diagnose_fga_query_range">Requested time range</string>
|
||||
<string name="diagnose_fga_query_range_min">Minimum (Default)</string>
|
||||
|
||||
<string name="diagnose_exf_title">Experimental flags</string>
|
||||
<string name="diagnose_exf_lom">Disable locking after manipulations</string>
|
||||
</resources>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue