mirror of
https://codeberg.org/timelimit/timelimit-android.git
synced 2025-10-03 01:39:22 +02:00
Adjust for Android U
This commit is contained in:
parent
37b3ea08e9
commit
43db6f4d2e
14 changed files with 74 additions and 18 deletions
|
@ -27,7 +27,7 @@ android {
|
|||
defaultConfig {
|
||||
applicationId "io.timelimit.android"
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 33
|
||||
targetSdkVersion 34
|
||||
versionCode 205
|
||||
versionName "6.14.2"
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
tools:ignore="ProtectedPermissions" />
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_SYSTEM_EXEMPTED" />
|
||||
<uses-permission android:name="android.permission.CALL_PHONE" />
|
||||
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
|
||||
<!-- for the categories which are limited to a wifi network -->
|
||||
|
@ -136,6 +137,7 @@
|
|||
</receiver>
|
||||
|
||||
<service
|
||||
android:foregroundServiceType="systemExempted"
|
||||
android:name=".integration.platform.android.BackgroundService"
|
||||
android:exported="false" />
|
||||
|
||||
|
|
|
@ -361,7 +361,13 @@ data class Device(
|
|||
(currentProtectionLevel != ProtectionLevel.DeviceOwner)
|
||||
|
||||
@Transient
|
||||
val isImportant = hasAnyManipulation || missingPermissionAtQOrLater || didReportUninstall
|
||||
val missingDeviceAdminPermission =
|
||||
platformType == DevicePlatform.ANDROID &&
|
||||
platformLevel >= 2 &&
|
||||
currentProtectionLevel == ProtectionLevel.None
|
||||
|
||||
@Transient
|
||||
val isImportant = hasAnyManipulation || missingPermissionAtQOrLater || missingDeviceAdminPermission || didReportUninstall
|
||||
}
|
||||
|
||||
enum class NetworkTime {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* TimeLimit Copyright <C> 2019 - 2022 Jonas Lochmann
|
||||
* 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
|
||||
|
@ -18,12 +18,17 @@ package io.timelimit.android.integration.platform.android
|
|||
import android.app.ActivityManager
|
||||
import android.app.NotificationManager
|
||||
import android.app.Service
|
||||
import android.app.admin.DevicePolicyManager
|
||||
import android.content.ComponentName
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Build
|
||||
import android.os.Build.VERSION
|
||||
import android.os.Build.VERSION_CODES
|
||||
import android.os.IBinder
|
||||
import androidx.core.app.NotificationCompat
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.content.getSystemService
|
||||
import io.timelimit.android.R
|
||||
import io.timelimit.android.integration.platform.AppStatusMessage
|
||||
import io.timelimit.android.logic.DefaultAppLogic
|
||||
|
@ -35,9 +40,10 @@ class BackgroundService: Service() {
|
|||
fun setStatusMessage(status: AppStatusMessage?, context: Context) {
|
||||
val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||
val intent = Intent(context, BackgroundService::class.java)
|
||||
val isRestricted = isBackgroundActivityRestricted(context)
|
||||
|
||||
if (status != null) {
|
||||
if (isBackgroundActivityRestricted(context)) {
|
||||
if (isRestricted) {
|
||||
val notification = buildNotification(status, context)
|
||||
|
||||
notificationManager.notify(NotificationIds.APP_STATUS, notification)
|
||||
|
@ -50,7 +56,7 @@ class BackgroundService: Service() {
|
|||
} else {
|
||||
context.stopService(intent)
|
||||
|
||||
if (isBackgroundActivityRestricted(context)) {
|
||||
if (isRestricted) {
|
||||
notificationManager.cancel(NotificationIds.APP_STATUS)
|
||||
}
|
||||
}
|
||||
|
@ -59,11 +65,19 @@ class BackgroundService: Service() {
|
|||
fun isBackgroundActivityRestricted(context: Context): Boolean {
|
||||
val activityManager = context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||
return activityManager.isBackgroundRestricted
|
||||
} else {
|
||||
return false
|
||||
if (VERSION.SDK_INT >= VERSION_CODES.P) {
|
||||
if (activityManager.isBackgroundRestricted) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
if (VERSION.SDK_INT >= VERSION_CODES.UPSIDE_DOWN_CAKE) {
|
||||
if (!context.getSystemService<DevicePolicyManager>()!!.isAdminActive(ComponentName(context, AdminReceiver::class.java))) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
private fun buildNotification(appStatusMessage: AppStatusMessage, context: Context) = NotificationCompat.Builder(context, NotificationChannels.APP_STATUS)
|
||||
|
|
|
@ -37,6 +37,7 @@ import io.timelimit.android.extensions.MinuteOfDay
|
|||
import io.timelimit.android.extensions.nextBlockedMinuteOfWeek
|
||||
import io.timelimit.android.integration.platform.*
|
||||
import io.timelimit.android.integration.platform.android.AccessibilityService
|
||||
import io.timelimit.android.integration.platform.android.BackgroundService
|
||||
import io.timelimit.android.livedata.*
|
||||
import io.timelimit.android.logic.blockingreason.AppBaseHandling
|
||||
import io.timelimit.android.logic.blockingreason.CategoryHandlingCache
|
||||
|
@ -178,6 +179,7 @@ class BackgroundTaskLogic(val appLogic: AppLogic) {
|
|||
|
||||
private suspend fun backgroundServiceLoop() {
|
||||
val realTime = RealTime.newInstance()
|
||||
var skipBackgroundRestrictionChecks = 0
|
||||
|
||||
while (true) {
|
||||
val backgroundServiceInterval = when (slowMainLoop) {
|
||||
|
@ -244,6 +246,24 @@ class BackgroundTaskLogic(val appLogic: AppLogic) {
|
|||
|
||||
// loop logic
|
||||
try {
|
||||
if (skipBackgroundRestrictionChecks <= 0) {
|
||||
if (BackgroundService.isBackgroundActivityRestricted(appLogic.context)) {
|
||||
commitUsedTimeUpdaters()
|
||||
undisturbedCategoryUsageCounter.reset()
|
||||
|
||||
appLogic.platformIntegration.setShowBlockingOverlay(false)
|
||||
appLogic.platformIntegration.setAppStatusMessage(
|
||||
AppStatusMessage(
|
||||
appLogic.context.getString(R.string.background_logic_error),
|
||||
appLogic.context.getString(R.string.background_logic_error_permission)
|
||||
)
|
||||
)
|
||||
|
||||
appLogic.timeApi.sleep(BACKGROUND_SERVICE_INTERVAL_LONG)
|
||||
continue
|
||||
} else skipBackgroundRestrictionChecks = 128
|
||||
} else skipBackgroundRestrictionChecks--
|
||||
|
||||
// get the current time
|
||||
appLogic.realTimeLogic.getRealTime(realTime)
|
||||
|
||||
|
|
|
@ -69,7 +69,7 @@ class NFCU2FManager (val parent: U2fManager, context: Context) {
|
|||
private val nfcReceiverIntent = PendingIntent.getBroadcast(
|
||||
context,
|
||||
PendingIntentIds.U2F_NFC_DISCOVERY,
|
||||
Intent(nfcReceiverAction),
|
||||
Intent(nfcReceiverAction).setPackage(context.packageName),
|
||||
PendingIntentIds.PENDING_INTENT_FLAGS_ALLOW_MUTATION
|
||||
)
|
||||
|
||||
|
|
|
@ -77,7 +77,7 @@ class UsbU2FManager (val parent: U2fManager, context: Context) {
|
|||
private val permissionResponseIntent = PendingIntent.getBroadcast(
|
||||
context,
|
||||
PendingIntentIds.U2F_USB_RESPONSE,
|
||||
Intent(permissionResponseAction),
|
||||
Intent(permissionResponseAction).setPackage(context.packageName),
|
||||
PendingIntentIds.PENDING_INTENT_FLAGS_ALLOW_MUTATION
|
||||
)
|
||||
|
||||
|
|
|
@ -38,7 +38,8 @@ 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),
|
||||
(!status.isQOrLater || status.overlay == RuntimePermissionStatus.Granted || status.accessibility) &&
|
||||
(status.androidPlatformLevel < 2 || status.protectionLevel != ProtectionLevel.None)
|
||||
) {
|
||||
if (status.usageStats != RuntimePermissionStatus.NotRequired) FlowRow {
|
||||
Text(stringResource(R.string.manage_device_permission_goal_needs))
|
||||
|
@ -52,8 +53,13 @@ fun PermissionGoals(status: PermissionScreenContent.Status) {
|
|||
PermissionIcon(SystemPermission.AccessibilityService, status.accessibility)
|
||||
}
|
||||
|
||||
if (status.usageStats == RuntimePermissionStatus.NotRequired && !status.isQOrLater)
|
||||
Text(stringResource(R.string.manage_device_permission_goal_reached_by_old_android))
|
||||
FlowRow {
|
||||
Text(stringResource(
|
||||
if (status.androidPlatformLevel >= 2) R.string.manage_device_permission_goal_needs
|
||||
else R.string.manage_device_permission_goal_eventually_needs_future
|
||||
))
|
||||
PermissionIcon(SystemPermission.DeviceAdmin, status.protectionLevel != ProtectionLevel.None)
|
||||
}
|
||||
}
|
||||
|
||||
PermissionGoal(
|
||||
|
|
|
@ -32,7 +32,8 @@ data class PermissionScreenContent(
|
|||
val usageStats: RuntimePermissionStatus,
|
||||
val overlay: RuntimePermissionStatus,
|
||||
val accessibility: Boolean,
|
||||
val isQOrLater: Boolean
|
||||
val isQOrLater: Boolean,
|
||||
val androidPlatformLevel: Int
|
||||
)
|
||||
|
||||
data class Dialog(
|
||||
|
|
|
@ -412,7 +412,9 @@ object OverviewHandling {
|
|||
data class UserList(val list: List<UserItem>, val canAdd: Boolean, val canShowMore: Boolean)
|
||||
data class DeviceItem(val device: Device, val userName: String?, val userType: UserType?, val isCurrentDevice: Boolean, val isConnected: Boolean) {
|
||||
val isMissingRequiredPermission = userType == UserType.Child && (
|
||||
device.currentUsageStatsPermission == RuntimePermissionStatus.NotGranted || device.missingPermissionAtQOrLater)
|
||||
device.currentUsageStatsPermission == RuntimePermissionStatus.NotGranted ||
|
||||
device.missingPermissionAtQOrLater ||
|
||||
device.missingDeviceAdminPermission)
|
||||
}
|
||||
data class DeviceList(val list: List<DeviceItem>, val canAdd: Boolean, val canShowMore: OverviewState.DeviceList?)
|
||||
}
|
|
@ -16,6 +16,7 @@
|
|||
package io.timelimit.android.ui.model.managedevice
|
||||
|
||||
import io.timelimit.android.data.model.Device
|
||||
import io.timelimit.android.data.model.DevicePlatform
|
||||
import io.timelimit.android.logic.AppLogic
|
||||
import io.timelimit.android.ui.manage.device.manage.permission.PermissionScreenContent
|
||||
import io.timelimit.android.ui.model.ActivityCommand
|
||||
|
@ -82,7 +83,8 @@ object ManageDevicePermissions {
|
|||
usageStats = device.currentUsageStatsPermission,
|
||||
overlay = device.currentOverlayPermission,
|
||||
accessibility = device.accessibilityServiceEnabled,
|
||||
isQOrLater = device.qOrLater
|
||||
isQOrLater = device.qOrLater,
|
||||
androidPlatformLevel = if (device.platformType == DevicePlatform.ANDROID) device.platformLevel else 0
|
||||
)
|
||||
}.distinctUntilChanged()
|
||||
}
|
|
@ -108,7 +108,8 @@ object SetupLocalModePermissions {
|
|||
usageStats = platformIntegration.getForegroundAppPermissionStatus(),
|
||||
overlay = platformIntegration.getDrawOverOtherAppsPermissionStatus(true),
|
||||
accessibility = platformIntegration.isAccessibilityServiceEnabled(),
|
||||
isQOrLater = AndroidVersion.qOrLater
|
||||
isQOrLater = AndroidVersion.qOrLater,
|
||||
androidPlatformLevel = AndroidVersion.platformLevel
|
||||
)
|
||||
)
|
||||
|
||||
|
|
|
@ -1033,6 +1033,7 @@
|
|||
<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_eventually_needs_future">benötigt zukünftig</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>
|
||||
|
|
|
@ -1082,6 +1082,7 @@
|
|||
<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_eventually_needs_future">needs in the future</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>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue