mirror of
https://codeberg.org/timelimit/timelimit-android.git
synced 2025-10-03 17:59:51 +02:00
Squashed commit of the following:
commit db5e372421bd6f3731085f702423221ce64e10f5
Author: Jonas L <jonas@determapp.de>
Date: Mon Mar 25 00:00:00 2019 +0000
Use home button before opening lockscreen in all cases
commit 19c64cbbfd29060cc6e4abc08fa7eb0de841f46c
Author: Jonas L <jonas@determapp.de>
Date: Mon Mar 25 00:00:00 2019 +0000
Add new database schema file
commit 244162a7654f966ec55e08e185e1bccb59461c7e
Author: Jonas L <jonas@determapp.de>
Date: Mon Mar 25 00:00:00 2019 +0000
Fix showing if accessibility service enabled
commit 6f562ec8ff95a797e150b5bb990f0586f6e372dc
Author: Jonas L <jonas@determapp.de>
Date: Mon Mar 25 00:00:00 2019 +0000
Fix compiling
commit c6464c2114230e9bef40ff8425f3d28fce1ff120
Author: Jonas L <jonas@determapp.de>
Date: Mon Mar 25 00:00:00 2019 +0000
Add managing accessibility service to device config screen
commit f13925c805a03f570cfe8fdae6ab2ce5f80644e4
Author: Jonas L <jonas@determapp.de>
Date: Mon Mar 25 00:00:00 2019 +0000
Add accessibility service to device setup
commit 39ff80da6553efe228fd429b2f39d6e8fca6f4f1
Author: Jonas L <jonas@determapp.de>
Date: Mon Mar 25 00:00:00 2019 +0000
Squashed commit of the following:
commit 52fa115b2f
Author: Jonas L <jonas@determapp.de>
Date: Mon Mar 25 00:00:00 2019 +0000
Squashed commit of the following:
commit bb5606826a0b108df334968657d87fff3762afe8
Author: Jonas L <jonas@determapp.de>
Date: Mon Mar 25 00:00:00 2019 +0000
Hide overlay permission
commit a0c0fe3624a86d9d7eee2c0486fa086a4a5ee064
Author: Jonas L <jonas@determapp.de>
Date: Mon Mar 25 00:00:00 2019 +0000
Add warning to overlay if shown for a longer time
commit 0705ee57374a0257e97f5dfd4bbde3428ec58933
Author: Jonas L <jonas@determapp.de>
Date: Mon Mar 25 00:00:00 2019 +0000
Allow ignoring warning of overlay manipulation
commit 2685be2de0bdb2eb56b2514cc8a6dfc05eec923e
Author: Jonas L <jonas@determapp.de>
Date: Mon Mar 25 00:00:00 2019 +0000
Add overlay permission to update device status action
commit dde4f800b8ab1331a22b6a702341edd3d595748c
Author: Jonas L <jonas@determapp.de>
Date: Mon Mar 25 00:00:00 2019 +0000
Add draw over other apps permission to device screen
commit 0d54e76cc23cb3f534c88533ce962cb84f68f105
Author: Jonas L <jonas@determapp.de>
Date: Mon Mar 25 00:00:00 2019 +0000
Add column for the overlay permission
commit 42da690ae823a9fead00e98d7a2d74ea7df406fe
Author: Jonas L <jonas@determapp.de>
Date: Mon Mar 25 00:00:00 2019 +0000
Add UI to grant overlay permission to the setup screen
commit 5b8697bc79c773666c2ca2be3201f0998da64169
Author: Jonas L <jonas@determapp.de>
Date: Mon Mar 25 00:00:00 2019 +0000
Add using draw over other apps permission
commit bcfb6a779f15732c948833a03b330539ea4694a6
Author: Jonas L <jonas@determapp.de>
Date: Mon Mar 25 00:00:00 2019 +0000
Add basically popup window blocking workaround
This commit is contained in:
parent
52fa115b2f
commit
399c39628b
27 changed files with 1056 additions and 47 deletions
662
app/schemas/io.timelimit.android.data.RoomDatabase/14.json
Normal file
662
app/schemas/io.timelimit.android.data.RoomDatabase/14.json
Normal file
|
@ -0,0 +1,662 @@
|
|||
{
|
||||
"formatVersion": 1,
|
||||
"database": {
|
||||
"version": 14,
|
||||
"identityHash": "d340606d3cf1eaf15eaf78b3e448a0d7",
|
||||
"entities": [
|
||||
{
|
||||
"tableName": "user",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `name` TEXT NOT NULL, `password` TEXT NOT NULL, `second_password_salt` TEXT NOT NULL, `type` TEXT NOT NULL, `timezone` TEXT NOT NULL, `disable_limits_until` INTEGER NOT NULL, `mail` TEXT NOT NULL, `current_device` TEXT NOT NULL, `category_for_not_assigned_apps` TEXT NOT NULL, `relax_primary_device` INTEGER NOT NULL, `mail_notification_flags` INTEGER NOT NULL, PRIMARY KEY(`id`))",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "id",
|
||||
"columnName": "id",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "name",
|
||||
"columnName": "name",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "password",
|
||||
"columnName": "password",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "secondPasswordSalt",
|
||||
"columnName": "second_password_salt",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "type",
|
||||
"columnName": "type",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "timeZone",
|
||||
"columnName": "timezone",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "disableLimitsUntil",
|
||||
"columnName": "disable_limits_until",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "mail",
|
||||
"columnName": "mail",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "currentDevice",
|
||||
"columnName": "current_device",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "categoryForNotAssignedApps",
|
||||
"columnName": "category_for_not_assigned_apps",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "relaxPrimaryDevice",
|
||||
"columnName": "relax_primary_device",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "mailNotificationFlags",
|
||||
"columnName": "mail_notification_flags",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"columnNames": [
|
||||
"id"
|
||||
],
|
||||
"autoGenerate": false
|
||||
},
|
||||
"indices": [],
|
||||
"foreignKeys": []
|
||||
},
|
||||
{
|
||||
"tableName": "device",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `name` TEXT NOT NULL, `model` TEXT NOT NULL, `added_at` INTEGER NOT NULL, `current_user_id` TEXT NOT NULL, `apps_version` TEXT NOT NULL, `network_time` TEXT NOT NULL, `current_protection_level` TEXT NOT NULL, `highest_permission_level` TEXT NOT NULL, `current_usage_stats_permission` TEXT NOT NULL, `highest_usage_stats_permission` TEXT NOT NULL, `current_notification_access_permission` TEXT NOT NULL, `highest_notification_access_permission` TEXT NOT NULL, `current_app_version` INTEGER NOT NULL, `highest_app_version` INTEGER NOT NULL, `tried_disabling_device_admin` INTEGER NOT NULL, `did_reboot` INTEGER NOT NULL, `had_manipulation` INTEGER NOT NULL, `did_report_uninstall` INTEGER NOT NULL, `is_user_kept_signed_in` INTEGER NOT NULL, `show_device_connected` INTEGER NOT NULL, `default_user` TEXT NOT NULL, `default_user_timeout` INTEGER NOT NULL, `consider_reboot_manipulation` INTEGER NOT NULL, `current_overlay_permission` TEXT NOT NULL, `highest_overlay_permission` TEXT NOT NULL, `current_accessibility_service_permission` INTEGER NOT NULL, `was_accessibility_service_permission` INTEGER NOT NULL, PRIMARY KEY(`id`))",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "id",
|
||||
"columnName": "id",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "name",
|
||||
"columnName": "name",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "model",
|
||||
"columnName": "model",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "addedAt",
|
||||
"columnName": "added_at",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "currentUserId",
|
||||
"columnName": "current_user_id",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "installedAppsVersion",
|
||||
"columnName": "apps_version",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "networkTime",
|
||||
"columnName": "network_time",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "currentProtectionLevel",
|
||||
"columnName": "current_protection_level",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "highestProtectionLevel",
|
||||
"columnName": "highest_permission_level",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "currentUsageStatsPermission",
|
||||
"columnName": "current_usage_stats_permission",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "highestUsageStatsPermission",
|
||||
"columnName": "highest_usage_stats_permission",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "currentNotificationAccessPermission",
|
||||
"columnName": "current_notification_access_permission",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "highestNotificationAccessPermission",
|
||||
"columnName": "highest_notification_access_permission",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "currentAppVersion",
|
||||
"columnName": "current_app_version",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "highestAppVersion",
|
||||
"columnName": "highest_app_version",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "manipulationTriedDisablingDeviceAdmin",
|
||||
"columnName": "tried_disabling_device_admin",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "manipulationDidReboot",
|
||||
"columnName": "did_reboot",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "hadManipulation",
|
||||
"columnName": "had_manipulation",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "didReportUninstall",
|
||||
"columnName": "did_report_uninstall",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "isUserKeptSignedIn",
|
||||
"columnName": "is_user_kept_signed_in",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "showDeviceConnected",
|
||||
"columnName": "show_device_connected",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "defaultUser",
|
||||
"columnName": "default_user",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "defaultUserTimeout",
|
||||
"columnName": "default_user_timeout",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "considerRebootManipulation",
|
||||
"columnName": "consider_reboot_manipulation",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "currentOverlayPermission",
|
||||
"columnName": "current_overlay_permission",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "highestOverlayPermission",
|
||||
"columnName": "highest_overlay_permission",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "accessibilityServiceEnabled",
|
||||
"columnName": "current_accessibility_service_permission",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "wasAccessibilityServiceEnabled",
|
||||
"columnName": "was_accessibility_service_permission",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"columnNames": [
|
||||
"id"
|
||||
],
|
||||
"autoGenerate": false
|
||||
},
|
||||
"indices": [],
|
||||
"foreignKeys": []
|
||||
},
|
||||
{
|
||||
"tableName": "app",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`device_id` TEXT NOT NULL, `package_name` TEXT NOT NULL, `title` TEXT NOT NULL, `launchable` INTEGER NOT NULL, `recommendation` TEXT NOT NULL, PRIMARY KEY(`device_id`, `package_name`))",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "deviceId",
|
||||
"columnName": "device_id",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "packageName",
|
||||
"columnName": "package_name",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "title",
|
||||
"columnName": "title",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "isLaunchable",
|
||||
"columnName": "launchable",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "recommendation",
|
||||
"columnName": "recommendation",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"columnNames": [
|
||||
"device_id",
|
||||
"package_name"
|
||||
],
|
||||
"autoGenerate": false
|
||||
},
|
||||
"indices": [
|
||||
{
|
||||
"name": "index_app_device_id",
|
||||
"unique": false,
|
||||
"columnNames": [
|
||||
"device_id"
|
||||
],
|
||||
"createSql": "CREATE INDEX `index_app_device_id` ON `${TABLE_NAME}` (`device_id`)"
|
||||
},
|
||||
{
|
||||
"name": "index_app_package_name",
|
||||
"unique": false,
|
||||
"columnNames": [
|
||||
"package_name"
|
||||
],
|
||||
"createSql": "CREATE INDEX `index_app_package_name` ON `${TABLE_NAME}` (`package_name`)"
|
||||
}
|
||||
],
|
||||
"foreignKeys": []
|
||||
},
|
||||
{
|
||||
"tableName": "category_app",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`category_id` TEXT NOT NULL, `package_name` TEXT NOT NULL, PRIMARY KEY(`category_id`, `package_name`))",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "categoryId",
|
||||
"columnName": "category_id",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "packageName",
|
||||
"columnName": "package_name",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"columnNames": [
|
||||
"category_id",
|
||||
"package_name"
|
||||
],
|
||||
"autoGenerate": false
|
||||
},
|
||||
"indices": [
|
||||
{
|
||||
"name": "index_category_app_category_id",
|
||||
"unique": false,
|
||||
"columnNames": [
|
||||
"category_id"
|
||||
],
|
||||
"createSql": "CREATE INDEX `index_category_app_category_id` ON `${TABLE_NAME}` (`category_id`)"
|
||||
},
|
||||
{
|
||||
"name": "index_category_app_package_name",
|
||||
"unique": false,
|
||||
"columnNames": [
|
||||
"package_name"
|
||||
],
|
||||
"createSql": "CREATE INDEX `index_category_app_package_name` ON `${TABLE_NAME}` (`package_name`)"
|
||||
}
|
||||
],
|
||||
"foreignKeys": []
|
||||
},
|
||||
{
|
||||
"tableName": "category",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `child_id` TEXT NOT NULL, `title` TEXT NOT NULL, `blocked_times` TEXT NOT NULL, `extra_time` INTEGER NOT NULL, `temporarily_blocked` INTEGER NOT NULL, `base_version` TEXT NOT NULL, `apps_version` TEXT NOT NULL, `rules_version` TEXT NOT NULL, `usedtimes_version` TEXT NOT NULL, `parent_category_id` TEXT NOT NULL, `block_all_notifications` INTEGER NOT NULL, PRIMARY KEY(`id`))",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "id",
|
||||
"columnName": "id",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "childId",
|
||||
"columnName": "child_id",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "title",
|
||||
"columnName": "title",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "blockedMinutesInWeek",
|
||||
"columnName": "blocked_times",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "extraTimeInMillis",
|
||||
"columnName": "extra_time",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "temporarilyBlocked",
|
||||
"columnName": "temporarily_blocked",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "baseVersion",
|
||||
"columnName": "base_version",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "assignedAppsVersion",
|
||||
"columnName": "apps_version",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "timeLimitRulesVersion",
|
||||
"columnName": "rules_version",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "usedTimesVersion",
|
||||
"columnName": "usedtimes_version",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "parentCategoryId",
|
||||
"columnName": "parent_category_id",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "blockAllNotifications",
|
||||
"columnName": "block_all_notifications",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"columnNames": [
|
||||
"id"
|
||||
],
|
||||
"autoGenerate": false
|
||||
},
|
||||
"indices": [],
|
||||
"foreignKeys": []
|
||||
},
|
||||
{
|
||||
"tableName": "used_time",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`day_of_epoch` INTEGER NOT NULL, `used_time` INTEGER NOT NULL, `category_id` TEXT NOT NULL, PRIMARY KEY(`category_id`, `day_of_epoch`))",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "dayOfEpoch",
|
||||
"columnName": "day_of_epoch",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "usedMillis",
|
||||
"columnName": "used_time",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "categoryId",
|
||||
"columnName": "category_id",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"columnNames": [
|
||||
"category_id",
|
||||
"day_of_epoch"
|
||||
],
|
||||
"autoGenerate": false
|
||||
},
|
||||
"indices": [],
|
||||
"foreignKeys": []
|
||||
},
|
||||
{
|
||||
"tableName": "time_limit_rule",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `category_id` TEXT NOT NULL, `apply_to_extra_time_usage` INTEGER NOT NULL, `day_mask` INTEGER NOT NULL, `max_time` INTEGER NOT NULL, PRIMARY KEY(`id`))",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "id",
|
||||
"columnName": "id",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "categoryId",
|
||||
"columnName": "category_id",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "applyToExtraTimeUsage",
|
||||
"columnName": "apply_to_extra_time_usage",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "dayMask",
|
||||
"columnName": "day_mask",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "maximumTimeInMillis",
|
||||
"columnName": "max_time",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"columnNames": [
|
||||
"id"
|
||||
],
|
||||
"autoGenerate": false
|
||||
},
|
||||
"indices": [],
|
||||
"foreignKeys": []
|
||||
},
|
||||
{
|
||||
"tableName": "config",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `value` TEXT NOT NULL, PRIMARY KEY(`id`))",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "key",
|
||||
"columnName": "id",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "value",
|
||||
"columnName": "value",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"columnNames": [
|
||||
"id"
|
||||
],
|
||||
"autoGenerate": false
|
||||
},
|
||||
"indices": [],
|
||||
"foreignKeys": []
|
||||
},
|
||||
{
|
||||
"tableName": "temporarily_allowed_app",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`device_id` TEXT NOT NULL, `package_name` TEXT NOT NULL, PRIMARY KEY(`device_id`, `package_name`))",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "deviceId",
|
||||
"columnName": "device_id",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "packageName",
|
||||
"columnName": "package_name",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"columnNames": [
|
||||
"device_id",
|
||||
"package_name"
|
||||
],
|
||||
"autoGenerate": false
|
||||
},
|
||||
"indices": [],
|
||||
"foreignKeys": []
|
||||
},
|
||||
{
|
||||
"tableName": "pending_sync_action",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`sequence_number` INTEGER NOT NULL, `action` TEXT NOT NULL, `integrity` TEXT NOT NULL, `scheduled_for_upload` INTEGER NOT NULL, `type` TEXT NOT NULL, `user_id` TEXT NOT NULL, PRIMARY KEY(`sequence_number`))",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "sequenceNumber",
|
||||
"columnName": "sequence_number",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "encodedAction",
|
||||
"columnName": "action",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "integrity",
|
||||
"columnName": "integrity",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "scheduledForUpload",
|
||||
"columnName": "scheduled_for_upload",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "type",
|
||||
"columnName": "type",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "userId",
|
||||
"columnName": "user_id",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"columnNames": [
|
||||
"sequence_number"
|
||||
],
|
||||
"autoGenerate": false
|
||||
},
|
||||
"indices": [
|
||||
{
|
||||
"name": "index_pending_sync_action_scheduled_for_upload",
|
||||
"unique": false,
|
||||
"columnNames": [
|
||||
"scheduled_for_upload"
|
||||
],
|
||||
"createSql": "CREATE INDEX `index_pending_sync_action_scheduled_for_upload` ON `${TABLE_NAME}` (`scheduled_for_upload`)"
|
||||
}
|
||||
],
|
||||
"foreignKeys": []
|
||||
}
|
||||
],
|
||||
"setupQueries": [
|
||||
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
|
||||
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, \"d340606d3cf1eaf15eaf78b3e448a0d7\")"
|
||||
]
|
||||
}
|
||||
}
|
|
@ -115,6 +115,18 @@
|
|||
</intent-filter>
|
||||
</service>
|
||||
|
||||
<service android:name=".integration.platform.android.AccessibilityService"
|
||||
android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
|
||||
|
||||
<intent-filter>
|
||||
<action android:name="android.accessibilityservice.AccessibilityService" />
|
||||
</intent-filter>
|
||||
|
||||
<meta-data android:name="android.accessibilityservice"
|
||||
android:resource="@xml/accesibility" />
|
||||
|
||||
</service>
|
||||
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
|
|
|
@ -98,4 +98,11 @@ object DatabaseMigrations {
|
|||
database.execSQL("ALTER TABLE `device` ADD COLUMN `highest_overlay_permission` TEXT NOT NULL DEFAULT \"not granted\"")
|
||||
}
|
||||
}
|
||||
|
||||
val MIGRATE_TO_V14 = object: Migration(13, 14) {
|
||||
override fun migrate(database: SupportSQLiteDatabase) {
|
||||
database.execSQL("ALTER TABLE `device` ADD COLUMN `current_accessibility_service_permission` INTEGER NOT NULL DEFAULT 0")
|
||||
database.execSQL("ALTER TABLE `device` ADD COLUMN `was_accessibility_service_permission` INTEGER NOT NULL DEFAULT 0")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@ import io.timelimit.android.data.model.*
|
|||
ConfigurationItem::class,
|
||||
TemporarilyAllowedApp::class,
|
||||
PendingSyncAction::class
|
||||
], version = 13)
|
||||
], version = 14)
|
||||
abstract class RoomDatabase: RoomDatabase(), io.timelimit.android.data.Database {
|
||||
companion object {
|
||||
private val lock = Object()
|
||||
|
@ -79,7 +79,8 @@ abstract class RoomDatabase: RoomDatabase(), io.timelimit.android.data.Database
|
|||
DatabaseMigrations.MIGRATE_TO_V10,
|
||||
DatabaseMigrations.MIGRATE_TO_V11,
|
||||
DatabaseMigrations.MIGRATE_TO_V12,
|
||||
DatabaseMigrations.MIGRATE_TO_V13
|
||||
DatabaseMigrations.MIGRATE_TO_V13,
|
||||
DatabaseMigrations.MIGRATE_TO_V14
|
||||
)
|
||||
.build()
|
||||
}
|
||||
|
|
|
@ -82,7 +82,11 @@ data class Device(
|
|||
@ColumnInfo(name = "current_overlay_permission")
|
||||
val currentOverlayPermission: RuntimePermissionStatus,
|
||||
@ColumnInfo(name = "highest_overlay_permission")
|
||||
val highestOverlayPermission: RuntimePermissionStatus
|
||||
val highestOverlayPermission: RuntimePermissionStatus,
|
||||
@ColumnInfo(name = "current_accessibility_service_permission")
|
||||
val accessibilityServiceEnabled: Boolean,
|
||||
@ColumnInfo(name = "was_accessibility_service_permission")
|
||||
val wasAccessibilityServiceEnabled: Boolean
|
||||
): JsonSerializable {
|
||||
companion object {
|
||||
private const val ID = "id"
|
||||
|
@ -111,6 +115,8 @@ data class Device(
|
|||
private const val CONSIDER_REBOOT_A_MANIPULATION = "cram"
|
||||
private const val CURRENT_OVERLAY_PERMISSION = "cop"
|
||||
private const val HIGHEST_OVERLAY_PERMISSION = "hop"
|
||||
private const val ACCESSIBILITY_SERVICE_ENABLED = "ase"
|
||||
private const val WAS_ACCESSIBILITY_SERVICE_ENABLED = "wase"
|
||||
|
||||
fun parse(reader: JsonReader): Device {
|
||||
var id: String? = null
|
||||
|
@ -139,6 +145,8 @@ data class Device(
|
|||
var considerRebootManipulation = false
|
||||
var currentOverlayPermission = RuntimePermissionStatus.NotGranted
|
||||
var highestOverlayPermission = RuntimePermissionStatus.NotGranted
|
||||
var accessibilityServiceEnabled = false
|
||||
var wasAccessibilityServiceEnabled = false
|
||||
|
||||
reader.beginObject()
|
||||
|
||||
|
@ -170,6 +178,8 @@ data class Device(
|
|||
CONSIDER_REBOOT_A_MANIPULATION -> considerRebootManipulation = reader.nextBoolean()
|
||||
CURRENT_OVERLAY_PERMISSION -> currentOverlayPermission = RuntimePermissionStatusUtil.parse(reader.nextString())
|
||||
HIGHEST_OVERLAY_PERMISSION -> highestOverlayPermission = RuntimePermissionStatusUtil.parse(reader.nextString())
|
||||
ACCESSIBILITY_SERVICE_ENABLED -> accessibilityServiceEnabled = reader.nextBoolean()
|
||||
WAS_ACCESSIBILITY_SERVICE_ENABLED -> wasAccessibilityServiceEnabled = reader.nextBoolean()
|
||||
else -> reader.skipValue()
|
||||
}
|
||||
}
|
||||
|
@ -202,7 +212,9 @@ data class Device(
|
|||
defaultUserTimeout = defaultUserTimeout,
|
||||
considerRebootManipulation = considerRebootManipulation,
|
||||
currentOverlayPermission = currentOverlayPermission,
|
||||
highestOverlayPermission = highestOverlayPermission
|
||||
highestOverlayPermission = highestOverlayPermission,
|
||||
accessibilityServiceEnabled = accessibilityServiceEnabled,
|
||||
wasAccessibilityServiceEnabled = wasAccessibilityServiceEnabled
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -268,6 +280,8 @@ data class Device(
|
|||
writer.name(CONSIDER_REBOOT_A_MANIPULATION).value(considerRebootManipulation)
|
||||
writer.name(CURRENT_OVERLAY_PERMISSION).value(RuntimePermissionStatusUtil.serialize(currentOverlayPermission))
|
||||
writer.name(HIGHEST_OVERLAY_PERMISSION).value(RuntimePermissionStatusUtil.serialize(highestOverlayPermission))
|
||||
writer.name(ACCESSIBILITY_SERVICE_ENABLED).value(accessibilityServiceEnabled)
|
||||
writer.name(WAS_ACCESSIBILITY_SERVICE_ENABLED).value(wasAccessibilityServiceEnabled)
|
||||
|
||||
writer.endObject()
|
||||
}
|
||||
|
@ -282,6 +296,8 @@ data class Device(
|
|||
val manipulationOfAppVersion = currentAppVersion != highestAppVersion
|
||||
@Transient
|
||||
val manipulationOfOverlayPermission = currentOverlayPermission != highestOverlayPermission
|
||||
@Transient
|
||||
val manipulationOfAccessibilityService = accessibilityServiceEnabled != wasAccessibilityServiceEnabled
|
||||
|
||||
@Transient
|
||||
val hasActiveManipulationWarning = manipulationOfProtectionLevel ||
|
||||
|
@ -290,7 +306,8 @@ data class Device(
|
|||
manipulationOfAppVersion ||
|
||||
manipulationTriedDisablingDeviceAdmin ||
|
||||
manipulationDidReboot ||
|
||||
manipulationOfOverlayPermission
|
||||
manipulationOfOverlayPermission ||
|
||||
manipulationOfAccessibilityService
|
||||
|
||||
@Transient
|
||||
val hasAnyManipulation = hasActiveManipulationWarning || hadManipulation
|
||||
|
|
|
@ -32,6 +32,7 @@ abstract class PlatformIntegration(
|
|||
abstract fun getDrawOverOtherAppsPermissionStatus(): RuntimePermissionStatus
|
||||
abstract fun getNotificationAccessPermissionStatus(): NewPermissionStatus
|
||||
abstract fun getOverlayPermissionStatus(): RuntimePermissionStatus
|
||||
abstract fun isAccessibilityServiceEnabled(): Boolean
|
||||
abstract fun disableDeviceAdmin()
|
||||
abstract fun trySetLockScreenPassword(password: String): Boolean
|
||||
// this must have a fallback if the permission is not granted
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* TimeLimit Copyright <C> 2019 Jonas Lochmann
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package io.timelimit.android.integration.platform.android
|
||||
|
||||
import android.accessibilityservice.AccessibilityService
|
||||
import android.view.accessibility.AccessibilityEvent
|
||||
import io.timelimit.android.logic.DefaultAppLogic
|
||||
|
||||
class AccessibilityService: AccessibilityService() {
|
||||
companion object {
|
||||
var instance: io.timelimit.android.integration.platform.android.AccessibilityService? = null
|
||||
}
|
||||
|
||||
override fun onServiceConnected() {
|
||||
super.onServiceConnected()
|
||||
|
||||
instance = this
|
||||
DefaultAppLogic.with(this) // init
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
|
||||
instance = null
|
||||
}
|
||||
|
||||
override fun onAccessibilityEvent(event: AccessibilityEvent?) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
override fun onInterrupt() {
|
||||
// ignore
|
||||
}
|
||||
|
||||
fun showHomescreen() {
|
||||
performGlobalAction(GLOBAL_ACTION_HOME)
|
||||
}
|
||||
}
|
|
@ -140,6 +140,28 @@ class AndroidIntegration(context: Context): PlatformIntegration(maximumProtectio
|
|||
|
||||
override fun getOverlayPermissionStatus(): RuntimePermissionStatus = overlay.getOverlayPermissionStatus()
|
||||
|
||||
override fun isAccessibilityServiceEnabled(): Boolean {
|
||||
val service = context.packageName + "/" + AccessibilityService::class.java.canonicalName
|
||||
|
||||
val accessibilityEnabled = try {
|
||||
Settings.Secure.getInt(context.contentResolver, Settings.Secure.ACCESSIBILITY_ENABLED)
|
||||
} catch (ex: Settings.SettingNotFoundException) {
|
||||
0
|
||||
}
|
||||
|
||||
if (accessibilityEnabled == 1) {
|
||||
val enabledServicesString = Settings.Secure.getString(context.contentResolver, Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES)
|
||||
|
||||
if (!enabledServicesString.isNullOrEmpty()) {
|
||||
if (enabledServicesString.split(":").contains(service)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
override fun trySetLockScreenPassword(password: String): Boolean {
|
||||
if (BuildConfig.DEBUG) {
|
||||
Log.d(LOG_TAG, "set password")
|
||||
|
|
|
@ -65,6 +65,10 @@ class DummyIntegration(
|
|||
return RuntimePermissionStatus.NotRequired
|
||||
}
|
||||
|
||||
override fun isAccessibilityServiceEnabled(): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun trySetLockScreenPassword(password: String): Boolean {
|
||||
return false // it failed
|
||||
}
|
||||
|
|
|
@ -97,7 +97,9 @@ class AppSetupLogic(private val appLogic: AppLogic) {
|
|||
defaultUserTimeout = 0,
|
||||
considerRebootManipulation = false,
|
||||
currentOverlayPermission = RuntimePermissionStatus.NotGranted,
|
||||
highestOverlayPermission = RuntimePermissionStatus.NotGranted
|
||||
highestOverlayPermission = RuntimePermissionStatus.NotGranted,
|
||||
accessibilityServiceEnabled = false,
|
||||
wasAccessibilityServiceEnabled = false
|
||||
)
|
||||
|
||||
appLogic.database.device().addDeviceSync(device)
|
||||
|
|
|
@ -31,11 +31,13 @@ import io.timelimit.android.date.DateInTimezone
|
|||
import io.timelimit.android.date.getMinuteOfWeek
|
||||
import io.timelimit.android.integration.platform.AppStatusMessage
|
||||
import io.timelimit.android.integration.platform.ProtectionLevel
|
||||
import io.timelimit.android.integration.platform.android.AccessibilityService
|
||||
import io.timelimit.android.integration.platform.android.AndroidIntegrationApps
|
||||
import io.timelimit.android.livedata.*
|
||||
import io.timelimit.android.sync.actions.UpdateDeviceStatusAction
|
||||
import io.timelimit.android.sync.actions.apply.ApplyActionUtil
|
||||
import io.timelimit.android.util.TimeTextUtil
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
import java.util.*
|
||||
|
@ -134,6 +136,22 @@ class BackgroundTaskLogic(val appLogic: AppLogic) {
|
|||
|
||||
private val appTitleCache = QueryAppTitleCache(appLogic.platformIntegration)
|
||||
|
||||
private suspend fun openLockscreen(blockedAppPackageName: String) {
|
||||
appLogic.platformIntegration.setAppStatusMessage(AppStatusMessage(
|
||||
title = appTitleCache.query(blockedAppPackageName),
|
||||
text = appLogic.context.getString(R.string.background_logic_opening_lockscreen)
|
||||
))
|
||||
|
||||
appLogic.platformIntegration.setShowBlockingOverlay(true)
|
||||
|
||||
if (appLogic.platformIntegration.isAccessibilityServiceEnabled()) {
|
||||
AccessibilityService.instance?.showHomescreen()
|
||||
delay(100)
|
||||
}
|
||||
|
||||
appLogic.platformIntegration.showAppLockScreen(blockedAppPackageName)
|
||||
}
|
||||
|
||||
private suspend fun backgroundServiceLoop() {
|
||||
val realTime = RealTime.newInstance()
|
||||
|
||||
|
@ -257,22 +275,12 @@ class BackgroundTaskLogic(val appLogic: AppLogic) {
|
|||
if (category == null) {
|
||||
usedTimeUpdateHelper?.commit(appLogic)
|
||||
|
||||
appLogic.platformIntegration.setAppStatusMessage(AppStatusMessage(
|
||||
title = appTitleCache.query(foregroundAppPackageName),
|
||||
text = appLogic.context.getString(R.string.background_logic_opening_lockscreen)
|
||||
))
|
||||
appLogic.platformIntegration.setSuspendedApps(listOf(foregroundAppPackageName), true)
|
||||
appLogic.platformIntegration.showAppLockScreen(foregroundAppPackageName)
|
||||
appLogic.platformIntegration.setShowBlockingOverlay(true)
|
||||
openLockscreen(foregroundAppPackageName)
|
||||
} else if (category.temporarilyBlocked or (parentCategory?.temporarilyBlocked == true)) {
|
||||
usedTimeUpdateHelper?.commit(appLogic)
|
||||
|
||||
appLogic.platformIntegration.setAppStatusMessage(AppStatusMessage(
|
||||
title = appTitleCache.query(foregroundAppPackageName),
|
||||
text = appLogic.context.getString(R.string.background_logic_opening_lockscreen)
|
||||
))
|
||||
appLogic.platformIntegration.showAppLockScreen(foregroundAppPackageName)
|
||||
appLogic.platformIntegration.setShowBlockingOverlay(true)
|
||||
openLockscreen(foregroundAppPackageName)
|
||||
} else {
|
||||
// disable time limits temporarily feature
|
||||
if (realTime.shouldTrustTimeTemporarily && nowTimestamp < deviceUserEntry.disableLimitsUntil) {
|
||||
|
@ -297,12 +305,7 @@ class BackgroundTaskLogic(val appLogic: AppLogic) {
|
|||
) {
|
||||
usedTimeUpdateHelper?.commit(appLogic)
|
||||
|
||||
appLogic.platformIntegration.setAppStatusMessage(AppStatusMessage(
|
||||
title = appTitleCache.query(foregroundAppPackageName),
|
||||
text = appLogic.context.getString(R.string.background_logic_opening_lockscreen)
|
||||
))
|
||||
appLogic.platformIntegration.showAppLockScreen(foregroundAppPackageName)
|
||||
appLogic.platformIntegration.setShowBlockingOverlay(true)
|
||||
openLockscreen(foregroundAppPackageName)
|
||||
} else {
|
||||
// check time limits
|
||||
val rules = timeLimitRules.get(category.id).waitForNonNullValue()
|
||||
|
@ -325,12 +328,7 @@ class BackgroundTaskLogic(val appLogic: AppLogic) {
|
|||
if (!isCurrentDevice) {
|
||||
usedTimeUpdateHelper?.commit(appLogic)
|
||||
|
||||
appLogic.platformIntegration.setAppStatusMessage(AppStatusMessage(
|
||||
title = appTitleCache.query(foregroundAppPackageName),
|
||||
text = appLogic.context.getString(R.string.background_logic_opening_lockscreen)
|
||||
))
|
||||
appLogic.platformIntegration.showAppLockScreen(foregroundAppPackageName)
|
||||
appLogic.platformIntegration.setShowBlockingOverlay(true)
|
||||
openLockscreen(foregroundAppPackageName)
|
||||
} else if (realTime.shouldTrustTimeTemporarily) {
|
||||
val usedTimes = usedTimesOfCategoryAndWeekByFirstDayOfWeek.get(Pair(category.id, nowDate.dayOfEpoch - nowDate.dayOfWeek)).waitForNonNullValue()
|
||||
val parentUsedTimes = parentCategory?.let {
|
||||
|
@ -439,25 +437,14 @@ class BackgroundTaskLogic(val appLogic: AppLogic) {
|
|||
|
||||
newUsedTimeItemBatchUpdateHelper.commit(appLogic)
|
||||
|
||||
appLogic.platformIntegration.setAppStatusMessage(AppStatusMessage(
|
||||
title = appTitleCache.query(foregroundAppPackageName),
|
||||
text = appLogic.context.getString(R.string.background_logic_opening_lockscreen)
|
||||
))
|
||||
appLogic.platformIntegration.showAppLockScreen(foregroundAppPackageName)
|
||||
appLogic.platformIntegration.setShowBlockingOverlay(true)
|
||||
}
|
||||
openLockscreen(foregroundAppPackageName) }
|
||||
}
|
||||
} else {
|
||||
// if should not trust the time temporarily
|
||||
|
||||
usedTimeUpdateHelper?.commit(appLogic)
|
||||
|
||||
appLogic.platformIntegration.setAppStatusMessage(AppStatusMessage(
|
||||
title = appTitleCache.query(foregroundAppPackageName),
|
||||
text = appLogic.context.getString(R.string.background_logic_opening_lockscreen)
|
||||
))
|
||||
appLogic.platformIntegration.showAppLockScreen(foregroundAppPackageName)
|
||||
appLogic.platformIntegration.setShowBlockingOverlay(true)
|
||||
openLockscreen(foregroundAppPackageName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -561,6 +548,7 @@ class BackgroundTaskLogic(val appLogic: AppLogic) {
|
|||
val usageStatsPermission = appLogic.platformIntegration.getForegroundAppPermissionStatus()
|
||||
val notificationAccess = appLogic.platformIntegration.getNotificationAccessPermissionStatus()
|
||||
val overlayPermission = appLogic.platformIntegration.getOverlayPermissionStatus()
|
||||
val accessibilityService = appLogic.platformIntegration.isAccessibilityServiceEnabled()
|
||||
|
||||
var changes = UpdateDeviceStatusAction.empty
|
||||
|
||||
|
@ -592,6 +580,12 @@ class BackgroundTaskLogic(val appLogic: AppLogic) {
|
|||
)
|
||||
}
|
||||
|
||||
if (accessibilityService != deviceEntry.accessibilityServiceEnabled) {
|
||||
changes = changes.copy(
|
||||
newAccessibilityServiceEnabled = accessibilityService
|
||||
)
|
||||
}
|
||||
|
||||
if (changes != UpdateDeviceStatusAction.empty) {
|
||||
ApplyActionUtil.applyAppLogicAction(
|
||||
action = changes,
|
||||
|
|
|
@ -156,7 +156,9 @@ object ApplyServerDataStatus {
|
|||
defaultUserTimeout = newDevice.defaultUserTimeout,
|
||||
considerRebootManipulation = newDevice.considerRebootManipulation,
|
||||
currentOverlayPermission = newDevice.currentOverlayPermission,
|
||||
highestOverlayPermission = newDevice.highestOverlayPermission
|
||||
highestOverlayPermission = newDevice.highestOverlayPermission,
|
||||
accessibilityServiceEnabled = newDevice.accessibilityServiceEnabled,
|
||||
wasAccessibilityServiceEnabled = newDevice.wasAccessibilityServiceEnabled
|
||||
))
|
||||
} else {
|
||||
// eventually update old entry
|
||||
|
@ -185,7 +187,9 @@ object ApplyServerDataStatus {
|
|||
defaultUserTimeout = newDevice.defaultUserTimeout,
|
||||
considerRebootManipulation = newDevice.considerRebootManipulation,
|
||||
currentOverlayPermission = newDevice.currentOverlayPermission,
|
||||
highestOverlayPermission = newDevice.highestOverlayPermission
|
||||
highestOverlayPermission = newDevice.highestOverlayPermission,
|
||||
accessibilityServiceEnabled = newDevice.accessibilityServiceEnabled,
|
||||
wasAccessibilityServiceEnabled = newDevice.wasAccessibilityServiceEnabled
|
||||
)
|
||||
|
||||
if (updatedDeviceEntry != oldDeviceEntry) {
|
||||
|
|
|
@ -564,6 +564,7 @@ data class UpdateDeviceStatusAction(
|
|||
val newUsageStatsPermissionStatus: RuntimePermissionStatus?,
|
||||
val newNotificationAccessPermission: NewPermissionStatus?,
|
||||
val newOverlayPermission: RuntimePermissionStatus?,
|
||||
val newAccessibilityServiceEnabled: Boolean?,
|
||||
val newAppVersion: Int?,
|
||||
val didReboot: Boolean
|
||||
): AppLogicAction() {
|
||||
|
@ -573,6 +574,7 @@ data class UpdateDeviceStatusAction(
|
|||
private const val NEW_USAGE_STATS_PERMISSION_STATUS = "usageStats"
|
||||
private const val NEW_NOTIFICATION_ACCESS_PERMISSION = "notificationAccess"
|
||||
private const val NEW_OVERLAY_PERMISSION = "overlayPermission"
|
||||
private const val NEW_ACCESSIBILITY_SERVICE_ENABLED = "accessibilityServiceEnabled"
|
||||
private const val NEW_APP_VERSION = "appVersion"
|
||||
private const val DID_REBOOT = "didReboot"
|
||||
|
||||
|
@ -581,6 +583,7 @@ data class UpdateDeviceStatusAction(
|
|||
newUsageStatsPermissionStatus = null,
|
||||
newNotificationAccessPermission = null,
|
||||
newOverlayPermission = null,
|
||||
newAccessibilityServiceEnabled = null,
|
||||
newAppVersion = null,
|
||||
didReboot = false
|
||||
)
|
||||
|
@ -620,6 +623,12 @@ data class UpdateDeviceStatusAction(
|
|||
.value(RuntimePermissionStatusUtil.serialize(newOverlayPermission))
|
||||
}
|
||||
|
||||
if (newAccessibilityServiceEnabled != null) {
|
||||
writer
|
||||
.name(NEW_ACCESSIBILITY_SERVICE_ENABLED)
|
||||
.value(newAccessibilityServiceEnabled)
|
||||
}
|
||||
|
||||
if (newAppVersion != null) {
|
||||
writer.name(NEW_APP_VERSION)
|
||||
writer.value(newAppVersion)
|
||||
|
@ -641,6 +650,7 @@ data class IgnoreManipulationAction(
|
|||
val ignoreNotificationAccessManipulation: Boolean,
|
||||
val ignoreUsageStatsAccessManipulation: Boolean,
|
||||
val ignoreOverlayPermissionManipulation: Boolean,
|
||||
val ignoreAccessibilityServiceManipulation: Boolean,
|
||||
val ignoreReboot: Boolean,
|
||||
val ignoreHadManipulation: Boolean
|
||||
): ParentAction() {
|
||||
|
@ -653,6 +663,7 @@ data class IgnoreManipulationAction(
|
|||
private const val IGNORE_NOTIFICATION_ACCESS = "notification"
|
||||
private const val IGNORE_USAGE_STATS_ACCESS = "usageStats"
|
||||
private const val IGNORE_OVERLAY_PERMISSION_MANIPULATION = "overlay"
|
||||
private const val IGNORE_ACCESSIBILITY_SERVICE_MANIPULATION = "accessibilityService"
|
||||
private const val IGNORE_HAD_MANIPULATION = "hadManipulation"
|
||||
private const val IGNORE_REBOOT = "reboot"
|
||||
}
|
||||
|
@ -667,6 +678,7 @@ data class IgnoreManipulationAction(
|
|||
(!ignoreNotificationAccessManipulation) &&
|
||||
(!ignoreUsageStatsAccessManipulation) &&
|
||||
(!ignoreOverlayPermissionManipulation) &&
|
||||
(!ignoreAccessibilityServiceManipulation) &&
|
||||
(!ignoreReboot) &&
|
||||
(!ignoreHadManipulation)
|
||||
|
||||
|
@ -681,6 +693,7 @@ data class IgnoreManipulationAction(
|
|||
writer.name(IGNORE_NOTIFICATION_ACCESS).value(ignoreNotificationAccessManipulation)
|
||||
writer.name(IGNORE_USAGE_STATS_ACCESS).value(ignoreUsageStatsAccessManipulation)
|
||||
writer.name(IGNORE_OVERLAY_PERMISSION_MANIPULATION).value(ignoreOverlayPermissionManipulation)
|
||||
writer.name(IGNORE_ACCESSIBILITY_SERVICE_MANIPULATION).value(ignoreAccessibilityServiceManipulation)
|
||||
writer.name(IGNORE_HAD_MANIPULATION).value(ignoreHadManipulation)
|
||||
writer.name(IGNORE_REBOOT).value(ignoreReboot)
|
||||
|
||||
|
|
|
@ -168,6 +168,24 @@ object LocalDatabaseAppLogicActionDispatcher {
|
|||
}
|
||||
}
|
||||
|
||||
if (action.newAccessibilityServiceEnabled != null) {
|
||||
if (device.accessibilityServiceEnabled != action.newAccessibilityServiceEnabled) {
|
||||
device = device.copy(
|
||||
accessibilityServiceEnabled = action.newAccessibilityServiceEnabled
|
||||
)
|
||||
|
||||
if (action.newAccessibilityServiceEnabled) {
|
||||
device = device.copy(
|
||||
wasAccessibilityServiceEnabled = true
|
||||
)
|
||||
}
|
||||
|
||||
if (device.accessibilityServiceEnabled != device.wasAccessibilityServiceEnabled) {
|
||||
device = device.copy(hadManipulation = true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (action.newAppVersion != null) {
|
||||
if (device.currentAppVersion != action.newAppVersion) {
|
||||
device = device.copy(
|
||||
|
|
|
@ -294,6 +294,10 @@ object LocalDatabaseParentActionDispatcher {
|
|||
deviceEntry = deviceEntry.copy(highestOverlayPermission = deviceEntry.currentOverlayPermission)
|
||||
}
|
||||
|
||||
if (action.ignoreAccessibilityServiceManipulation) {
|
||||
deviceEntry = deviceEntry.copy(wasAccessibilityServiceEnabled = deviceEntry.accessibilityServiceEnabled)
|
||||
}
|
||||
|
||||
if (action.ignoreReboot) {
|
||||
deviceEntry = deviceEntry.copy(manipulationDidReboot = false)
|
||||
}
|
||||
|
|
|
@ -180,7 +180,9 @@ data class ServerDeviceData(
|
|||
val defaultUserTimeout: Int,
|
||||
val considerRebootManipulation: Boolean,
|
||||
val currentOverlayPermission: RuntimePermissionStatus,
|
||||
val highestOverlayPermission: RuntimePermissionStatus
|
||||
val highestOverlayPermission: RuntimePermissionStatus,
|
||||
val accessibilityServiceEnabled: Boolean,
|
||||
val wasAccessibilityServiceEnabled: Boolean
|
||||
) {
|
||||
companion object {
|
||||
private const val DEVICE_ID = "deviceId"
|
||||
|
@ -208,6 +210,8 @@ data class ServerDeviceData(
|
|||
private const val CONSIDER_REBOOT_MANIPULATION = "rebootIsManipulation"
|
||||
private const val CURRENT_OVERLAY_PERMISSION = "cOverlay"
|
||||
private const val HIGHEST_OVERLAY_PERMISSION = "hOverlay"
|
||||
private const val ACCESSIBILITY_SERVICE_ENABLED = "asEnabled"
|
||||
private const val WAS_ACCESSIBILITY_SERVICE_ENABLED = "wasAsEnabled"
|
||||
|
||||
fun parse(reader: JsonReader): ServerDeviceData {
|
||||
var deviceId: String? = null
|
||||
|
@ -235,6 +239,8 @@ data class ServerDeviceData(
|
|||
var considerRebootManipulation: Boolean? = null
|
||||
var currentOverlayPermission: RuntimePermissionStatus? = null
|
||||
var highestOverlayPermission: RuntimePermissionStatus? = null
|
||||
var accessibilityServiceEnabled: Boolean? = null
|
||||
var wasAccessibilityServiceEnabled: Boolean? = null
|
||||
|
||||
reader.beginObject()
|
||||
while (reader.hasNext()) {
|
||||
|
@ -264,6 +270,8 @@ data class ServerDeviceData(
|
|||
CONSIDER_REBOOT_MANIPULATION -> considerRebootManipulation = reader.nextBoolean()
|
||||
CURRENT_OVERLAY_PERMISSION -> currentOverlayPermission = RuntimePermissionStatusUtil.parse(reader.nextString())
|
||||
HIGHEST_OVERLAY_PERMISSION -> highestOverlayPermission = RuntimePermissionStatusUtil.parse(reader.nextString())
|
||||
ACCESSIBILITY_SERVICE_ENABLED -> accessibilityServiceEnabled = reader.nextBoolean()
|
||||
WAS_ACCESSIBILITY_SERVICE_ENABLED -> wasAccessibilityServiceEnabled = reader.nextBoolean()
|
||||
else -> reader.skipValue()
|
||||
}
|
||||
}
|
||||
|
@ -294,7 +302,9 @@ data class ServerDeviceData(
|
|||
defaultUserTimeout = defaultUserTimeout!!,
|
||||
considerRebootManipulation = considerRebootManipulation!!,
|
||||
currentOverlayPermission = currentOverlayPermission!!,
|
||||
highestOverlayPermission = highestOverlayPermission!!
|
||||
highestOverlayPermission = highestOverlayPermission!!,
|
||||
accessibilityServiceEnabled = accessibilityServiceEnabled!!,
|
||||
wasAccessibilityServiceEnabled = wasAccessibilityServiceEnabled!!
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -195,6 +195,13 @@ class ManageDeviceFragment : Fragment(), FragmentWithCustomTitle {
|
|||
}
|
||||
}
|
||||
|
||||
override fun openAccessibilitySettings() {
|
||||
startActivity(
|
||||
Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS)
|
||||
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
)
|
||||
}
|
||||
|
||||
override fun manageDeviceAdmin() {
|
||||
if (binding.isThisDevice == true) {
|
||||
val protectionLevel = logic.platformIntegration.getCurrentProtectionLevel()
|
||||
|
@ -279,6 +286,7 @@ class ManageDeviceFragment : Fragment(), FragmentWithCustomTitle {
|
|||
binding.notificationAccessPermission = device.currentNotificationAccessPermission
|
||||
binding.protectionLevel = device.currentProtectionLevel
|
||||
binding.overlayPermission = device.currentOverlayPermission
|
||||
binding.accessibilityServiceEnabled = device.accessibilityServiceEnabled
|
||||
binding.didAppDowngrade = device.currentAppVersion < device.highestAppVersion
|
||||
}
|
||||
})
|
||||
|
@ -365,6 +373,7 @@ interface ManageDeviceFragmentHandlers {
|
|||
fun openUsageStatsSettings()
|
||||
fun openNotificationAccessSettings()
|
||||
fun openDrawOverOtherAppsScreen()
|
||||
fun openAccessibilitySettings()
|
||||
fun manageDeviceAdmin()
|
||||
fun editDeviceTitle()
|
||||
fun showAuthenticationScreen()
|
||||
|
|
|
@ -42,6 +42,7 @@ object ManageDeviceManipulation {
|
|||
binding.hasManipulatedUsageStatsAccess = device?.manipulationOfUsageStats ?: false
|
||||
binding.hasManipulatedNotificationAccess = device?.manipulationOfNotificationAccess ?: false
|
||||
binding.hasManipulatedOverlayPermission = device?.manipulationOfOverlayPermission ?: false
|
||||
binding.hasManipulatedAccessibilityService = device?.manipulationOfAccessibilityService ?: false
|
||||
binding.hasManipulationReboot = device?.manipulationDidReboot ?: false
|
||||
binding.hasHadManipulation = (device?.hadManipulation ?: false) and (! (device?.hasActiveManipulationWarning ?: false))
|
||||
binding.hasAnyManipulation = device?.hasAnyManipulation ?: false
|
||||
|
@ -64,6 +65,7 @@ object ManageDeviceManipulation {
|
|||
binding.usageAccessCheckbox,
|
||||
binding.notificationAccessCheckbox,
|
||||
binding.overlayPermissionCheckbox,
|
||||
binding.accessibilityServiceCheckbox,
|
||||
binding.rebootCheckbox,
|
||||
binding.hadManipulationCheckbox
|
||||
)
|
||||
|
@ -83,6 +85,7 @@ object ManageDeviceManipulation {
|
|||
ignoreDeviceAdminManipulationAttempt = binding.deviceAdminDisableAttemptCheckbox.isChecked && binding.hasTriedManipulatingDeviceAdmin == true,
|
||||
ignoreDeviceAdminManipulation = binding.deviceAdminDisabledCheckbox.isChecked && binding.hasManipulatedDeviceAdmin == true,
|
||||
ignoreOverlayPermissionManipulation = binding.overlayPermissionCheckbox.isChecked && binding.hasManipulatedOverlayPermission == true,
|
||||
ignoreAccessibilityServiceManipulation = binding.accessibilityServiceCheckbox.isChecked && binding.hasManipulatedAccessibilityService == true,
|
||||
ignoreAppDowngrade = binding.appVersionCheckbox.isChecked && binding.hasManipulatedAppVersion == true,
|
||||
ignoreReboot = binding.rebootCheckbox.isChecked && binding.hasManipulationReboot == true,
|
||||
ignoreHadManipulation = binding.hadManipulationCheckbox.isChecked || (
|
||||
|
|
|
@ -99,10 +99,18 @@ class SetupDevicePermissionsFragment : Fragment() {
|
|||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
startActivity(
|
||||
Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + context!!.packageName))
|
||||
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun openAccessibilitySettings() {
|
||||
startActivity(
|
||||
Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS)
|
||||
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
)
|
||||
}
|
||||
|
||||
override fun gotoNextStep() {
|
||||
navigation.safeNavigate(
|
||||
SetupDevicePermissionsFragmentDirections
|
||||
|
@ -124,6 +132,7 @@ class SetupDevicePermissionsFragment : Fragment() {
|
|||
binding.protectionLevel = platform.getCurrentProtectionLevel()
|
||||
binding.usageStatsAccess = platform.getForegroundAppPermissionStatus()
|
||||
binding.overlayPermission = platform.getOverlayPermissionStatus()
|
||||
binding.accessibilityServiceEnabled = platform.isAccessibilityServiceEnabled()
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
|
@ -138,5 +147,6 @@ interface SetupDevicePermissionsHandlers {
|
|||
fun openUsageStatsSettings()
|
||||
fun openNotificationAccessSettings()
|
||||
fun openDrawOverOtherAppsScreen()
|
||||
fun openAccessibilitySettings()
|
||||
fun gotoNextStep()
|
||||
}
|
||||
|
|
|
@ -58,6 +58,10 @@
|
|||
name="overlayPermission"
|
||||
type="RuntimePermissionStatus" />
|
||||
|
||||
<variable
|
||||
name="accessibilityServiceEnabled"
|
||||
type="boolean" />
|
||||
|
||||
<variable
|
||||
name="handlers"
|
||||
type="io.timelimit.android.ui.manage.device.manage.ManageDeviceFragmentHandlers" />
|
||||
|
@ -461,6 +465,65 @@
|
|||
</LinearLayout>
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:onClick="@{() -> handlers.openAccessibilitySettings()}"
|
||||
android:foreground="?selectableItemBackground"
|
||||
android:clickable="@{safeUnbox(isThisDevice)}"
|
||||
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_accessibility_title"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<TextView
|
||||
android:textAppearance="?android:textAppearanceMedium"
|
||||
android:text="@string/manage_device_permission_accessibility_text"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<TextView
|
||||
android:visibility="@{accessibilityServiceEnabled == true ? View.VISIBLE : View.GONE}"
|
||||
android:textColor="@color/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:visibility="@{accessibilityServiceEnabled == false ? View.VISIBLE : View.GONE}"
|
||||
android:textColor="@color/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:visibility="@{safeUnbox(isThisDevice) ? View.VISIBLE : View.GONE}"
|
||||
android:text="@string/manage_device_permission_tap_top_open_settings"
|
||||
android:textAppearance="?android:textAppearanceSmall"
|
||||
android:layout_width="match_parent"
|
||||
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>
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:visibility="@{BuildConfig.hasServer ? View.VISIBLE : View.GONE}"
|
||||
app:cardUseCompatPadding="true"
|
||||
|
|
|
@ -34,6 +34,10 @@
|
|||
name="overlayPermission"
|
||||
type="RuntimePermissionStatus" />
|
||||
|
||||
<variable
|
||||
name="accessibilityServiceEnabled"
|
||||
type="boolean" />
|
||||
|
||||
<variable
|
||||
name="handlers"
|
||||
type="io.timelimit.android.ui.setup.SetupDevicePermissionsHandlers" />
|
||||
|
@ -293,6 +297,57 @@
|
|||
</LinearLayout>
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:onClick="@{() -> handlers.openAccessibilitySettings()}"
|
||||
android:foreground="?selectableItemBackground"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
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_accessibility_title"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<TextView
|
||||
android:textAppearance="?android:textAppearanceMedium"
|
||||
android:text="@string/manage_device_permission_accessibility_text"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<TextView
|
||||
android:visibility="@{accessibilityServiceEnabled == true ? View.VISIBLE : View.GONE}"
|
||||
android:textColor="@color/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:visibility="@{accessibilityServiceEnabled == false ? View.VISIBLE : View.GONE}"
|
||||
android:textColor="@color/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:text="@string/manage_device_permission_tap_top_open_settings"
|
||||
android:textAppearance="?android:textAppearanceSmall"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
</LinearLayout>
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="match_parent"
|
||||
|
|
|
@ -37,6 +37,10 @@
|
|||
name="hasManipulatedOverlayPermission"
|
||||
type="Boolean" />
|
||||
|
||||
<variable
|
||||
name="hasManipulatedAccessibilityService"
|
||||
type="Boolean" />
|
||||
|
||||
<variable
|
||||
name="hasManipulatedAppVersion"
|
||||
type="Boolean" />
|
||||
|
@ -118,6 +122,13 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<CheckBox
|
||||
android:visibility="@{safeUnbox(hasManipulatedAccessibilityService) ? View.VISIBLE : View.GONE}"
|
||||
android:id="@+id/accessibility_service_checkbox"
|
||||
android:text="@string/manage_device_manipulation_accessibility_service"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<CheckBox
|
||||
android:visibility="@{safeUnbox(hasManipulatedAppVersion) ? View.VISIBLE : View.GONE}"
|
||||
android:id="@+id/app_version_checkbox"
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
<string name="manage_device_manipulation_usage_stats_access">Nutzungsdatenzugriff</string>
|
||||
<string name="manage_device_manipulation_notification_access">Benachrichtigungszugriff</string>
|
||||
<string name="manage_device_manipulation_overlay_permission">Berechtigung zum Anzeigen über anderen Apps</string>
|
||||
<string name="manage_device_manipulation_accessibility_service">Bedienhilfe-Berechtigung</string>
|
||||
<string name="manage_device_manipulation_app_version">ältere App-Version installiert</string>
|
||||
<string name="manage_device_manipulation_reboot">Gerät wurde neu gestartet</string>
|
||||
<string name="manage_device_manipulation_existed">Es gab eine Manipulation, die wieder beendet wurde</string>
|
||||
|
|
|
@ -52,6 +52,12 @@
|
|||
Das Anzeigen über anderen Apps kann das Sperren in einigen Fällen verbessern.
|
||||
</string>
|
||||
|
||||
<string name="manage_device_permission_accessibility_title">Bedienhilfe</string>
|
||||
<string name="manage_device_permission_accessibility_text">
|
||||
Damit \"drückt\" TimeLimit den Home-Button, bevor der Sperrbildschirm aufgerufen wird.
|
||||
Das kann das Sperren in einigen Fällen verbessern.
|
||||
</string>
|
||||
|
||||
<string name="manage_device_permission_device_admin_title">Geräte-Administrator</string>
|
||||
<string name="manage_device_permission_device_admin_text_disabled">
|
||||
Die Geräte-Administrator-Berechtigung wurde nicht gewährt. TimeLimit kann jederzeit über die Systemeinstellungen beendet werden.
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
<string name="manage_device_manipulation_usage_stats_access">usage stats access</string>
|
||||
<string name="manage_device_manipulation_notification_access">notification access</string>
|
||||
<string name="manage_device_manipulation_overlay_permission">draw over other Apps permission</string>
|
||||
<string name="manage_device_manipulation_accessibility_service">Accessibility service permission</string>
|
||||
<string name="manage_device_manipulation_app_version">older App version installed</string>
|
||||
<string name="manage_device_manipulation_reboot">device was rebooted</string>
|
||||
<string name="manage_device_manipulation_existed">there was a manipulation which was stopped again</string>
|
||||
|
|
|
@ -52,6 +52,12 @@
|
|||
Enabling drawing on top of other Apps can improve blocking in some cases.
|
||||
</string>
|
||||
|
||||
<string name="manage_device_permission_accessibility_title">Accessibility service</string>
|
||||
<string name="manage_device_permission_accessibility_text">
|
||||
This is used to \"press\" the home button before showing the lock screen.
|
||||
This fixes blocking in some cases.
|
||||
</string>
|
||||
|
||||
<string name="manage_device_permission_device_admin_title">Device admin</string>
|
||||
<string name="manage_device_permission_device_admin_text_disabled">
|
||||
The device admin permission was not granted.
|
||||
|
|
22
app/src/main/res/xml/accesibility.xml
Normal file
22
app/src/main/res/xml/accesibility.xml
Normal file
|
@ -0,0 +1,22 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
TimeLimit Copyright <C> 2019 Jonas Lochmann
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation version 3 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
-->
|
||||
<accessibility-service
|
||||
android:description="@string/manage_device_permission_accessibility_text"
|
||||
android:accessibilityEventTypes=""
|
||||
android:accessibilityFeedbackType="feedbackGeneric"
|
||||
android:notificationTimeout="100"
|
||||
android:canRetrieveWindowContent="false"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android" />
|
Loading…
Add table
Add a link
Reference in a new issue