mirror of
https://codeberg.org/timelimit/timelimit-android.git
synced 2025-10-03 09:49:25 +02:00
new permission UI
This commit is contained in:
parent
130b3c4b4c
commit
fbd501c3e1
25 changed files with 889 additions and 1255 deletions
|
@ -177,6 +177,7 @@ dependencies {
|
||||||
implementation "com.google.android.material:material:1.8.0"
|
implementation "com.google.android.material:material:1.8.0"
|
||||||
implementation 'androidx.compose.material:material:1.3.1'
|
implementation 'androidx.compose.material:material:1.3.1'
|
||||||
implementation 'androidx.activity:activity-compose:1.6.1'
|
implementation 'androidx.activity:activity-compose:1.6.1'
|
||||||
|
implementation "com.google.accompanist:accompanist-flowlayout:0.30.0"
|
||||||
implementation 'androidx.compose.material:material-icons-extended:1.3.1'
|
implementation 'androidx.compose.material:material-icons-extended:1.3.1'
|
||||||
implementation 'androidx.fragment:fragment-ktx:1.5.5'
|
implementation 'androidx.fragment:fragment-ktx:1.5.5'
|
||||||
|
|
||||||
|
|
|
@ -45,6 +45,7 @@ import io.timelimit.android.R
|
||||||
import io.timelimit.android.data.IdGenerator
|
import io.timelimit.android.data.IdGenerator
|
||||||
import io.timelimit.android.data.model.UserType
|
import io.timelimit.android.data.model.UserType
|
||||||
import io.timelimit.android.extensions.showSafe
|
import io.timelimit.android.extensions.showSafe
|
||||||
|
import io.timelimit.android.integration.platform.SystemPermissionConfirmationLevel
|
||||||
import io.timelimit.android.integration.platform.android.NotificationChannels
|
import io.timelimit.android.integration.platform.android.NotificationChannels
|
||||||
import io.timelimit.android.livedata.ignoreUnchanged
|
import io.timelimit.android.livedata.ignoreUnchanged
|
||||||
import io.timelimit.android.livedata.liveDataFromNullableValue
|
import io.timelimit.android.livedata.liveDataFromNullableValue
|
||||||
|
@ -141,6 +142,9 @@ class MainActivity : AppCompatActivity(), ActivityViewModelHolder, U2fManager.De
|
||||||
ActivityCommand.ShowCanNotAddDevicesInLocalModeDialogFragment -> CanNotAddDevicesInLocalModeDialogFragment().show(supportFragmentManager)
|
ActivityCommand.ShowCanNotAddDevicesInLocalModeDialogFragment -> CanNotAddDevicesInLocalModeDialogFragment().show(supportFragmentManager)
|
||||||
ActivityCommand.ShowAuthenticationScreen -> showAuthenticationScreen()
|
ActivityCommand.ShowAuthenticationScreen -> showAuthenticationScreen()
|
||||||
ActivityCommand.ShowMissingPremiumDialog -> RequiresPurchaseDialogFragment().show(supportFragmentManager)
|
ActivityCommand.ShowMissingPremiumDialog -> RequiresPurchaseDialogFragment().show(supportFragmentManager)
|
||||||
|
is ActivityCommand.LaunchSystemSettings -> mainModel.logic.platformIntegration.openSystemPermissionScren(
|
||||||
|
this@MainActivity, message.permission, SystemPermissionConfirmationLevel.Suggestion
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,9 +19,11 @@ import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.fragment.app.FragmentManager
|
import androidx.fragment.app.FragmentManager
|
||||||
import io.timelimit.android.ui.diagnose.deviceowner.DeviceOwnerScreen
|
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.manage.device.manage.user.ManageDeviceUserScreen
|
||||||
import io.timelimit.android.ui.model.Screen
|
import io.timelimit.android.ui.model.Screen
|
||||||
import io.timelimit.android.ui.overview.overview.OverviewScreen
|
import io.timelimit.android.ui.overview.overview.OverviewScreen
|
||||||
|
import io.timelimit.android.ui.setup.SetupDevicePermissionsScreen
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun ScreenMultiplexer(
|
fun ScreenMultiplexer(
|
||||||
|
@ -36,5 +38,7 @@ fun ScreenMultiplexer(
|
||||||
is Screen.OverviewScreen -> OverviewScreen(screen.content, modifier = modifier)
|
is Screen.OverviewScreen -> OverviewScreen(screen.content, modifier = modifier)
|
||||||
is Screen.ManageDeviceUserScreen -> ManageDeviceUserScreen(screen.items, screen.actions, screen.overlay, modifier)
|
is Screen.ManageDeviceUserScreen -> ManageDeviceUserScreen(screen.items, screen.actions, screen.overlay, modifier)
|
||||||
is Screen.DeviceOwnerScreen -> DeviceOwnerScreen(screen.content, modifier = 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)
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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)
|
||||||
|
)
|
||||||
|
}
|
|
@ -16,35 +16,13 @@
|
||||||
package io.timelimit.android.ui.manage.device.manage.permission
|
package io.timelimit.android.ui.manage.device.manage.permission
|
||||||
|
|
||||||
import android.content.Context
|
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.R
|
||||||
import io.timelimit.android.data.model.Device
|
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.NewPermissionStatus
|
||||||
import io.timelimit.android.integration.platform.ProtectionLevel
|
import io.timelimit.android.integration.platform.ProtectionLevel
|
||||||
import io.timelimit.android.integration.platform.RuntimePermissionStatus
|
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 {
|
object ManageDevicePermissionsFragment {
|
||||||
companion object {
|
|
||||||
fun getPreviewText(device: Device, context: Context): String {
|
fun getPreviewText(device: Device, context: Context): String {
|
||||||
val permissionLabels = mutableListOf<String>()
|
val permissionLabels = mutableListOf<String>()
|
||||||
|
|
||||||
|
@ -74,144 +52,4 @@ class ManageDevicePermissionsFragment : Fragment(), FragmentWithCustomTitle {
|
||||||
permissionLabels.joinToString(", ")
|
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()
|
|
||||||
}
|
}
|
|
@ -0,0 +1,150 @@
|
||||||
|
/*
|
||||||
|
* 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.*
|
||||||
|
import androidx.compose.material.*
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.CheckBox
|
||||||
|
import androidx.compose.material.icons.filled.CheckBoxOutlineBlank
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import io.timelimit.android.R
|
||||||
|
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
|
||||||
|
|
||||||
|
@OptIn(ExperimentalLayoutApi::class)
|
||||||
|
@Composable
|
||||||
|
fun PermissionGoals(status: PermissionScreenContent.Status) {
|
||||||
|
PermissionGoal(
|
||||||
|
stringResource(R.string.manage_device_permission_goal_limit_title),
|
||||||
|
status.usageStats != RuntimePermissionStatus.NotGranted &&
|
||||||
|
(!status.isQOrLater || status.overlay == RuntimePermissionStatus.Granted || status.accessibility),
|
||||||
|
) {
|
||||||
|
if (status.usageStats != RuntimePermissionStatus.NotRequired) FlowRow {
|
||||||
|
Text(stringResource(R.string.manage_device_permission_goal_needs))
|
||||||
|
PermissionIcon(SystemPermission.UsageStats, status.usageStats == RuntimePermissionStatus.Granted)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status.isQOrLater) FlowRow {
|
||||||
|
Text(stringResource(R.string.manage_device_permission_goal_needs))
|
||||||
|
PermissionIcon(SystemPermission.Overlay, status.overlay == RuntimePermissionStatus.Granted)
|
||||||
|
Text(stringResource(R.string.manage_device_permission_goal_or))
|
||||||
|
PermissionIcon(SystemPermission.AccessibilityService, status.accessibility)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status.usageStats == RuntimePermissionStatus.NotRequired && !status.isQOrLater)
|
||||||
|
Text(stringResource(R.string.manage_device_permission_goal_reached_by_old_android))
|
||||||
|
}
|
||||||
|
|
||||||
|
PermissionGoal(
|
||||||
|
stringResource(R.string.manage_device_permission_goal_floating_window),
|
||||||
|
status.accessibility
|
||||||
|
) {
|
||||||
|
FlowRow {
|
||||||
|
Text(stringResource(R.string.manage_device_permission_goal_eventually_needs))
|
||||||
|
PermissionIcon(SystemPermission.AccessibilityService, status.accessibility)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PermissionGoal(
|
||||||
|
stringResource(R.string.manage_device_permission_goal_background_audio),
|
||||||
|
status.notificationAccess == NewPermissionStatus.Granted
|
||||||
|
) {
|
||||||
|
FlowRow {
|
||||||
|
Text(stringResource(R.string.manage_device_permission_goal_needs))
|
||||||
|
PermissionIcon(
|
||||||
|
SystemPermission.Notification,
|
||||||
|
status.notificationAccess == NewPermissionStatus.Granted
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PermissionGoal(
|
||||||
|
stringResource(R.string.manage_device_permission_goal_manipulation_protection),
|
||||||
|
status.protectionLevel == ProtectionLevel.DeviceOwner
|
||||||
|
) {
|
||||||
|
Text(stringResource(
|
||||||
|
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
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun PermissionGoal(
|
||||||
|
title: String,
|
||||||
|
checked: Boolean,
|
||||||
|
content: @Composable () -> Unit
|
||||||
|
) {
|
||||||
|
Card (
|
||||||
|
elevation = 4.dp
|
||||||
|
) {
|
||||||
|
Row (
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
|
) {
|
||||||
|
Column (
|
||||||
|
Modifier
|
||||||
|
.weight(1f)
|
||||||
|
.padding(8.dp),
|
||||||
|
verticalArrangement = Arrangement.spacedBy(8.dp)
|
||||||
|
) {
|
||||||
|
Text(title, style = MaterialTheme.typography.h6)
|
||||||
|
|
||||||
|
content()
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.width(8.dp))
|
||||||
|
|
||||||
|
if (checked) Icon(
|
||||||
|
Icons.Default.CheckBox,
|
||||||
|
stringResource(R.string.manage_device_permission_goal_reached),
|
||||||
|
tint = MaterialTheme.colors.primary
|
||||||
|
) else Icon(
|
||||||
|
Icons.Default.CheckBoxOutlineBlank,
|
||||||
|
stringResource(R.string.manage_device_permission_goal_missed)
|
||||||
|
)
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.width(8.dp))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun PermissionIcon(permission: SystemPermission, checked: Boolean) {
|
||||||
|
val icon = PermissionVisualization.getIcon(permission)
|
||||||
|
val label = PermissionVisualization.getLabel(LocalContext.current, false, permission)
|
||||||
|
|
||||||
|
val tint =
|
||||||
|
if (checked) MaterialTheme.colors.primary
|
||||||
|
else LocalContentColor.current
|
||||||
|
|
||||||
|
Icon(
|
||||||
|
icon,
|
||||||
|
label,
|
||||||
|
tint = tint
|
||||||
|
)
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
/*
|
||||||
|
* 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.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,
|
||||||
|
modifier: Modifier = Modifier
|
||||||
|
) {
|
||||||
|
Column (
|
||||||
|
verticalArrangement = Arrangement.spacedBy(8.dp),
|
||||||
|
modifier = modifier
|
||||||
|
) {
|
||||||
|
PermissionScreenPermissionList(content.status, content.showDetails)
|
||||||
|
PermissionGoals(content.status)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (content.dialog != null) PermissionScreenDialog(content.dialog, content.status)
|
||||||
|
}
|
|
@ -0,0 +1,43 @@
|
||||||
|
/*
|
||||||
|
* 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 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
|
||||||
|
|
||||||
|
data class PermissionScreenContent(
|
||||||
|
val status: Status,
|
||||||
|
val dialog: Dialog?,
|
||||||
|
val showDetails: (SystemPermission) -> Unit
|
||||||
|
) {
|
||||||
|
data class Status(
|
||||||
|
val notificationAccess: NewPermissionStatus,
|
||||||
|
val protectionLevel: ProtectionLevel,
|
||||||
|
val maxProtectionLevel: ProtectionLevel?,
|
||||||
|
val usageStats: RuntimePermissionStatus,
|
||||||
|
val overlay: RuntimePermissionStatus,
|
||||||
|
val accessibility: Boolean,
|
||||||
|
val isQOrLater: Boolean
|
||||||
|
)
|
||||||
|
|
||||||
|
data class Dialog(
|
||||||
|
val permission: SystemPermission,
|
||||||
|
val launchSystemSettings: (() -> Unit)?,
|
||||||
|
val close: () -> Unit
|
||||||
|
)
|
||||||
|
}
|
|
@ -0,0 +1,85 @@
|
||||||
|
/*
|
||||||
|
* 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.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.material.*
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import io.timelimit.android.R
|
||||||
|
import io.timelimit.android.integration.platform.ProtectionLevel
|
||||||
|
import io.timelimit.android.integration.platform.SystemPermission
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun PermissionScreenDialog(
|
||||||
|
dialog: PermissionScreenContent.Dialog,
|
||||||
|
status: PermissionScreenContent.Status
|
||||||
|
) {
|
||||||
|
val permissionIcon = PermissionVisualization.getIcon(dialog.permission)
|
||||||
|
val permissionTitle = PermissionVisualization.getLabel(LocalContext.current, false, dialog.permission)
|
||||||
|
val permissionDescription = PermissionVisualization.getDescription(LocalContext.current, dialog.permission)
|
||||||
|
val permissionStatus = PermissionVisualization.getStatusText(LocalContext.current, dialog.permission, status)
|
||||||
|
|
||||||
|
AlertDialog(
|
||||||
|
onDismissRequest = dialog.close,
|
||||||
|
title = {
|
||||||
|
Row (
|
||||||
|
horizontalArrangement = Arrangement.spacedBy(16.dp),
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
|
) {
|
||||||
|
Icon(permissionIcon, permissionTitle)
|
||||||
|
Text(permissionTitle)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
text = {
|
||||||
|
Column (
|
||||||
|
verticalArrangement = Arrangement.spacedBy(8.dp)
|
||||||
|
) {
|
||||||
|
Text(permissionDescription, style = MaterialTheme.typography.body1)
|
||||||
|
|
||||||
|
Text(permissionStatus, style = MaterialTheme.typography.body1)
|
||||||
|
|
||||||
|
if (dialog.permission == SystemPermission.DeviceAdmin) {
|
||||||
|
val message =
|
||||||
|
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
|
||||||
|
|
||||||
|
if (message != null) Text(stringResource(message), style = MaterialTheme.typography.body1)
|
||||||
|
}
|
||||||
|
|
||||||
|
Text(stringResource(R.string.manage_device_permission_link_only_info))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
dismissButton = {
|
||||||
|
TextButton(onClick = dialog.close) {
|
||||||
|
Text(stringResource(R.string.generic_cancel))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
confirmButton = {
|
||||||
|
if (dialog.launchSystemSettings != null) {
|
||||||
|
TextButton(onClick = dialog.launchSystemSettings) {
|
||||||
|
Text(stringResource(R.string.manage_device_permission_btn_modify))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
|
@ -0,0 +1,79 @@
|
||||||
|
/*
|
||||||
|
* 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.clickable
|
||||||
|
import androidx.compose.foundation.layout.*
|
||||||
|
import androidx.compose.material.Card
|
||||||
|
import androidx.compose.material.Icon
|
||||||
|
import androidx.compose.material.MaterialTheme
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import io.timelimit.android.integration.platform.SystemPermission
|
||||||
|
|
||||||
|
@OptIn(ExperimentalLayoutApi::class)
|
||||||
|
@Composable
|
||||||
|
fun PermissionScreenPermissionList(
|
||||||
|
status: PermissionScreenContent.Status,
|
||||||
|
showDetails: (SystemPermission) -> Unit
|
||||||
|
) {
|
||||||
|
val permissions = listOf(
|
||||||
|
SystemPermission.UsageStats,
|
||||||
|
SystemPermission.DeviceAdmin,
|
||||||
|
SystemPermission.Notification,
|
||||||
|
SystemPermission.Overlay,
|
||||||
|
SystemPermission.AccessibilityService
|
||||||
|
)
|
||||||
|
|
||||||
|
FlowRow (
|
||||||
|
horizontalArrangement = Arrangement.spacedBy(16.dp, Alignment.CenterHorizontally),
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
maxItemsInEachRow = 3
|
||||||
|
) {
|
||||||
|
for (permission in permissions) {
|
||||||
|
val permissionIcon = PermissionVisualization.getIcon(permission)
|
||||||
|
val permissionStatus = PermissionVisualization.getStatusColor(status, permission)
|
||||||
|
val permissionLabel = PermissionVisualization.getLabel(LocalContext.current, false, permission)
|
||||||
|
|
||||||
|
Box (
|
||||||
|
Modifier.padding(vertical = 8.dp)
|
||||||
|
) {
|
||||||
|
Card(
|
||||||
|
modifier = Modifier.clickable(
|
||||||
|
onClick = { showDetails(permission) },
|
||||||
|
onClickLabel = permissionLabel
|
||||||
|
),
|
||||||
|
backgroundColor = when (permissionStatus) {
|
||||||
|
PermissionVisualization.Status.Neutral -> MaterialTheme.colors.surface
|
||||||
|
PermissionVisualization.Status.Good -> MaterialTheme.colors.primary
|
||||||
|
},
|
||||||
|
elevation = 8.dp
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
permissionIcon,
|
||||||
|
permissionLabel,
|
||||||
|
Modifier
|
||||||
|
.padding(16.dp)
|
||||||
|
.size(64.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,110 @@
|
||||||
|
/*
|
||||||
|
* 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 android.content.Context
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.*
|
||||||
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
|
import io.timelimit.android.R
|
||||||
|
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
|
||||||
|
|
||||||
|
object PermissionVisualization {
|
||||||
|
fun getIcon(permission: SystemPermission): ImageVector = when (permission) {
|
||||||
|
SystemPermission.UsageStats -> Icons.Default.BarChart
|
||||||
|
SystemPermission.DeviceAdmin -> Icons.Default.Shield
|
||||||
|
SystemPermission.Notification -> Icons.Default.Notifications
|
||||||
|
SystemPermission.Overlay -> Icons.Default.Layers
|
||||||
|
SystemPermission.AccessibilityService -> Icons.Default.AccessibilityNew
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getLabel(context: Context, short: Boolean, permission: SystemPermission): String = context.getString(when (permission) {
|
||||||
|
SystemPermission.UsageStats ->
|
||||||
|
if (short) R.string.manage_device_permissions_usagestats_title_short
|
||||||
|
else R.string.manage_device_permissions_usagestats_title
|
||||||
|
SystemPermission.DeviceAdmin -> R.string.manage_device_permission_device_admin_title
|
||||||
|
SystemPermission.Notification -> R.string.manage_device_permission_notification_access_title
|
||||||
|
SystemPermission.Overlay -> R.string.manage_device_permissions_overlay_title
|
||||||
|
SystemPermission.AccessibilityService -> R.string.manage_device_permission_accessibility_title
|
||||||
|
})
|
||||||
|
|
||||||
|
fun getDescription(context: Context, permission: SystemPermission): String = context.getString(when (permission) {
|
||||||
|
SystemPermission.UsageStats -> R.string.manage_device_permissions_usagestats_text
|
||||||
|
SystemPermission.DeviceAdmin -> R.string.manage_device_permission_device_admin_text
|
||||||
|
SystemPermission.Notification -> R.string.manage_device_permission_notification_access_text
|
||||||
|
SystemPermission.Overlay -> R.string.manage_device_permissions_overlay_text
|
||||||
|
SystemPermission.AccessibilityService -> R.string.manage_device_permission_accessibility_text
|
||||||
|
})
|
||||||
|
|
||||||
|
fun getStatusColor(status: PermissionScreenContent.Status, permission: SystemPermission): Status = when (permission) {
|
||||||
|
SystemPermission.UsageStats ->
|
||||||
|
if (status.usageStats == RuntimePermissionStatus.Granted) Status.Good
|
||||||
|
else Status.Neutral
|
||||||
|
SystemPermission.DeviceAdmin ->
|
||||||
|
if (status.protectionLevel != ProtectionLevel.None) Status.Good
|
||||||
|
else Status.Neutral
|
||||||
|
SystemPermission.Notification ->
|
||||||
|
if (status.notificationAccess == NewPermissionStatus.Granted) Status.Good
|
||||||
|
else Status.Neutral
|
||||||
|
SystemPermission.Overlay ->
|
||||||
|
if (status.overlay == RuntimePermissionStatus.Granted) Status.Good
|
||||||
|
else Status.Neutral
|
||||||
|
SystemPermission.AccessibilityService ->
|
||||||
|
if (status.accessibility) Status.Good
|
||||||
|
else Status.Neutral
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getStatusText(context: Context, permission: SystemPermission, status: PermissionScreenContent.Status): String = when (permission) {
|
||||||
|
SystemPermission.UsageStats ->
|
||||||
|
context.getString(when (status.usageStats) {
|
||||||
|
RuntimePermissionStatus.Granted -> R.string.manage_device_permission_status_granted
|
||||||
|
RuntimePermissionStatus.NotGranted -> R.string.manage_device_permission_status_not_granted
|
||||||
|
RuntimePermissionStatus.NotRequired -> R.string.manage_device_permission_status_not_required
|
||||||
|
})
|
||||||
|
SystemPermission.DeviceAdmin ->
|
||||||
|
context.getString(when (status.protectionLevel) {
|
||||||
|
ProtectionLevel.None -> R.string.manage_device_permission_device_admin_text_disabled
|
||||||
|
ProtectionLevel.SimpleDeviceAdmin -> R.string.manage_device_permission_device_admin_text_simple
|
||||||
|
ProtectionLevel.PasswordDeviceAdmin -> R.string.manage_device_permission_device_admin_text_password
|
||||||
|
ProtectionLevel.DeviceOwner -> R.string.manage_device_permission_device_admin_text_owner
|
||||||
|
})
|
||||||
|
SystemPermission.Notification ->
|
||||||
|
context.getString(when (status.notificationAccess) {
|
||||||
|
NewPermissionStatus.Granted -> R.string.manage_device_permission_status_granted
|
||||||
|
NewPermissionStatus.NotGranted -> R.string.manage_device_permission_status_not_granted
|
||||||
|
NewPermissionStatus.NotSupported -> R.string.manage_device_permission_status_not_supported
|
||||||
|
})
|
||||||
|
SystemPermission.Overlay ->
|
||||||
|
context.getString(when (status.overlay) {
|
||||||
|
RuntimePermissionStatus.Granted -> R.string.manage_device_permission_status_granted
|
||||||
|
RuntimePermissionStatus.NotGranted -> R.string.manage_device_permission_status_not_granted
|
||||||
|
RuntimePermissionStatus.NotRequired -> R.string.manage_device_permission_status_not_required
|
||||||
|
})
|
||||||
|
SystemPermission.AccessibilityService ->
|
||||||
|
context.getString(when (status.accessibility) {
|
||||||
|
true -> R.string.manage_device_permission_status_granted
|
||||||
|
false -> R.string.manage_device_permission_status_not_granted
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class Status {
|
||||||
|
Neutral,
|
||||||
|
Good,
|
||||||
|
}
|
||||||
|
}
|
|
@ -15,9 +15,12 @@
|
||||||
*/
|
*/
|
||||||
package io.timelimit.android.ui.model
|
package io.timelimit.android.ui.model
|
||||||
|
|
||||||
|
import io.timelimit.android.integration.platform.SystemPermission
|
||||||
|
|
||||||
sealed class ActivityCommand {
|
sealed class ActivityCommand {
|
||||||
object ShowCanNotAddDevicesInLocalModeDialogFragment: ActivityCommand()
|
object ShowCanNotAddDevicesInLocalModeDialogFragment: ActivityCommand()
|
||||||
object ShowAddDeviceFragment: ActivityCommand()
|
object ShowAddDeviceFragment: ActivityCommand()
|
||||||
object ShowAuthenticationScreen: ActivityCommand()
|
object ShowAuthenticationScreen: ActivityCommand()
|
||||||
object ShowMissingPremiumDialog: ActivityCommand()
|
object ShowMissingPremiumDialog: ActivityCommand()
|
||||||
|
class LaunchSystemSettings(val permission: SystemPermission): ActivityCommand()
|
||||||
}
|
}
|
|
@ -30,6 +30,7 @@ import io.timelimit.android.ui.model.launch.LaunchHandling
|
||||||
import io.timelimit.android.ui.model.main.OverviewHandling
|
import io.timelimit.android.ui.model.main.OverviewHandling
|
||||||
import io.timelimit.android.ui.model.managechild.ManageChildHandling
|
import io.timelimit.android.ui.model.managechild.ManageChildHandling
|
||||||
import io.timelimit.android.ui.model.managedevice.ManageDeviceHandling
|
import io.timelimit.android.ui.model.managedevice.ManageDeviceHandling
|
||||||
|
import io.timelimit.android.ui.model.setup.SetupLocalModePermissions
|
||||||
import kotlinx.coroutines.channels.Channel
|
import kotlinx.coroutines.channels.Channel
|
||||||
import kotlinx.coroutines.channels.ReceiveChannel
|
import kotlinx.coroutines.channels.ReceiveChannel
|
||||||
import kotlinx.coroutines.flow.*
|
import kotlinx.coroutines.flow.*
|
||||||
|
@ -57,8 +58,8 @@ class MainModel(application: Application): AndroidViewModel(application) {
|
||||||
}
|
}
|
||||||
|
|
||||||
val activityModel = ActivityViewModel(application)
|
val activityModel = ActivityViewModel(application)
|
||||||
|
val logic = DefaultAppLogic.with(application)
|
||||||
|
|
||||||
private val logic = DefaultAppLogic.with(application)
|
|
||||||
private val activityCommandInternal = Channel<ActivityCommand>()
|
private val activityCommandInternal = Channel<ActivityCommand>()
|
||||||
private val authenticationScreenClosed = MutableSharedFlow<Unit>(extraBufferCapacity = 1)
|
private val authenticationScreenClosed = MutableSharedFlow<Unit>(extraBufferCapacity = 1)
|
||||||
|
|
||||||
|
@ -112,6 +113,7 @@ class MainModel(application: Application): AndroidViewModel(application) {
|
||||||
Case.simple<_, _, State.ManageChild> { state -> ManageChildHandling.processState(logic, state, updateMethod(::updateState)) },
|
Case.simple<_, _, State.ManageChild> { state -> ManageChildHandling.processState(logic, state, updateMethod(::updateState)) },
|
||||||
Case.simple<_, _, State.ManageDevice> { state -> ManageDeviceHandling.processState(logic, activityCommandInternal, authenticationModelApi, state, updateMethod(::updateState)) },
|
Case.simple<_, _, State.ManageDevice> { state -> ManageDeviceHandling.processState(logic, activityCommandInternal, authenticationModelApi, state, updateMethod(::updateState)) },
|
||||||
Case.simple<_, _, State.DiagnoseScreen.DeviceOwner> { DeviceOwnerHandling.processState(logic, scope, authenticationModelApi, state) },
|
Case.simple<_, _, State.DiagnoseScreen.DeviceOwner> { DeviceOwnerHandling.processState(logic, scope, authenticationModelApi, state) },
|
||||||
|
Case.simple<_, _, State.Setup.DevicePermissions> { state -> SetupLocalModePermissions.handle(logic, activityCommandInternal, state, updateMethod(::updateState)) },
|
||||||
Case.simple<_, _, FragmentState> { state ->
|
Case.simple<_, _, FragmentState> { state ->
|
||||||
state.transform {
|
state.transform {
|
||||||
val containerId = it.containerId ?: run {
|
val containerId = it.containerId ?: run {
|
||||||
|
|
|
@ -19,6 +19,7 @@ import androidx.compose.material.SnackbarHostState
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.outlined.Info
|
import androidx.compose.material.icons.outlined.Info
|
||||||
import io.timelimit.android.R
|
import io.timelimit.android.R
|
||||||
|
import io.timelimit.android.ui.manage.device.manage.permission.PermissionScreenContent
|
||||||
import io.timelimit.android.ui.model.diagnose.DeviceOwnerHandling
|
import io.timelimit.android.ui.model.diagnose.DeviceOwnerHandling
|
||||||
import io.timelimit.android.ui.model.main.OverviewHandling
|
import io.timelimit.android.ui.model.main.OverviewHandling
|
||||||
import io.timelimit.android.ui.model.managedevice.ManageDeviceUser
|
import io.timelimit.android.ui.model.managedevice.ManageDeviceUser
|
||||||
|
@ -177,12 +178,9 @@ sealed class Screen(
|
||||||
|
|
||||||
class ManageDevicePermissions(
|
class ManageDevicePermissions(
|
||||||
state: State,
|
state: State,
|
||||||
toolbarIcons: List<Menu.Icon>,
|
val content: PermissionScreenContent,
|
||||||
toolbarOptions: List<Menu.Dropdown>,
|
|
||||||
fragment: FragmentState,
|
|
||||||
containerId: Int,
|
|
||||||
override val backStack: List<BackStackItem>
|
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)
|
override val title = Title.StringResource(R.string.manage_device_card_permission_title)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -215,6 +213,12 @@ sealed class Screen(
|
||||||
): Screen(state), ScreenWithAuthenticationFab, ScreenWithSnackbar, ScreenWithTitle {
|
): Screen(state), ScreenWithAuthenticationFab, ScreenWithSnackbar, ScreenWithTitle {
|
||||||
override val title = Title.StringResource(R.string.diagnose_dom_title)
|
override val title = Title.StringResource(R.string.diagnose_dom_title)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class SetupDevicePermissionsScreen(
|
||||||
|
state: State,
|
||||||
|
val content: PermissionScreenContent,
|
||||||
|
val next: () -> Unit
|
||||||
|
): Screen(state)
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ScreenWithAuthenticationFab
|
interface ScreenWithAuthenticationFab
|
||||||
|
|
|
@ -21,6 +21,7 @@ import androidx.compose.material.icons.filled.DirectionsBike
|
||||||
import androidx.compose.material.icons.filled.Phone
|
import androidx.compose.material.icons.filled.Phone
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import io.timelimit.android.R
|
import io.timelimit.android.R
|
||||||
|
import io.timelimit.android.integration.platform.SystemPermission
|
||||||
import io.timelimit.android.ui.contacts.ContactsFragment
|
import io.timelimit.android.ui.contacts.ContactsFragment
|
||||||
import io.timelimit.android.ui.diagnose.*
|
import io.timelimit.android.ui.diagnose.*
|
||||||
import io.timelimit.android.ui.diagnose.exitreason.DiagnoseExitReasonFragment
|
import io.timelimit.android.ui.diagnose.exitreason.DiagnoseExitReasonFragment
|
||||||
|
@ -35,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.advanced.ManageDeviceAdvancedFragmentArgs
|
||||||
import io.timelimit.android.ui.manage.device.manage.feature.ManageDeviceFeaturesFragment
|
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.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.ManageParentFragment
|
||||||
import io.timelimit.android.ui.manage.parent.ManageParentFragmentArgs
|
import io.timelimit.android.ui.manage.parent.ManageParentFragmentArgs
|
||||||
import io.timelimit.android.ui.manage.parent.link.LinkParentMailFragment
|
import io.timelimit.android.ui.manage.parent.link.LinkParentMailFragment
|
||||||
|
@ -228,9 +227,7 @@ sealed class State (val previous: State?): Serializable {
|
||||||
object AdjustDefaultUserTimeout: Overlay()
|
object AdjustDefaultUserTimeout: Overlay()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
class Permissions(previousMain: Main): Sub(previousMain, ManageDevicePermissionsFragment::class.java) {
|
data class Permissions(val previousMain: Main, val currentDialog: SystemPermission? = null): Sub(previousMain, Fragment::class.java)
|
||||||
override val arguments: Bundle get() = ManageDevicePermissionsFragmentArgs(deviceId).toBundle()
|
|
||||||
}
|
|
||||||
class Features(previousMain: Main): Sub(previousMain, ManageDeviceFeaturesFragment::class.java) {
|
class Features(previousMain: Main): Sub(previousMain, ManageDeviceFeaturesFragment::class.java) {
|
||||||
override val arguments: Bundle get() = ManageDeviceFeaturesFragmentArgs(deviceId).toBundle()
|
override val arguments: Bundle get() = ManageDeviceFeaturesFragmentArgs(deviceId).toBundle()
|
||||||
}
|
}
|
||||||
|
@ -256,7 +253,10 @@ sealed class State (val previous: State?): Serializable {
|
||||||
class SetupTerms: FragmentStateLegacy(previous = null, fragmentClass = SetupTermsFragment::class.java)
|
class SetupTerms: FragmentStateLegacy(previous = null, fragmentClass = SetupTermsFragment::class.java)
|
||||||
class SetupHelpInfo(previous: SetupTerms): FragmentStateLegacy(previous = previous, fragmentClass = SetupHelpInfoFragment::class.java)
|
class SetupHelpInfo(previous: SetupTerms): FragmentStateLegacy(previous = previous, fragmentClass = SetupHelpInfoFragment::class.java)
|
||||||
class SelectMode(previous: SetupHelpInfo): FragmentStateLegacy(previous = previous, fragmentClass = SetupSelectModeFragment::class.java)
|
class SelectMode(previous: SetupHelpInfo): FragmentStateLegacy(previous = previous, fragmentClass = SetupSelectModeFragment::class.java)
|
||||||
class DevicePermissions(previous: SelectMode): FragmentStateLegacy(previous = previous, fragmentClass = SetupDevicePermissionsFragment::class.java)
|
data class DevicePermissions(
|
||||||
|
val previousSelectMode: SelectMode,
|
||||||
|
val currentDialog: SystemPermission? = null
|
||||||
|
): FragmentStateLegacy(previous = previousSelectMode, fragmentClass = Fragment::class.java)
|
||||||
class LocalMode(previous: DevicePermissions): FragmentStateLegacy(previous = previous, fragmentClass = SetupLocalModeFragment::class.java)
|
class LocalMode(previous: DevicePermissions): FragmentStateLegacy(previous = previous, fragmentClass = SetupLocalModeFragment::class.java)
|
||||||
class RemoteChild(previous: SelectMode): FragmentStateLegacy(previous = previous, fragmentClass = SetupRemoteChildFragment::class.java)
|
class RemoteChild(previous: SelectMode): FragmentStateLegacy(previous = previous, fragmentClass = SetupRemoteChildFragment::class.java)
|
||||||
class ParentMode(previous: SelectMode): FragmentStateLegacy(previous = previous, fragmentClass = SetupParentModeFragment::class.java)
|
class ParentMode(previous: SelectMode): FragmentStateLegacy(previous = previous, fragmentClass = SetupParentModeFragment::class.java)
|
||||||
|
|
|
@ -118,11 +118,15 @@ object ManageDeviceHandling {
|
||||||
updateMethod(updateState)
|
updateMethod(updateState)
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
Case.simple<_, _, State.ManageDevice.Permissions> {
|
Case.simple<_, _, State.ManageDevice.Permissions> {state ->
|
||||||
processPermissionsState(
|
ManageDevicePermissions.processState(
|
||||||
it,
|
scope,
|
||||||
|
logic,
|
||||||
|
activityCommand,
|
||||||
|
state,
|
||||||
subBackStackLive,
|
subBackStackLive,
|
||||||
deviceLive
|
deviceLive,
|
||||||
|
updateMethod(updateState)
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
Case.simple<_, _, State.ManageDevice.Features> {
|
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(
|
private fun processFeaturesState(
|
||||||
stateLive: Flow<State.ManageDevice.Features>,
|
stateLive: Flow<State.ManageDevice.Features>,
|
||||||
parentBackStackLive: Flow<List<BackStackItem>>,
|
parentBackStackLive: Flow<List<BackStackItem>>,
|
||||||
|
|
|
@ -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()
|
||||||
|
}
|
|
@ -0,0 +1,80 @@
|
||||||
|
/*
|
||||||
|
* 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.setup
|
||||||
|
|
||||||
|
import io.timelimit.android.integration.platform.PlatformIntegration
|
||||||
|
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.Screen
|
||||||
|
import io.timelimit.android.ui.model.State
|
||||||
|
import io.timelimit.android.util.AndroidVersion
|
||||||
|
import kotlinx.coroutines.channels.SendChannel
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.flow.combine
|
||||||
|
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||||
|
import kotlinx.coroutines.flow.flow
|
||||||
|
|
||||||
|
object SetupLocalModePermissions {
|
||||||
|
fun handle(
|
||||||
|
logic: AppLogic,
|
||||||
|
activityCommand: SendChannel<ActivityCommand>,
|
||||||
|
stateLive: Flow<State.Setup.DevicePermissions>,
|
||||||
|
updateState: ((State.Setup.DevicePermissions) -> State) -> Unit
|
||||||
|
): Flow<Screen> {
|
||||||
|
val deviceStatusLive = deviceStatus(logic.platformIntegration)
|
||||||
|
|
||||||
|
return combine(stateLive, deviceStatusLive) { state, deviceStatus ->
|
||||||
|
Screen.SetupDevicePermissionsScreen(
|
||||||
|
state,
|
||||||
|
PermissionScreenContent(
|
||||||
|
status = deviceStatus,
|
||||||
|
dialog = state.currentDialog?.let { dialog ->
|
||||||
|
PermissionScreenContent.Dialog(
|
||||||
|
permission = dialog,
|
||||||
|
launchSystemSettings = {
|
||||||
|
activityCommand.trySend(ActivityCommand.LaunchSystemSettings(dialog))
|
||||||
|
|
||||||
|
updateState { it.copy(currentDialog = null) }
|
||||||
|
},
|
||||||
|
close = { updateState { it.copy(currentDialog = null) } }
|
||||||
|
)
|
||||||
|
},
|
||||||
|
showDetails = { permission -> updateState { it.copy(currentDialog = permission) } }
|
||||||
|
)
|
||||||
|
) { updateState { State.Setup.LocalMode(it) } }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun deviceStatus(platformIntegration: PlatformIntegration): Flow<PermissionScreenContent.Status> = flow {
|
||||||
|
while (true) {
|
||||||
|
emit(
|
||||||
|
PermissionScreenContent.Status(
|
||||||
|
notificationAccess = platformIntegration.getNotificationAccessPermissionStatus(),
|
||||||
|
protectionLevel = platformIntegration.getCurrentProtectionLevel(),
|
||||||
|
maxProtectionLevel = platformIntegration.maximumProtectionLevel,
|
||||||
|
usageStats = platformIntegration.getForegroundAppPermissionStatus(),
|
||||||
|
overlay = platformIntegration.getDrawOverOtherAppsPermissionStatus(true),
|
||||||
|
accessibility = platformIntegration.isAccessibilityServiceEnabled(),
|
||||||
|
isQOrLater = AndroidVersion.qOrLater
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
delay(2000)
|
||||||
|
}
|
||||||
|
}.distinctUntilChanged()
|
||||||
|
}
|
|
@ -1,131 +0,0 @@
|
||||||
/*
|
|
||||||
* 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.setup
|
|
||||||
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.view.LayoutInflater
|
|
||||||
import android.view.View
|
|
||||||
import android.view.ViewGroup
|
|
||||||
import androidx.fragment.app.Fragment
|
|
||||||
import io.timelimit.android.async.Threads
|
|
||||||
import io.timelimit.android.databinding.FragmentSetupDevicePermissionsBinding
|
|
||||||
import io.timelimit.android.integration.platform.SystemPermission
|
|
||||||
import io.timelimit.android.logic.AppLogic
|
|
||||||
import io.timelimit.android.logic.DefaultAppLogic
|
|
||||||
import io.timelimit.android.ui.manage.device.manage.permission.PermissionInfoHelpDialog
|
|
||||||
import io.timelimit.android.ui.model.UpdateStateCommand
|
|
||||||
import io.timelimit.android.ui.model.execute
|
|
||||||
|
|
||||||
class SetupDevicePermissionsFragment : Fragment() {
|
|
||||||
private val logic: AppLogic by lazy { DefaultAppLogic.with(context!!) }
|
|
||||||
private lateinit var binding: FragmentSetupDevicePermissionsBinding
|
|
||||||
|
|
||||||
lateinit var refreshStatusRunnable: Runnable
|
|
||||||
|
|
||||||
init {
|
|
||||||
refreshStatusRunnable = Runnable {
|
|
||||||
refreshStatus()
|
|
||||||
|
|
||||||
Threads.mainThreadHandler.postDelayed(refreshStatusRunnable, 2000L)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
|
||||||
binding = FragmentSetupDevicePermissionsBinding.inflate(inflater, container, false)
|
|
||||||
|
|
||||||
binding.handlers = object: SetupDevicePermissionsHandlers {
|
|
||||||
override fun manageDeviceAdmin() {
|
|
||||||
logic.platformIntegration.openSystemPermissionScren(requireActivity(), SystemPermission.DeviceAdmin)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun openUsageStatsSettings() {
|
|
||||||
logic.platformIntegration.openSystemPermissionScren(requireActivity(), SystemPermission.UsageStats)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun openNotificationAccessSettings() {
|
|
||||||
logic.platformIntegration.openSystemPermissionScren(requireActivity(), SystemPermission.Notification)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun openDrawOverOtherAppsScreen() {
|
|
||||||
logic.platformIntegration.openSystemPermissionScren(requireActivity(), SystemPermission.Overlay)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun openAccessibilitySettings() {
|
|
||||||
logic.platformIntegration.openSystemPermissionScren(requireActivity(), SystemPermission.AccessibilityService)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun gotoNextStep() {
|
|
||||||
requireActivity().execute(UpdateStateCommand.Setup.LocalMode)
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
refreshStatus()
|
|
||||||
|
|
||||||
return binding.root
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun refreshStatus() {
|
|
||||||
val platform = logic.platformIntegration
|
|
||||||
|
|
||||||
binding.notificationAccessPermission = platform.getNotificationAccessPermissionStatus()
|
|
||||||
binding.protectionLevel = platform.getCurrentProtectionLevel()
|
|
||||||
binding.usageStatsAccess = platform.getForegroundAppPermissionStatus()
|
|
||||||
binding.overlayPermission = platform.getDrawOverOtherAppsPermissionStatus(true)
|
|
||||||
binding.accessibilityServiceEnabled = platform.isAccessibilityServiceEnabled()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onResume() {
|
|
||||||
super.onResume()
|
|
||||||
|
|
||||||
// this additionally schedules it
|
|
||||||
refreshStatusRunnable.run()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onPause() {
|
|
||||||
super.onPause()
|
|
||||||
|
|
||||||
Threads.mainThreadHandler.removeCallbacks(refreshStatusRunnable)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
interface SetupDevicePermissionsHandlers {
|
|
||||||
fun manageDeviceAdmin()
|
|
||||||
fun openUsageStatsSettings()
|
|
||||||
fun openNotificationAccessSettings()
|
|
||||||
fun openDrawOverOtherAppsScreen()
|
|
||||||
fun openAccessibilitySettings()
|
|
||||||
fun gotoNextStep()
|
|
||||||
fun helpUsageStatsAccess()
|
|
||||||
fun helpNotificationAccess()
|
|
||||||
fun helpDrawOverOtherApps()
|
|
||||||
fun helpAccesibility()
|
|
||||||
}
|
|
|
@ -0,0 +1,65 @@
|
||||||
|
/*
|
||||||
|
* 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.setup
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.rememberScrollState
|
||||||
|
import androidx.compose.foundation.verticalScroll
|
||||||
|
import androidx.compose.material.Button
|
||||||
|
import androidx.compose.material.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import io.timelimit.android.R
|
||||||
|
import io.timelimit.android.integration.platform.RuntimePermissionStatus
|
||||||
|
import io.timelimit.android.ui.manage.device.manage.permission.PermissionScreen
|
||||||
|
import io.timelimit.android.ui.manage.device.manage.permission.PermissionScreenContent
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun SetupDevicePermissionsScreen(
|
||||||
|
content: PermissionScreenContent,
|
||||||
|
next: () -> Unit,
|
||||||
|
modifier: Modifier
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
Modifier
|
||||||
|
.verticalScroll(rememberScrollState())
|
||||||
|
.padding(8.dp),
|
||||||
|
verticalArrangement = Arrangement.spacedBy(8.dp)
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
stringResource(R.string.setup_device_permissions_text_short),
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
|
modifier = Modifier.fillMaxWidth()
|
||||||
|
)
|
||||||
|
|
||||||
|
PermissionScreen(content)
|
||||||
|
|
||||||
|
Button(
|
||||||
|
onClick = next,
|
||||||
|
modifier = Modifier.align(Alignment.End),
|
||||||
|
enabled = content.status.usageStats != RuntimePermissionStatus.NotGranted
|
||||||
|
) {
|
||||||
|
Text(stringResource(R.string.wiazrd_next))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,410 +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.setup.SetupDevicePermissionsFragment">
|
|
||||||
|
|
||||||
<data>
|
|
||||||
<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.setup.SetupDevicePermissionsHandlers" />
|
|
||||||
|
|
||||||
<import type="android.view.View" />
|
|
||||||
<import type="io.timelimit.android.integration.platform.RuntimePermissionStatus" />
|
|
||||||
<import type="io.timelimit.android.integration.platform.NewPermissionStatus" />
|
|
||||||
<import type="io.timelimit.android.integration.platform.ProtectionLevel" />
|
|
||||||
</data>
|
|
||||||
|
|
||||||
<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:id="@+id/usage_stats_access_title"
|
|
||||||
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/device_admin_btn"
|
|
||||||
style="?materialButtonOutlinedStyle"
|
|
||||||
android:layout_marginEnd="8dp"
|
|
||||||
android:text="@string/manage_device_permission_btn_modify"
|
|
||||||
android:layout_gravity="end"
|
|
||||||
android:onClick="@{() -> handlers.openUsageStatsSettings()}"
|
|
||||||
android:enabled="@{usageStatsAccess != RuntimePermissionStatus.NotRequired}"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content">
|
|
||||||
<requestFocus />
|
|
||||||
</Button>
|
|
||||||
|
|
||||||
</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: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:nextFocusUp="@id/usage_stats_access_btn"
|
|
||||||
android:nextFocusDown="@id/notification_access_title"
|
|
||||||
style="?materialButtonOutlinedStyle"
|
|
||||||
android:layout_marginEnd="8dp"
|
|
||||||
android:text="@string/manage_device_permission_btn_modify"
|
|
||||||
android:layout_gravity="end"
|
|
||||||
android:onClick="@{() -> handlers.manageDeviceAdmin()}"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
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/device_admin_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:text="@string/manage_device_permission_btn_modify"
|
|
||||||
android:layout_gravity="end"
|
|
||||||
android:onClick="@{() -> handlers.openNotificationAccessSettings()}"
|
|
||||||
android:enabled="@{notificationAccessPermission != NewPermissionStatus.NotSupported}"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
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:text="@string/manage_device_permission_btn_modify"
|
|
||||||
android:layout_gravity="end"
|
|
||||||
android:onClick="@{() -> handlers.openDrawOverOtherAppsScreen()}"
|
|
||||||
android:enabled="@{overlayPermission != RuntimePermissionStatus.NotRequired}"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
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/next_btn"
|
|
||||||
style="?materialButtonOutlinedStyle"
|
|
||||||
android:layout_marginEnd="8dp"
|
|
||||||
android:text="@string/manage_device_permission_btn_modify"
|
|
||||||
android:layout_gravity="end"
|
|
||||||
android:onClick="@{() -> handlers.openAccessibilitySettings()}"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
</androidx.cardview.widget.CardView>
|
|
||||||
|
|
||||||
<Button
|
|
||||||
android:nextFocusUp="@id/accessibility_btn"
|
|
||||||
android:id="@+id/next_btn"
|
|
||||||
android:layout_gravity="end"
|
|
||||||
android:layout_marginTop="8dp"
|
|
||||||
android:layout_marginEnd="4dp"
|
|
||||||
android:enabled="@{usageStatsAccess != RuntimePermissionStatus.NotGranted}"
|
|
||||||
android:onClick="@{() -> handlers.gotoNextStep()}"
|
|
||||||
android:text="@string/wiazrd_next"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
</ScrollView>
|
|
||||||
</layout>
|
|
|
@ -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) && (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) && (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) && (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>
|
|
|
@ -84,15 +84,6 @@
|
||||||
android:name="parentId"
|
android:name="parentId"
|
||||||
app:argType="string" />
|
app:argType="string" />
|
||||||
</fragment>
|
</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
|
<fragment
|
||||||
android:id="@+id/manageDeviceFeaturesFragment"
|
android:id="@+id/manageDeviceFeaturesFragment"
|
||||||
android:name="io.timelimit.android.ui.manage.device.manage.feature.ManageDeviceFeaturesFragment"
|
android:name="io.timelimit.android.ui.manage.device.manage.feature.ManageDeviceFeaturesFragment"
|
||||||
|
|
|
@ -981,9 +981,10 @@
|
||||||
Diese Berechtigung kann nur durch TimeLimit bzw. ein Elternteil, das TimeLimit deinstalliert, deaktiviert werden.
|
Diese Berechtigung kann nur durch TimeLimit bzw. ein Elternteil, das TimeLimit deinstalliert, deaktiviert werden.
|
||||||
</string>
|
</string>
|
||||||
|
|
||||||
<string name="manage_device_permission_open_at_target_device">
|
<string name="manage_device_permission_device_owner_unsupported">Die Geräte-Besitzer-Berechtigung
|
||||||
Öffnen Sie diesen Bildschirm am entsprechenden Gerät, um die Berechtigung festzulegen
|
ist etwas anderes und ist nicht verfügbar.</string>
|
||||||
</string>
|
<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_status_granted">Die Berechtigung wurde erteilt</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_granted">Die Berechtigung wurde nicht erteilt</string>
|
||||||
|
@ -992,6 +993,12 @@
|
||||||
|
|
||||||
<string name="manage_device_permission_btn_modify">Ändern</string>
|
<string name="manage_device_permission_btn_modify">Ändern</string>
|
||||||
|
|
||||||
|
<string name="manage_device_permission_link_only_info">Apps können sich keine Berechtigungen selbst erteilen.
|
||||||
|
Sie werden stets zu einer Systemapp weitergeleitet, um die Änderung durchzuführen.
|
||||||
|
Dadurch können die Berechtigungen nicht mittels Fernsteuerung geändert werden.
|
||||||
|
Um Änderungen ohne Passwort zu verhindern müssen Sie die entsprechende Systemapp sperren.
|
||||||
|
</string>
|
||||||
|
|
||||||
<string name="manage_device_permission_no_ui_usage_stats_text">
|
<string name="manage_device_permission_no_ui_usage_stats_text">
|
||||||
Dieses Gerät hat keine grafische Oberfläche zum Erteilen dieser Berechtigung - diese kann
|
Dieses Gerät hat keine grafische Oberfläche zum Erteilen dieser Berechtigung - diese kann
|
||||||
nur von einem Computer mittels ADB geändert werden.
|
nur von einem Computer mittels ADB geändert werden.
|
||||||
|
@ -1005,6 +1012,20 @@
|
||||||
\n\nDie Berechtigung kann über die Deinstallations-Funktion von TimeLimit deaktiviert werden.
|
\n\nDie Berechtigung kann über die Deinstallations-Funktion von TimeLimit deaktiviert werden.
|
||||||
</string>
|
</string>
|
||||||
|
|
||||||
|
<string name="manage_device_permission_goal_limit_title">Zeitbeschränkungen ermöglichen</string>
|
||||||
|
<string name="manage_device_permission_goal_floating_window">Sperren von Apps in Fenstern ermöglichen</string>
|
||||||
|
<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>
|
||||||
|
<string name="manage_device_permission_goal_reached_by_old_android">benötigt wegen alter Android-Version Nichts weiter</string>
|
||||||
|
<string name="manage_device_permission_goal_needs_device_owner">benötigt Geräte-Besitzer-Berechtigung</string>
|
||||||
|
<string name="manage_device_permission_goal_reached">Ziel erreicht</string>
|
||||||
|
<string name="manage_device_permission_goal_missed">Ziel nicht erreicht</string>
|
||||||
|
|
||||||
<string name="manage_device_downgrade_title">Downgrade</string>
|
<string name="manage_device_downgrade_title">Downgrade</string>
|
||||||
<string name="manage_device_downgrade_text">Auf diesem Gerät wurde eine neuere Version von TimeLimit durch eine ältere ersetzt</string>
|
<string name="manage_device_downgrade_text">Auf diesem Gerät wurde eine neuere Version von TimeLimit durch eine ältere ersetzt</string>
|
||||||
|
|
||||||
|
@ -1387,12 +1408,8 @@
|
||||||
<string name="set_password_view_label_password_repeat">Neues Passwort wiederholen</string>
|
<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="set_password_view_checkbox_no_password">Passwortschutz nicht verwenden</string>
|
||||||
|
|
||||||
<string name="setup_device_permissions_text">
|
<string name="setup_device_permissions_text_short">
|
||||||
TimeLimit benötigt einige Berechtigungen, um funktionieren zu können.
|
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>
|
||||||
|
|
||||||
<string name="setup_device_needs_parent">Ein Elternteil muss sich anmelden, um die Einrichtung abzuschließen</string>
|
<string name="setup_device_needs_parent">Ein Elternteil muss sich anmelden, um die Einrichtung abzuschließen</string>
|
||||||
|
|
|
@ -80,6 +80,8 @@
|
||||||
(<a href="https://github.com/JetBrains/kotlin/blob/master/license/LICENSE.txt">Apache License, Version 2.0</a>)
|
(<a href="https://github.com/JetBrains/kotlin/blob/master/license/LICENSE.txt">Apache License, Version 2.0</a>)
|
||||||
\nAndroid X
|
\nAndroid X
|
||||||
(<a href="https://www.apache.org/licenses/LICENSE-2.0">Apache License, Version 2.0</a>)
|
(<a href="https://www.apache.org/licenses/LICENSE-2.0">Apache License, Version 2.0</a>)
|
||||||
|
\n<a href="https://github.com/google/accompanist">Google Accompanist</a>
|
||||||
|
(<a href="https://github.com/google/accompanist/blob/main/LICENSE">Apache License, Version 2.0</a>)
|
||||||
\nAndroid Navigation Component
|
\nAndroid Navigation Component
|
||||||
(<a href="https://www.apache.org/licenses/LICENSE-2.0">Apache License, Version 2.0</a>)
|
(<a href="https://www.apache.org/licenses/LICENSE-2.0">Apache License, Version 2.0</a>)
|
||||||
\nAndroid Room
|
\nAndroid Room
|
||||||
|
@ -1029,9 +1031,10 @@
|
||||||
This permission can only be disabled by TimeLimit/ a parent which uninstalls TimeLimit.
|
This permission can only be disabled by TimeLimit/ a parent which uninstalls TimeLimit.
|
||||||
</string>
|
</string>
|
||||||
|
|
||||||
<string name="manage_device_permission_open_at_target_device">
|
<string name="manage_device_permission_device_owner_unsupported">The device owner permission
|
||||||
Open the screen at the other device to modify the permissions
|
is something different and not available.</string>
|
||||||
</string>
|
<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_status_granted">The permission was granted</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_granted">The permission was not granted</string>
|
||||||
|
@ -1040,6 +1043,12 @@
|
||||||
|
|
||||||
<string name="manage_device_permission_btn_modify">Modify</string>
|
<string name="manage_device_permission_btn_modify">Modify</string>
|
||||||
|
|
||||||
|
<string name="manage_device_permission_link_only_info">Apps can not grant permissions themself.
|
||||||
|
You are redirected to a system App to change the permission.
|
||||||
|
Due to that, you can not change the permissions remotely.
|
||||||
|
To protect the setting, you have to block the corresponding system App.
|
||||||
|
</string>
|
||||||
|
|
||||||
<string name="manage_device_permission_no_ui_usage_stats_text">
|
<string name="manage_device_permission_no_ui_usage_stats_text">
|
||||||
This device does not allow changing this permission graphically. You can only
|
This device does not allow changing this permission graphically. You can only
|
||||||
change it from a PC using ADB.
|
change it from a PC using ADB.
|
||||||
|
@ -1053,6 +1062,20 @@
|
||||||
\n\nYou can disable it by using the uninstall feature of TimeLimit.
|
\n\nYou can disable it by using the uninstall feature of TimeLimit.
|
||||||
</string>
|
</string>
|
||||||
|
|
||||||
|
<string name="manage_device_permission_goal_limit_title">Allow applying limits</string>
|
||||||
|
<string name="manage_device_permission_goal_floating_window">Allow blocking floating windows</string>
|
||||||
|
<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>
|
||||||
|
<string name="manage_device_permission_goal_reached_by_old_android">needs nothing due to old Android version</string>
|
||||||
|
<string name="manage_device_permission_goal_needs_device_owner">needs device owner</string>
|
||||||
|
<string name="manage_device_permission_goal_reached">goal reached</string>
|
||||||
|
<string name="manage_device_permission_goal_missed">goal not reached</string>
|
||||||
|
|
||||||
<string name="manage_device_downgrade_title">Downgrade</string>
|
<string name="manage_device_downgrade_title">Downgrade</string>
|
||||||
<string name="manage_device_downgrade_text">On this device, a newer version of TimeLimit was replaced by an older one</string>
|
<string name="manage_device_downgrade_text">On this device, a newer version of TimeLimit was replaced by an older one</string>
|
||||||
|
|
||||||
|
@ -1432,12 +1455,8 @@
|
||||||
<string name="set_password_view_label_password_repeat">Repeat new password</string>
|
<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="set_password_view_checkbox_no_password">Disable password protection</string>
|
||||||
|
|
||||||
<string name="setup_device_permissions_text">
|
<string name="setup_device_permissions_text_short">
|
||||||
TimeLimit needs some permissions to work.
|
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>
|
||||||
|
|
||||||
<string name="setup_device_needs_parent">A parent must authenticate to finish the setup</string>
|
<string name="setup_device_needs_parent">A parent must authenticate to finish the setup</string>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue