Use new permission GUI after the setup

This commit is contained in:
Jonas Lochmann 2023-04-03 02:00:00 +02:00
parent 9d403f38f2
commit bd2942c6b7
No known key found for this signature in database
GPG key ID: 8B8C9AEE10FA5B36
16 changed files with 173 additions and 724 deletions

View file

@ -19,6 +19,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.fragment.app.FragmentManager
import io.timelimit.android.ui.diagnose.deviceowner.DeviceOwnerScreen
import io.timelimit.android.ui.manage.device.manage.permission.ManageDevicePermissionScreen
import io.timelimit.android.ui.manage.device.manage.user.ManageDeviceUserScreen
import io.timelimit.android.ui.model.Screen
import io.timelimit.android.ui.overview.overview.OverviewScreen
@ -38,5 +39,6 @@ fun ScreenMultiplexer(
is Screen.ManageDeviceUserScreen -> ManageDeviceUserScreen(screen.items, screen.actions, screen.overlay, modifier)
is Screen.DeviceOwnerScreen -> DeviceOwnerScreen(screen.content, modifier = modifier)
is Screen.SetupDevicePermissionsScreen -> SetupDevicePermissionsScreen(screen.content, screen.next, modifier)
is Screen.ManageDevicePermissions -> ManageDevicePermissionScreen(screen.content, modifier)
}
}

View file

@ -0,0 +1,36 @@
/*
* TimeLimit Copyright <C> 2019 - 2023 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.manage.device.manage.permission
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
@Composable
fun ManageDevicePermissionScreen(
content: PermissionScreenContent,
modifier: Modifier = Modifier
) {
PermissionScreen(
content,
modifier
.verticalScroll(rememberScrollState())
.padding(8.dp)
)
}

View file

@ -16,35 +16,13 @@
package io.timelimit.android.ui.manage.device.manage.permission
import android.content.Context
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.lifecycle.LiveData
import androidx.lifecycle.Observer
import androidx.lifecycle.map
import io.timelimit.android.R
import io.timelimit.android.data.model.Device
import io.timelimit.android.data.model.UserType
import io.timelimit.android.databinding.ManageDevicePermissionsFragmentBinding
import io.timelimit.android.integration.platform.NewPermissionStatus
import io.timelimit.android.integration.platform.ProtectionLevel
import io.timelimit.android.integration.platform.RuntimePermissionStatus
import io.timelimit.android.integration.platform.SystemPermission
import io.timelimit.android.livedata.ignoreUnchanged
import io.timelimit.android.livedata.liveDataFromNonNullValue
import io.timelimit.android.logic.AppLogic
import io.timelimit.android.logic.DefaultAppLogic
import io.timelimit.android.ui.main.ActivityViewModel
import io.timelimit.android.ui.main.ActivityViewModelHolder
import io.timelimit.android.ui.main.AuthenticationFab
import io.timelimit.android.ui.main.FragmentWithCustomTitle
import io.timelimit.android.ui.model.UpdateStateCommand
import io.timelimit.android.ui.model.execute
class ManageDevicePermissionsFragment : Fragment(), FragmentWithCustomTitle {
companion object {
object ManageDevicePermissionsFragment {
fun getPreviewText(device: Device, context: Context): String {
val permissionLabels = mutableListOf<String>()
@ -74,144 +52,4 @@ class ManageDevicePermissionsFragment : Fragment(), FragmentWithCustomTitle {
permissionLabels.joinToString(", ")
}
}
}
private val activity: ActivityViewModelHolder by lazy { getActivity() as ActivityViewModelHolder }
private val logic: AppLogic by lazy { DefaultAppLogic.with(requireContext()) }
private val auth: ActivityViewModel by lazy { activity.getActivityViewModel() }
private val args: ManageDevicePermissionsFragmentArgs by lazy { ManageDevicePermissionsFragmentArgs.fromBundle(requireArguments()) }
private val deviceEntry: LiveData<Device?> by lazy {
logic.database.device().getDeviceById(args.deviceId)
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val binding = ManageDevicePermissionsFragmentBinding.inflate(inflater, container, false)
// auth
AuthenticationFab.manageAuthenticationFab(
fab = binding.fab,
shouldHighlight = auth.shouldHighlightAuthenticationButton,
authenticatedUser = auth.authenticatedUser,
fragment = this,
doesSupportAuth = liveDataFromNonNullValue(true)
)
auth.authenticatedUser.map { it?.second?.type == UserType.Parent }.observe(this, Observer {
binding.isUserSignedIn = it
})
// handlers
binding.handlers = object: ManageDevicePermissionsFragmentHandlers {
override fun openUsageStatsSettings() {
if (binding.isThisDevice == true) {
logic.platformIntegration.openSystemPermissionScren(
requireActivity(),
SystemPermission.UsageStats
)
}
}
override fun openNotificationAccessSettings() {
if (binding.isThisDevice == true) {
logic.platformIntegration.openSystemPermissionScren(
requireActivity(),
SystemPermission.Notification
)
}
}
override fun openDrawOverOtherAppsScreen() {
if (binding.isThisDevice == true) {
logic.platformIntegration.openSystemPermissionScren(
requireActivity(),
SystemPermission.Overlay
)
}
}
override fun openAccessibilitySettings() {
if (binding.isThisDevice == true) {
logic.platformIntegration.openSystemPermissionScren(
requireActivity(),
SystemPermission.AccessibilityService
)
}
}
override fun manageDeviceAdmin() {
if (binding.isThisDevice == true) {
logic.platformIntegration.openSystemPermissionScren(
requireActivity(),
SystemPermission.DeviceAdmin
)
}
}
override fun showAuthenticationScreen() {
activity.showAuthenticationScreen()
}
override fun helpUsageStatsAccess() {
PermissionInfoHelpDialog.show(requireActivity(), SystemPermission.UsageStats)
}
override fun helpNotificationAccess() {
PermissionInfoHelpDialog.show(requireActivity(), SystemPermission.Notification)
}
override fun helpDrawOverOtherApps() {
PermissionInfoHelpDialog.show(requireActivity(), SystemPermission.Overlay)
}
override fun helpAccesibility() {
PermissionInfoHelpDialog.show(requireActivity(), SystemPermission.AccessibilityService)
}
}
// is this device
val isThisDevice = logic.deviceId.map { ownDeviceId -> ownDeviceId == args.deviceId }.ignoreUnchanged()
isThisDevice.observe(this, Observer {
binding.isThisDevice = it
})
// permissions
deviceEntry.observe(this, Observer {
device ->
if (device == null) {
requireActivity().execute(UpdateStateCommand.ManageDevice.Leave)
} else {
binding.usageStatsAccess = device.currentUsageStatsPermission
binding.notificationAccessPermission = device.currentNotificationAccessPermission
binding.protectionLevel = device.currentProtectionLevel
binding.overlayPermission = device.currentOverlayPermission
binding.accessibilityServiceEnabled = device.accessibilityServiceEnabled
}
})
return binding.root
}
override fun onResume() {
super.onResume()
logic.backgroundTaskLogic.syncDeviceStatusAsync()
}
override fun getCustomTitle(): LiveData<String?> = deviceEntry.map { "${getString(R.string.manage_device_card_permission_title)} < ${it?.name} < ${getString(R.string.main_tab_overview)}" }
}
interface ManageDevicePermissionsFragmentHandlers {
fun openUsageStatsSettings()
fun openNotificationAccessSettings()
fun openDrawOverOtherAppsScreen()
fun openAccessibilitySettings()
fun manageDeviceAdmin()
fun showAuthenticationScreen()
fun helpUsageStatsAccess()
fun helpNotificationAccess()
fun helpDrawOverOtherApps()
fun helpAccesibility()
}

View file

@ -84,7 +84,9 @@ fun PermissionGoals(status: PermissionScreenContent.Status) {
status.protectionLevel == ProtectionLevel.DeviceOwner
) {
Text(stringResource(
if (status.maxProtectionLevel == ProtectionLevel.DeviceOwner)
if (status.maxProtectionLevel == null)
R.string.manage_device_permission_goal_manipulation_protection_check_remotely
else if (status.maxProtectionLevel == ProtectionLevel.DeviceOwner)
R.string.manage_device_permission_goal_needs_device_owner
else
R.string.manage_device_permission_goal_manipulation_protection_unavailable

View file

@ -18,14 +18,17 @@ package io.timelimit.android.ui.manage.device.manage.permission
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
@Composable
fun PermissionScreen(
content: PermissionScreenContent
content: PermissionScreenContent,
modifier: Modifier = Modifier
) {
Column (
verticalArrangement = Arrangement.spacedBy(8.dp)
verticalArrangement = Arrangement.spacedBy(8.dp),
modifier = modifier
) {
PermissionScreenPermissionList(content.status, content.showDetails)
PermissionGoals(content.status)

View file

@ -28,7 +28,7 @@ data class PermissionScreenContent(
data class Status(
val notificationAccess: NewPermissionStatus,
val protectionLevel: ProtectionLevel,
val maxProtectionLevel: ProtectionLevel,
val maxProtectionLevel: ProtectionLevel?,
val usageStats: RuntimePermissionStatus,
val overlay: RuntimePermissionStatus,
val accessibility: Boolean,

View file

@ -59,7 +59,7 @@ fun PermissionScreenDialog(
if (dialog.permission == SystemPermission.DeviceAdmin) {
val message =
if (status.maxProtectionLevel != ProtectionLevel.DeviceOwner) R.string.manage_device_permission_device_owner_unsupported
if (status.maxProtectionLevel != ProtectionLevel.DeviceOwner && status.maxProtectionLevel != null) R.string.manage_device_permission_device_owner_unsupported
else if (status.protectionLevel != ProtectionLevel.DeviceOwner) R.string.manage_device_permission_device_owner_not_granted
else null

View file

@ -178,12 +178,9 @@ sealed class Screen(
class ManageDevicePermissions(
state: State,
toolbarIcons: List<Menu.Icon>,
toolbarOptions: List<Menu.Dropdown>,
fragment: FragmentState,
containerId: Int,
val content: PermissionScreenContent,
override val backStack: List<BackStackItem>
): FragmentScreen(state, toolbarIcons, toolbarOptions, fragment, containerId), ScreenWithBackStack, ScreenWithTitle {
): Screen(state), ScreenWithBackStack, ScreenWithTitle {
override val title = Title.StringResource(R.string.manage_device_card_permission_title)
}

View file

@ -36,8 +36,6 @@ import io.timelimit.android.ui.manage.device.manage.advanced.ManageDeviceAdvance
import io.timelimit.android.ui.manage.device.manage.advanced.ManageDeviceAdvancedFragmentArgs
import io.timelimit.android.ui.manage.device.manage.feature.ManageDeviceFeaturesFragment
import io.timelimit.android.ui.manage.device.manage.feature.ManageDeviceFeaturesFragmentArgs
import io.timelimit.android.ui.manage.device.manage.permission.ManageDevicePermissionsFragment
import io.timelimit.android.ui.manage.device.manage.permission.ManageDevicePermissionsFragmentArgs
import io.timelimit.android.ui.manage.parent.ManageParentFragment
import io.timelimit.android.ui.manage.parent.ManageParentFragmentArgs
import io.timelimit.android.ui.manage.parent.link.LinkParentMailFragment
@ -229,9 +227,7 @@ sealed class State (val previous: State?): Serializable {
object AdjustDefaultUserTimeout: Overlay()
}
}
class Permissions(previousMain: Main): Sub(previousMain, ManageDevicePermissionsFragment::class.java) {
override val arguments: Bundle get() = ManageDevicePermissionsFragmentArgs(deviceId).toBundle()
}
data class Permissions(val previousMain: Main, val currentDialog: SystemPermission? = null): Sub(previousMain, Fragment::class.java)
class Features(previousMain: Main): Sub(previousMain, ManageDeviceFeaturesFragment::class.java) {
override val arguments: Bundle get() = ManageDeviceFeaturesFragmentArgs(deviceId).toBundle()
}

View file

@ -118,11 +118,15 @@ object ManageDeviceHandling {
updateMethod(updateState)
)
},
Case.simple<_, _, State.ManageDevice.Permissions> {
processPermissionsState(
it,
Case.simple<_, _, State.ManageDevice.Permissions> {state ->
ManageDevicePermissions.processState(
scope,
logic,
activityCommand,
state,
subBackStackLive,
deviceLive
deviceLive,
updateMethod(updateState)
)
},
Case.simple<_, _, State.ManageDevice.Features> {
@ -142,21 +146,6 @@ object ManageDeviceHandling {
)
}
private fun processPermissionsState(
stateLive: Flow<State.ManageDevice.Permissions>,
parentBackStackLive: Flow<List<BackStackItem>>,
deviceLive: Flow<Device>
): Flow<Screen> = combine(stateLive, deviceLive, parentBackStackLive) { state, device, backStack ->
Screen.ManageDevicePermissions(
state,
state.toolbarIcons,
state.toolbarOptions,
state,
R.id.fragment_manage_device_permissions,
backStack
)
}
private fun processFeaturesState(
stateLive: Flow<State.ManageDevice.Features>,
parentBackStackLive: Flow<List<BackStackItem>>,

View file

@ -0,0 +1,88 @@
/*
* TimeLimit Copyright <C> 2019 - 2023 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.model.managedevice
import io.timelimit.android.data.model.Device
import io.timelimit.android.logic.AppLogic
import io.timelimit.android.ui.manage.device.manage.permission.PermissionScreenContent
import io.timelimit.android.ui.model.ActivityCommand
import io.timelimit.android.ui.model.BackStackItem
import io.timelimit.android.ui.model.Screen
import io.timelimit.android.ui.model.State
import io.timelimit.android.ui.model.setup.SetupLocalModePermissions
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.channels.SendChannel
import kotlinx.coroutines.flow.*
object ManageDevicePermissions {
fun processState(
scope: CoroutineScope,
logic: AppLogic,
activityCommand: SendChannel<ActivityCommand>,
stateLive: Flow<State.ManageDevice.Permissions>,
parentBackStackLive: Flow<List<BackStackItem>>,
deviceLive: SharedFlow<Device>,
updateState: ((State.ManageDevice.Permissions) -> State) -> Unit
): Flow<Screen> {
val isCurrentDeviceLive = isCurrentDevice(logic, deviceLive).shareIn(scope, SharingStarted.Lazily, 1)
val deviceStatusLive = isCurrentDeviceLive.transformLatest { isCurrentDevice ->
if (isCurrentDevice) emitAll(SetupLocalModePermissions.deviceStatus(logic.platformIntegration))
else emitAll(statusFromDevice(deviceLive))
}
return combine(
stateLive, deviceStatusLive, isCurrentDeviceLive, parentBackStackLive
) { state, deviceStatus, isCurrentDevice, parentBackStack ->
Screen.ManageDevicePermissions(
state,
PermissionScreenContent(
status = deviceStatus,
dialog = state.currentDialog?.let { dialog ->
PermissionScreenContent.Dialog(
permission = dialog,
launchSystemSettings = if (isCurrentDevice) ({
activityCommand.trySend(ActivityCommand.LaunchSystemSettings(dialog))
updateState { it.copy(currentDialog = null) }
}) else null,
close = { updateState { it.copy(currentDialog = null) } }
)
},
showDetails = { permission -> updateState { it.copy(currentDialog = permission) } }
),
parentBackStack
)
}
}
private fun isCurrentDevice(logic: AppLogic, deviceLive: Flow<Device>): Flow<Boolean> {
val ownDeviceIdLive = logic.database.config().getOwnDeviceIdFlow()
return combine(ownDeviceIdLive, deviceLive) { deviceId, device -> device.id == deviceId }
}
private fun statusFromDevice(deviceLive: Flow<Device>): Flow<PermissionScreenContent.Status> = deviceLive.map { device ->
PermissionScreenContent.Status(
notificationAccess = device.currentNotificationAccessPermission,
protectionLevel = device.currentProtectionLevel,
maxProtectionLevel = null,
usageStats = device.currentUsageStatsPermission,
overlay = device.currentOverlayPermission,
accessibility = device.accessibilityServiceEnabled,
isQOrLater = device.qOrLater
)
}.distinctUntilChanged()
}

View file

@ -60,7 +60,7 @@ object SetupLocalModePermissions {
}
}
private fun deviceStatus(platformIntegration: PlatformIntegration): Flow<PermissionScreenContent.Status> = flow {
fun deviceStatus(platformIntegration: PlatformIntegration): Flow<PermissionScreenContent.Status> = flow {
while (true) {
emit(
PermissionScreenContent.Status(

View file

@ -1,471 +0,0 @@
<!--
TimeLimit Copyright <C> 2019 - 2020 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.manage.device.manage.permission.ManageDevicePermissionsFragment">
<data>
<variable
name="isThisDevice"
type="Boolean" />
<variable
name="usageStatsAccess"
type="io.timelimit.android.integration.platform.RuntimePermissionStatus" />
<variable
name="notificationAccessPermission"
type="io.timelimit.android.integration.platform.NewPermissionStatus" />
<variable
name="protectionLevel"
type="io.timelimit.android.integration.platform.ProtectionLevel" />
<variable
name="overlayPermission"
type="RuntimePermissionStatus" />
<variable
name="accessibilityServiceEnabled"
type="boolean" />
<variable
name="handlers"
type="io.timelimit.android.ui.manage.device.manage.permission.ManageDevicePermissionsFragmentHandlers" />
<variable
name="isUserSignedIn"
type="boolean" />
<import type="android.view.View" />
<import type="io.timelimit.android.data.model.NetworkTime" />
<import type="io.timelimit.android.integration.platform.RuntimePermissionStatus" />
<import type="io.timelimit.android.integration.platform.NewPermissionStatus" />
<import type="io.timelimit.android.integration.platform.ProtectionLevel" />
<import type="io.timelimit.android.BuildConfig" />
</data>
<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">
<LinearLayout
android:padding="8dp"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:text="@string/setup_device_permissions_text"
android:textAppearance="?android:textAppearanceMedium"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<androidx.cardview.widget.CardView
app:cardUseCompatPadding="true"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:orientation="vertical"
android:padding="8dp"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:textAppearance="?android:textAppearanceLarge"
android:text="@string/manage_device_permission_device_admin_title"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<TextView
android:visibility="@{protectionLevel == ProtectionLevel.None ? View.VISIBLE : View.GONE}"
android:textAppearance="?android:textAppearanceMedium"
android:text="@string/manage_device_permission_device_admin_text_disabled"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<TextView
android:visibility="@{protectionLevel == ProtectionLevel.SimpleDeviceAdmin ? View.VISIBLE : View.GONE}"
android:textAppearance="?android:textAppearanceMedium"
android:text="@string/manage_device_permission_device_admin_text_simple"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<TextView
android:visibility="@{protectionLevel == ProtectionLevel.PasswordDeviceAdmin ? View.VISIBLE : View.GONE}"
android:textAppearance="?android:textAppearanceMedium"
android:text="@string/manage_device_permission_device_admin_text_password"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<TextView
android:visibility="@{protectionLevel == ProtectionLevel.DeviceOwner ? View.VISIBLE : View.GONE}"
android:textAppearance="?android:textAppearanceMedium"
android:text="@string/manage_device_permission_device_admin_text_owner"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<Button
android:id="@+id/device_admin_btn"
android:nextFocusDown="@id/usage_stats_access_title"
style="?materialButtonOutlinedStyle"
android:layout_marginEnd="8dp"
android:layout_marginTop="8dp"
android:text="@string/manage_device_permission_btn_modify"
android:layout_gravity="end"
android:enabled="@{safeUnbox(isThisDevice)}"
android:onClick="@{() -> handlers.manageDeviceAdmin()}"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<requestFocus />
</Button>
<TextView
android:visibility="@{safeUnbox(isThisDevice) ? View.GONE : View.VISIBLE}"
android:text="@string/manage_device_permission_open_at_target_device"
android:textAppearance="?android:textAppearanceSmall"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
</androidx.cardview.widget.CardView>
<androidx.cardview.widget.CardView
app:cardUseCompatPadding="true"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:orientation="vertical"
android:padding="8dp"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/usage_stats_access_title"
android:nextFocusUp="@id/device_admin_btn"
android:nextFocusDown="@id/usage_stats_access_btn"
tools:ignore="UnusedAttribute"
android:drawableTint="?colorOnSurface"
android:background="?selectableItemBackground"
android:drawableEnd="@drawable/ic_info_outline_black_24dp"
android:onClick="@{() -> handlers.helpUsageStatsAccess()}"
android:textAppearance="?android:textAppearanceLarge"
android:text="@string/manage_device_permissions_usagestats_title"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<TextView
android:paddingTop="8dp"
android:gravity="center_horizontal"
android:visibility="@{usageStatsAccess == RuntimePermissionStatus.Granted ? View.VISIBLE : View.GONE}"
android:textColor="@color/text_green"
android:textAppearance="?android:textAppearanceMedium"
android:text="@string/manage_device_permission_status_granted"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<TextView
android:paddingTop="8dp"
android:gravity="center_horizontal"
android:visibility="@{usageStatsAccess == RuntimePermissionStatus.NotGranted ? View.VISIBLE : View.GONE}"
android:textColor="@color/text_red"
android:textAppearance="?android:textAppearanceMedium"
android:text="@string/manage_device_permission_status_not_granted"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<TextView
android:paddingTop="8dp"
android:gravity="center_horizontal"
android:visibility="@{usageStatsAccess == RuntimePermissionStatus.NotRequired ? View.VISIBLE : View.GONE}"
android:textColor="@color/text_green"
android:textAppearance="?android:textAppearanceMedium"
android:text="@string/manage_device_permission_status_not_required"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<Button
android:id="@+id/usage_stats_access_btn"
android:nextFocusUp="@id/usage_stats_access_title"
android:nextFocusDown="@id/notification_access_title"
style="?materialButtonOutlinedStyle"
android:layout_marginEnd="8dp"
android:layout_marginTop="8dp"
android:text="@string/manage_device_permission_btn_modify"
android:layout_gravity="end"
android:onClick="@{() -> handlers.openUsageStatsSettings()}"
android:enabled="@{safeUnbox(isThisDevice) &amp;&amp; (usageStatsAccess != RuntimePermissionStatus.NotRequired)}"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:visibility="@{((safeUnbox(isThisDevice) || (usageStatsAccess == RuntimePermissionStatus.NotRequired))) ? View.GONE : View.VISIBLE}"
android:text="@string/manage_device_permission_open_at_target_device"
android:textAppearance="?android:textAppearanceSmall"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
</androidx.cardview.widget.CardView>
<androidx.cardview.widget.CardView
app:cardUseCompatPadding="true"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:orientation="vertical"
android:padding="8dp"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/notification_access_title"
android:nextFocusUp="@id/usage_stats_access_btn"
android:nextFocusDown="@id/notification_access_button"
tools:ignore="UnusedAttribute"
android:drawableTint="?colorOnSurface"
android:background="?selectableItemBackground"
android:drawableEnd="@drawable/ic_info_outline_black_24dp"
android:onClick="@{() -> handlers.helpNotificationAccess()}"
android:textAppearance="?android:textAppearanceLarge"
android:text="@string/manage_device_permission_notification_access_title"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<TextView
android:paddingTop="8dp"
android:gravity="center_horizontal"
android:visibility="@{notificationAccessPermission == NewPermissionStatus.Granted ? View.VISIBLE : View.GONE}"
android:textColor="@color/text_green"
android:textAppearance="?android:textAppearanceMedium"
android:text="@string/manage_device_permission_status_granted"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<TextView
android:paddingTop="8dp"
android:gravity="center_horizontal"
android:visibility="@{notificationAccessPermission == NewPermissionStatus.NotGranted ? View.VISIBLE : View.GONE}"
android:textColor="@color/text_red"
android:textAppearance="?android:textAppearanceMedium"
android:text="@string/manage_device_permission_status_not_granted"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<TextView
android:paddingTop="8dp"
android:gravity="center_horizontal"
android:visibility="@{notificationAccessPermission == NewPermissionStatus.NotSupported ? View.VISIBLE : View.GONE}"
android:textColor="@color/text_red"
android:textAppearance="?android:textAppearanceMedium"
android:text="@string/manage_device_permission_status_not_supported"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<Button
android:id="@+id/notification_access_button"
android:nextFocusUp="@id/notification_access_title"
android:nextFocusDown="@id/overlay_title"
style="?materialButtonOutlinedStyle"
android:layout_marginEnd="8dp"
android:layout_marginTop="8dp"
android:text="@string/manage_device_permission_btn_modify"
android:layout_gravity="end"
android:onClick="@{() -> handlers.openNotificationAccessSettings()}"
android:enabled="@{safeUnbox(isThisDevice) &amp;&amp; (notificationAccessPermission != NewPermissionStatus.NotSupported)}"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:visibility="@{((safeUnbox(isThisDevice) || (notificationAccessPermission == NewPermissionStatus.NotSupported))) ? View.GONE : View.VISIBLE}"
android:text="@string/manage_device_permission_open_at_target_device"
android:textAppearance="?android:textAppearanceSmall"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
</androidx.cardview.widget.CardView>
<androidx.cardview.widget.CardView
app:cardUseCompatPadding="true"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:orientation="vertical"
android:padding="8dp"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/overlay_title"
android:nextFocusUp="@id/notification_access_button"
android:nextFocusDown="@id/overlay_btn"
tools:ignore="UnusedAttribute"
android:drawableTint="?colorOnSurface"
android:background="?selectableItemBackground"
android:drawableEnd="@drawable/ic_info_outline_black_24dp"
android:onClick="@{() -> handlers.helpDrawOverOtherApps()}"
android:textAppearance="?android:textAppearanceLarge"
android:text="@string/manage_device_permissions_overlay_title"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<TextView
android:paddingTop="8dp"
android:gravity="center_horizontal"
android:visibility="@{overlayPermission == RuntimePermissionStatus.Granted ? View.VISIBLE : View.GONE}"
android:textColor="@color/text_green"
android:textAppearance="?android:textAppearanceMedium"
android:text="@string/manage_device_permission_status_granted"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<TextView
android:paddingTop="8dp"
android:gravity="center_horizontal"
android:visibility="@{overlayPermission == RuntimePermissionStatus.NotGranted ? View.VISIBLE : View.GONE}"
android:textColor="@color/text_red"
android:textAppearance="?android:textAppearanceMedium"
android:text="@string/manage_device_permission_status_not_granted"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<TextView
android:paddingTop="8dp"
android:gravity="center_horizontal"
android:visibility="@{overlayPermission == RuntimePermissionStatus.NotRequired ? View.VISIBLE : View.GONE}"
android:textColor="@color/text_green"
android:textAppearance="?android:textAppearanceMedium"
android:text="@string/manage_device_permission_status_not_required"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<Button
android:id="@+id/overlay_btn"
android:nextFocusUp="@id/overlay_title"
android:nextFocusDown="@id/accessibility_title"
style="?materialButtonOutlinedStyle"
android:layout_marginEnd="8dp"
android:layout_marginTop="8dp"
android:text="@string/manage_device_permission_btn_modify"
android:layout_gravity="end"
android:onClick="@{() -> handlers.openDrawOverOtherAppsScreen()}"
android:enabled="@{safeUnbox(isThisDevice) &amp;&amp; (overlayPermission != RuntimePermissionStatus.NotRequired)}"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:visibility="@{((safeUnbox(isThisDevice) || (overlayPermission == RuntimePermissionStatus.NotRequired))) ? View.GONE : View.VISIBLE}"
android:text="@string/manage_device_permission_open_at_target_device"
android:textAppearance="?android:textAppearanceSmall"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
</androidx.cardview.widget.CardView>
<androidx.cardview.widget.CardView
app:cardUseCompatPadding="true"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:orientation="vertical"
android:padding="8dp"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/accessibility_title"
android:nextFocusUp="@id/overlay_btn"
android:nextFocusDown="@id/accessibility_btn"
tools:ignore="UnusedAttribute"
android:drawableTint="?colorOnSurface"
android:background="?selectableItemBackground"
android:drawableEnd="@drawable/ic_info_outline_black_24dp"
android:onClick="@{() -> handlers.helpAccesibility()}"
android:textAppearance="?android:textAppearanceLarge"
android:text="@string/manage_device_permission_accessibility_title"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<TextView
android:paddingTop="8dp"
android:gravity="center_horizontal"
android:visibility="@{accessibilityServiceEnabled == true ? View.VISIBLE : View.GONE}"
android:textColor="@color/text_green"
android:textAppearance="?android:textAppearanceMedium"
android:text="@string/manage_device_permission_status_granted"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<TextView
android:paddingTop="8dp"
android:gravity="center_horizontal"
android:visibility="@{accessibilityServiceEnabled == false ? View.VISIBLE : View.GONE}"
android:textColor="@color/text_red"
android:textAppearance="?android:textAppearanceMedium"
android:text="@string/manage_device_permission_status_not_granted"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<Button
android:id="@+id/accessibility_btn"
android:nextFocusUp="@id/accessibility_title"
android:nextFocusDown="@id/fab"
style="?materialButtonOutlinedStyle"
android:layout_marginEnd="8dp"
android:layout_marginTop="8dp"
android:text="@string/manage_device_permission_btn_modify"
android:layout_gravity="end"
android:onClick="@{() -> handlers.openAccessibilitySettings()}"
android:enabled="@{safeUnbox(isThisDevice)}"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:visibility="@{safeUnbox(isThisDevice) ? View.GONE : View.VISIBLE}"
android:text="@string/manage_device_permission_open_at_target_device"
android:textAppearance="?android:textAppearanceSmall"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
</androidx.cardview.widget.CardView>
<View
android:visibility="@{isUserSignedIn ? View.GONE : View.VISIBLE}"
android:layout_width="match_parent"
android:layout_height="76dp" />
</LinearLayout>
</ScrollView>
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:nextFocusUp="@id/accessibility_btn"
android:onClick="@{() -> handlers.showAuthenticationScreen()}"
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>

View file

@ -84,15 +84,6 @@
android:name="parentId"
app:argType="string" />
</fragment>
<fragment
android:id="@+id/manageDevicePermissionsFragment"
android:name="io.timelimit.android.ui.manage.device.manage.permission.ManageDevicePermissionsFragment"
android:label="manage_device_permissions_fragment"
tools:layout="@layout/manage_device_permissions_fragment" >
<argument
android:name="deviceId"
app:argType="string" />
</fragment>
<fragment
android:id="@+id/manageDeviceFeaturesFragment"
android:name="io.timelimit.android.ui.manage.device.manage.feature.ManageDeviceFeaturesFragment"

View file

@ -986,10 +986,6 @@
<string name="manage_device_permission_device_owner_not_granted">Die Geräte-Besitzer-Berechtigung
ist etwas anderes und wurde nicht erteilt.</string>
<string name="manage_device_permission_open_at_target_device">
Öffnen Sie diesen Bildschirm am entsprechenden Gerät, um die Berechtigung festzulegen
</string>
<string name="manage_device_permission_status_granted">Die Berechtigung wurde erteilt</string>
<string name="manage_device_permission_status_not_granted">Die Berechtigung wurde nicht erteilt</string>
<string name="manage_device_permission_status_not_required">Die Berechtigung wird aufgrund der alten Android-Version nicht benötigt</string>
@ -1021,6 +1017,7 @@
<string name="manage_device_permission_goal_background_audio">Einschränkung von Audiowiedergaben im Hintergrund ermöglichen</string>
<string name="manage_device_permission_goal_manipulation_protection">Manipulationen verhindern</string>
<string name="manage_device_permission_goal_manipulation_protection_unavailable">in der aktuellen Umgebung nicht verfügbar</string>
<string name="manage_device_permission_goal_manipulation_protection_check_remotely">öffnen Sie diese Ansicht am entsprechenden Gerät</string>
<string name="manage_device_permission_goal_eventually_needs">benötigt evtl.</string>
<string name="manage_device_permission_goal_needs">benötigt</string>
<string name="manage_device_permission_goal_or">oder</string>
@ -1411,14 +1408,6 @@
<string name="set_password_view_label_password_repeat">Neues Passwort wiederholen</string>
<string name="set_password_view_checkbox_no_password">Passwortschutz nicht verwenden</string>
<string name="setup_device_permissions_text">
TimeLimit benötigt einige Berechtigungen, um funktionieren zu können.
Wirklich erforderlich ist nur der Nutzungsdatenzugriff.
Ab Android 10 wird zum Öffnen des Sperrbildschirms die Berechtigung
\"Über anderen Apps anzeigen\" oder \"Bedienhilfe\" benötigt.
Die weiteren Berechtigungen ermöglichen Zusatzfunktionen.
</string>
<string name="setup_device_permissions_text_short">
TimeLimit benötigt einige Berechtigungen, um funktionieren zu können
</string>

View file

@ -1036,10 +1036,6 @@
<string name="manage_device_permission_device_owner_not_granted">The device
owner permission is something different and was not granted.</string>
<string name="manage_device_permission_open_at_target_device">
Open the screen at the other device to modify the permissions
</string>
<string name="manage_device_permission_status_granted">The permission was granted</string>
<string name="manage_device_permission_status_not_granted">The permission was not granted</string>
<string name="manage_device_permission_status_not_required">The permission is not needed due to the old Android version</string>
@ -1071,6 +1067,7 @@
<string name="manage_device_permission_goal_background_audio">Allow limiting background audio</string>
<string name="manage_device_permission_goal_manipulation_protection">Protect against manipulation</string>
<string name="manage_device_permission_goal_manipulation_protection_unavailable">unavailable in the current environment</string>
<string name="manage_device_permission_goal_manipulation_protection_check_remotely">open this screen at the device</string>
<string name="manage_device_permission_goal_eventually_needs">eventually needs</string>
<string name="manage_device_permission_goal_needs">needs</string>
<string name="manage_device_permission_goal_or">or</string>
@ -1458,14 +1455,6 @@
<string name="set_password_view_label_password_repeat">Repeat new password</string>
<string name="set_password_view_checkbox_no_password">Disable password protection</string>
<string name="setup_device_permissions_text">
TimeLimit needs some permissions to work.
Only the usage stats access permission is absolutely necessary.
Starting Android 10, the permission \"Draw over other Apps\" or \"Accessibility service\"
is required to open the lockscreen.
The other permissions are required for some extra features.
</string>
<string name="setup_device_permissions_text_short">
TimeLimit needs some permissions to work
</string>