From 43db6f4d2ec266a68fb9dc355a3de80307304518 Mon Sep 17 00:00:00 2001 From: Jonas Lochmann Date: Mon, 12 Jun 2023 02:00:00 +0200 Subject: [PATCH] Adjust for Android U --- app/build.gradle | 2 +- app/src/main/AndroidManifest.xml | 2 ++ .../io/timelimit/android/data/model/Device.kt | 8 +++++- .../platform/android/BackgroundService.kt | 28 ++++++++++++++----- .../android/logic/BackgroundTaskLogic.kt | 20 +++++++++++++ .../android/u2f/nfc/NFCU2FManager.kt | 2 +- .../android/u2f/usb/UsbU2FManager.kt | 2 +- .../manage/permission/PermissionGoals.kt | 12 ++++++-- .../permission/PermissionScreenContent.kt | 3 +- .../android/ui/model/main/OverviewHandling.kt | 4 ++- .../managedevice/ManageDevicePermissions.kt | 4 ++- .../model/setup/SetupLocalModePermissions.kt | 3 +- app/src/main/res/values-de/strings.xml | 1 + app/src/main/res/values/strings.xml | 1 + 14 files changed, 74 insertions(+), 18 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 3c839f6..4de830e 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -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" diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index bc3219f..77bb3c4 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -30,6 +30,7 @@ tools:ignore="ProtectedPermissions" /> + @@ -136,6 +137,7 @@ diff --git a/app/src/main/java/io/timelimit/android/data/model/Device.kt b/app/src/main/java/io/timelimit/android/data/model/Device.kt index 2fcc822..a11a0d5 100644 --- a/app/src/main/java/io/timelimit/android/data/model/Device.kt +++ b/app/src/main/java/io/timelimit/android/data/model/Device.kt @@ -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 { diff --git a/app/src/main/java/io/timelimit/android/integration/platform/android/BackgroundService.kt b/app/src/main/java/io/timelimit/android/integration/platform/android/BackgroundService.kt index 63b6d8d..8e5c4e4 100644 --- a/app/src/main/java/io/timelimit/android/integration/platform/android/BackgroundService.kt +++ b/app/src/main/java/io/timelimit/android/integration/platform/android/BackgroundService.kt @@ -1,5 +1,5 @@ /* - * TimeLimit Copyright 2019 - 2022 Jonas Lochmann + * TimeLimit Copyright 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()!!.isAdminActive(ComponentName(context, AdminReceiver::class.java))) { + return true + } + } + + return false } private fun buildNotification(appStatusMessage: AppStatusMessage, context: Context) = NotificationCompat.Builder(context, NotificationChannels.APP_STATUS) diff --git a/app/src/main/java/io/timelimit/android/logic/BackgroundTaskLogic.kt b/app/src/main/java/io/timelimit/android/logic/BackgroundTaskLogic.kt index 5c3238c..e209331 100644 --- a/app/src/main/java/io/timelimit/android/logic/BackgroundTaskLogic.kt +++ b/app/src/main/java/io/timelimit/android/logic/BackgroundTaskLogic.kt @@ -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) diff --git a/app/src/main/java/io/timelimit/android/u2f/nfc/NFCU2FManager.kt b/app/src/main/java/io/timelimit/android/u2f/nfc/NFCU2FManager.kt index 7e454fd..3081e02 100644 --- a/app/src/main/java/io/timelimit/android/u2f/nfc/NFCU2FManager.kt +++ b/app/src/main/java/io/timelimit/android/u2f/nfc/NFCU2FManager.kt @@ -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 ) diff --git a/app/src/main/java/io/timelimit/android/u2f/usb/UsbU2FManager.kt b/app/src/main/java/io/timelimit/android/u2f/usb/UsbU2FManager.kt index 7592185..ae0b5b0 100644 --- a/app/src/main/java/io/timelimit/android/u2f/usb/UsbU2FManager.kt +++ b/app/src/main/java/io/timelimit/android/u2f/usb/UsbU2FManager.kt @@ -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 ) diff --git a/app/src/main/java/io/timelimit/android/ui/manage/device/manage/permission/PermissionGoals.kt b/app/src/main/java/io/timelimit/android/ui/manage/device/manage/permission/PermissionGoals.kt index 3595951..155b7fc 100644 --- a/app/src/main/java/io/timelimit/android/ui/manage/device/manage/permission/PermissionGoals.kt +++ b/app/src/main/java/io/timelimit/android/ui/manage/device/manage/permission/PermissionGoals.kt @@ -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( diff --git a/app/src/main/java/io/timelimit/android/ui/manage/device/manage/permission/PermissionScreenContent.kt b/app/src/main/java/io/timelimit/android/ui/manage/device/manage/permission/PermissionScreenContent.kt index ee518b0..16c63f5 100644 --- a/app/src/main/java/io/timelimit/android/ui/manage/device/manage/permission/PermissionScreenContent.kt +++ b/app/src/main/java/io/timelimit/android/ui/manage/device/manage/permission/PermissionScreenContent.kt @@ -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( diff --git a/app/src/main/java/io/timelimit/android/ui/model/main/OverviewHandling.kt b/app/src/main/java/io/timelimit/android/ui/model/main/OverviewHandling.kt index 1028329..6818135 100644 --- a/app/src/main/java/io/timelimit/android/ui/model/main/OverviewHandling.kt +++ b/app/src/main/java/io/timelimit/android/ui/model/main/OverviewHandling.kt @@ -412,7 +412,9 @@ object OverviewHandling { data class UserList(val list: List, 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, val canAdd: Boolean, val canShowMore: OverviewState.DeviceList?) } \ No newline at end of file diff --git a/app/src/main/java/io/timelimit/android/ui/model/managedevice/ManageDevicePermissions.kt b/app/src/main/java/io/timelimit/android/ui/model/managedevice/ManageDevicePermissions.kt index 52a96ea..9718948 100644 --- a/app/src/main/java/io/timelimit/android/ui/model/managedevice/ManageDevicePermissions.kt +++ b/app/src/main/java/io/timelimit/android/ui/model/managedevice/ManageDevicePermissions.kt @@ -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() } \ No newline at end of file diff --git a/app/src/main/java/io/timelimit/android/ui/model/setup/SetupLocalModePermissions.kt b/app/src/main/java/io/timelimit/android/ui/model/setup/SetupLocalModePermissions.kt index 0a23bd0..400de7b 100644 --- a/app/src/main/java/io/timelimit/android/ui/model/setup/SetupLocalModePermissions.kt +++ b/app/src/main/java/io/timelimit/android/ui/model/setup/SetupLocalModePermissions.kt @@ -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 ) ) diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index bbd8214..22ea0f9 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -1033,6 +1033,7 @@ in der aktuellen Umgebung nicht verfügbar öffnen Sie diese Ansicht am entsprechenden Gerät benötigt evtl. + benötigt zukünftig benötigt oder benötigt wegen alter Android-Version Nichts weiter diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 803cb62..35ba748 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1082,6 +1082,7 @@ unavailable in the current environment open this screen at the device eventually needs + needs in the future needs or needs nothing due to old Android version