mirror of
https://codeberg.org/timelimit/timelimit-android.git
synced 2025-10-04 18:29:27 +02:00
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
This commit is contained in:
parent
57bfe99226
commit
52fa115b2f
30 changed files with 1144 additions and 22 deletions
|
@ -2,7 +2,7 @@
|
||||||
"formatVersion": 1,
|
"formatVersion": 1,
|
||||||
"database": {
|
"database": {
|
||||||
"version": 12,
|
"version": 12,
|
||||||
"identityHash": "6634817cfeb16e6c23aced572b2a391e",
|
"identityHash": "289393ddc0b615d627ac88802fbfb977",
|
||||||
"entities": [
|
"entities": [
|
||||||
{
|
{
|
||||||
"tableName": "user",
|
"tableName": "user",
|
||||||
|
@ -92,7 +92,7 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"tableName": "device",
|
"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, PRIMARY KEY(`id`))",
|
"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, PRIMARY KEY(`id`))",
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
"fieldPath": "id",
|
"fieldPath": "id",
|
||||||
|
@ -237,6 +237,18 @@
|
||||||
"columnName": "consider_reboot_manipulation",
|
"columnName": "consider_reboot_manipulation",
|
||||||
"affinity": "INTEGER",
|
"affinity": "INTEGER",
|
||||||
"notNull": true
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "currentOverlayPermission",
|
||||||
|
"columnName": "current_overlay_permission",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "highestOverlayPermission",
|
||||||
|
"columnName": "highest_overlay_permission",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"primaryKey": {
|
"primaryKey": {
|
||||||
|
@ -356,7 +368,7 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"tableName": "category",
|
"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, `block_all_notifications` 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, PRIMARY KEY(`id`))",
|
"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": [
|
"fields": [
|
||||||
{
|
{
|
||||||
"fieldPath": "id",
|
"fieldPath": "id",
|
||||||
|
@ -394,12 +406,6 @@
|
||||||
"affinity": "INTEGER",
|
"affinity": "INTEGER",
|
||||||
"notNull": true
|
"notNull": true
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"fieldPath": "blockAllNotifications",
|
|
||||||
"columnName": "block_all_notifications",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"fieldPath": "baseVersion",
|
"fieldPath": "baseVersion",
|
||||||
"columnName": "base_version",
|
"columnName": "base_version",
|
||||||
|
@ -429,6 +435,12 @@
|
||||||
"columnName": "parent_category_id",
|
"columnName": "parent_category_id",
|
||||||
"affinity": "TEXT",
|
"affinity": "TEXT",
|
||||||
"notNull": true
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "blockAllNotifications",
|
||||||
|
"columnName": "block_all_notifications",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"primaryKey": {
|
"primaryKey": {
|
||||||
|
@ -632,7 +644,7 @@
|
||||||
],
|
],
|
||||||
"setupQueries": [
|
"setupQueries": [
|
||||||
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
|
"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, \"6634817cfeb16e6c23aced572b2a391e\")"
|
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, \"289393ddc0b615d627ac88802fbfb977\")"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
650
app/schemas/io.timelimit.android.data.RoomDatabase/13.json
Normal file
650
app/schemas/io.timelimit.android.data.RoomDatabase/13.json
Normal file
|
@ -0,0 +1,650 @@
|
||||||
|
{
|
||||||
|
"formatVersion": 1,
|
||||||
|
"database": {
|
||||||
|
"version": 13,
|
||||||
|
"identityHash": "289393ddc0b615d627ac88802fbfb977",
|
||||||
|
"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, 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
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"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, \"289393ddc0b615d627ac88802fbfb977\")"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
|
@ -20,7 +20,6 @@
|
||||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
||||||
<uses-permission android:name="android.permission.VIBRATE" />
|
<uses-permission android:name="android.permission.VIBRATE" />
|
||||||
<!--
|
<!--
|
||||||
not used yet
|
|
||||||
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
|
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
|
||||||
-->
|
-->
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
|
|
|
@ -91,4 +91,11 @@ object DatabaseMigrations {
|
||||||
database.execSQL("ALTER TABLE `category` ADD COLUMN `block_all_notifications` INTEGER NOT NULL DEFAULT 0")
|
database.execSQL("ALTER TABLE `category` ADD COLUMN `block_all_notifications` INTEGER NOT NULL DEFAULT 0")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val MIGRATE_TO_V13 = object: Migration(12, 13) {
|
||||||
|
override fun migrate(database: SupportSQLiteDatabase) {
|
||||||
|
database.execSQL("ALTER TABLE `device` ADD COLUMN `current_overlay_permission` TEXT NOT NULL DEFAULT \"not granted\"")
|
||||||
|
database.execSQL("ALTER TABLE `device` ADD COLUMN `highest_overlay_permission` TEXT NOT NULL DEFAULT \"not granted\"")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,7 +32,7 @@ import io.timelimit.android.data.model.*
|
||||||
ConfigurationItem::class,
|
ConfigurationItem::class,
|
||||||
TemporarilyAllowedApp::class,
|
TemporarilyAllowedApp::class,
|
||||||
PendingSyncAction::class
|
PendingSyncAction::class
|
||||||
], version = 12)
|
], version = 13)
|
||||||
abstract class RoomDatabase: RoomDatabase(), io.timelimit.android.data.Database {
|
abstract class RoomDatabase: RoomDatabase(), io.timelimit.android.data.Database {
|
||||||
companion object {
|
companion object {
|
||||||
private val lock = Object()
|
private val lock = Object()
|
||||||
|
@ -78,7 +78,8 @@ abstract class RoomDatabase: RoomDatabase(), io.timelimit.android.data.Database
|
||||||
DatabaseMigrations.MIGRATE_TO_V9,
|
DatabaseMigrations.MIGRATE_TO_V9,
|
||||||
DatabaseMigrations.MIGRATE_TO_V10,
|
DatabaseMigrations.MIGRATE_TO_V10,
|
||||||
DatabaseMigrations.MIGRATE_TO_V11,
|
DatabaseMigrations.MIGRATE_TO_V11,
|
||||||
DatabaseMigrations.MIGRATE_TO_V12
|
DatabaseMigrations.MIGRATE_TO_V12,
|
||||||
|
DatabaseMigrations.MIGRATE_TO_V13
|
||||||
)
|
)
|
||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
|
|
|
@ -78,7 +78,11 @@ data class Device(
|
||||||
@ColumnInfo(name = "default_user_timeout")
|
@ColumnInfo(name = "default_user_timeout")
|
||||||
val defaultUserTimeout: Int,
|
val defaultUserTimeout: Int,
|
||||||
@ColumnInfo(name = "consider_reboot_manipulation")
|
@ColumnInfo(name = "consider_reboot_manipulation")
|
||||||
val considerRebootManipulation: Boolean
|
val considerRebootManipulation: Boolean,
|
||||||
|
@ColumnInfo(name = "current_overlay_permission")
|
||||||
|
val currentOverlayPermission: RuntimePermissionStatus,
|
||||||
|
@ColumnInfo(name = "highest_overlay_permission")
|
||||||
|
val highestOverlayPermission: RuntimePermissionStatus
|
||||||
): JsonSerializable {
|
): JsonSerializable {
|
||||||
companion object {
|
companion object {
|
||||||
private const val ID = "id"
|
private const val ID = "id"
|
||||||
|
@ -105,6 +109,8 @@ data class Device(
|
||||||
private const val DEFAULT_USER = "du"
|
private const val DEFAULT_USER = "du"
|
||||||
private const val DEFAULT_USER_TIMEOUT = "dut"
|
private const val DEFAULT_USER_TIMEOUT = "dut"
|
||||||
private const val CONSIDER_REBOOT_A_MANIPULATION = "cram"
|
private const val CONSIDER_REBOOT_A_MANIPULATION = "cram"
|
||||||
|
private const val CURRENT_OVERLAY_PERMISSION = "cop"
|
||||||
|
private const val HIGHEST_OVERLAY_PERMISSION = "hop"
|
||||||
|
|
||||||
fun parse(reader: JsonReader): Device {
|
fun parse(reader: JsonReader): Device {
|
||||||
var id: String? = null
|
var id: String? = null
|
||||||
|
@ -131,6 +137,8 @@ data class Device(
|
||||||
var defaultUser = ""
|
var defaultUser = ""
|
||||||
var defaultUserTimeout = 0
|
var defaultUserTimeout = 0
|
||||||
var considerRebootManipulation = false
|
var considerRebootManipulation = false
|
||||||
|
var currentOverlayPermission = RuntimePermissionStatus.NotGranted
|
||||||
|
var highestOverlayPermission = RuntimePermissionStatus.NotGranted
|
||||||
|
|
||||||
reader.beginObject()
|
reader.beginObject()
|
||||||
|
|
||||||
|
@ -160,6 +168,8 @@ data class Device(
|
||||||
DEFAULT_USER -> defaultUser = reader.nextString()
|
DEFAULT_USER -> defaultUser = reader.nextString()
|
||||||
DEFAULT_USER_TIMEOUT -> defaultUserTimeout = reader.nextInt()
|
DEFAULT_USER_TIMEOUT -> defaultUserTimeout = reader.nextInt()
|
||||||
CONSIDER_REBOOT_A_MANIPULATION -> considerRebootManipulation = reader.nextBoolean()
|
CONSIDER_REBOOT_A_MANIPULATION -> considerRebootManipulation = reader.nextBoolean()
|
||||||
|
CURRENT_OVERLAY_PERMISSION -> currentOverlayPermission = RuntimePermissionStatusUtil.parse(reader.nextString())
|
||||||
|
HIGHEST_OVERLAY_PERMISSION -> highestOverlayPermission = RuntimePermissionStatusUtil.parse(reader.nextString())
|
||||||
else -> reader.skipValue()
|
else -> reader.skipValue()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -190,7 +200,9 @@ data class Device(
|
||||||
showDeviceConnected = showDeviceConnected,
|
showDeviceConnected = showDeviceConnected,
|
||||||
defaultUser = defaultUser,
|
defaultUser = defaultUser,
|
||||||
defaultUserTimeout = defaultUserTimeout,
|
defaultUserTimeout = defaultUserTimeout,
|
||||||
considerRebootManipulation = considerRebootManipulation
|
considerRebootManipulation = considerRebootManipulation,
|
||||||
|
currentOverlayPermission = currentOverlayPermission,
|
||||||
|
highestOverlayPermission = highestOverlayPermission
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -254,6 +266,8 @@ data class Device(
|
||||||
writer.name(DEFAULT_USER).value(defaultUser)
|
writer.name(DEFAULT_USER).value(defaultUser)
|
||||||
writer.name(DEFAULT_USER_TIMEOUT).value(defaultUserTimeout)
|
writer.name(DEFAULT_USER_TIMEOUT).value(defaultUserTimeout)
|
||||||
writer.name(CONSIDER_REBOOT_A_MANIPULATION).value(considerRebootManipulation)
|
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.endObject()
|
writer.endObject()
|
||||||
}
|
}
|
||||||
|
@ -266,6 +280,8 @@ data class Device(
|
||||||
val manipulationOfNotificationAccess = currentNotificationAccessPermission != highestNotificationAccessPermission
|
val manipulationOfNotificationAccess = currentNotificationAccessPermission != highestNotificationAccessPermission
|
||||||
@Transient
|
@Transient
|
||||||
val manipulationOfAppVersion = currentAppVersion != highestAppVersion
|
val manipulationOfAppVersion = currentAppVersion != highestAppVersion
|
||||||
|
@Transient
|
||||||
|
val manipulationOfOverlayPermission = currentOverlayPermission != highestOverlayPermission
|
||||||
|
|
||||||
@Transient
|
@Transient
|
||||||
val hasActiveManipulationWarning = manipulationOfProtectionLevel ||
|
val hasActiveManipulationWarning = manipulationOfProtectionLevel ||
|
||||||
|
@ -273,7 +289,8 @@ data class Device(
|
||||||
manipulationOfNotificationAccess ||
|
manipulationOfNotificationAccess ||
|
||||||
manipulationOfAppVersion ||
|
manipulationOfAppVersion ||
|
||||||
manipulationTriedDisablingDeviceAdmin ||
|
manipulationTriedDisablingDeviceAdmin ||
|
||||||
manipulationDidReboot
|
manipulationDidReboot ||
|
||||||
|
manipulationOfOverlayPermission
|
||||||
|
|
||||||
@Transient
|
@Transient
|
||||||
val hasAnyManipulation = hasActiveManipulationWarning || hadManipulation
|
val hasAnyManipulation = hasActiveManipulationWarning || hadManipulation
|
||||||
|
|
|
@ -31,12 +31,14 @@ abstract class PlatformIntegration(
|
||||||
abstract fun getForegroundAppPermissionStatus(): RuntimePermissionStatus
|
abstract fun getForegroundAppPermissionStatus(): RuntimePermissionStatus
|
||||||
abstract fun getDrawOverOtherAppsPermissionStatus(): RuntimePermissionStatus
|
abstract fun getDrawOverOtherAppsPermissionStatus(): RuntimePermissionStatus
|
||||||
abstract fun getNotificationAccessPermissionStatus(): NewPermissionStatus
|
abstract fun getNotificationAccessPermissionStatus(): NewPermissionStatus
|
||||||
|
abstract fun getOverlayPermissionStatus(): RuntimePermissionStatus
|
||||||
abstract fun disableDeviceAdmin()
|
abstract fun disableDeviceAdmin()
|
||||||
abstract fun trySetLockScreenPassword(password: String): Boolean
|
abstract fun trySetLockScreenPassword(password: String): Boolean
|
||||||
// this must have a fallback if the permission is not granted
|
// this must have a fallback if the permission is not granted
|
||||||
abstract fun showOverlayMessage(text: String)
|
abstract fun showOverlayMessage(text: String)
|
||||||
|
|
||||||
abstract fun showAppLockScreen(currentPackageName: String)
|
abstract fun showAppLockScreen(currentPackageName: String)
|
||||||
|
abstract fun setShowBlockingOverlay(show: Boolean)
|
||||||
// this should throw an SecurityException if the permission is missing
|
// this should throw an SecurityException if the permission is missing
|
||||||
abstract suspend fun getForegroundAppPackageName(): String?
|
abstract suspend fun getForegroundAppPackageName(): String?
|
||||||
abstract fun setAppStatusMessage(message: AppStatusMessage?)
|
abstract fun setAppStatusMessage(message: AppStatusMessage?)
|
||||||
|
|
|
@ -17,6 +17,7 @@ package io.timelimit.android.integration.platform.android
|
||||||
|
|
||||||
import android.annotation.TargetApi
|
import android.annotation.TargetApi
|
||||||
import android.app.ActivityManager
|
import android.app.ActivityManager
|
||||||
|
import android.app.Application
|
||||||
import android.app.NotificationManager
|
import android.app.NotificationManager
|
||||||
import android.app.PendingIntent
|
import android.app.PendingIntent
|
||||||
import android.app.admin.DevicePolicyManager
|
import android.app.admin.DevicePolicyManager
|
||||||
|
@ -73,6 +74,7 @@ class AndroidIntegration(context: Context): PlatformIntegration(maximumProtectio
|
||||||
private val activityManager = this.context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
|
private val activityManager = this.context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
|
||||||
private val notificationManager = this.context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
private val notificationManager = this.context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||||
private val deviceAdmin = ComponentName(context.applicationContext, AdminReceiver::class.java)
|
private val deviceAdmin = ComponentName(context.applicationContext, AdminReceiver::class.java)
|
||||||
|
private val overlay = OverlayUtil(context as Application)
|
||||||
|
|
||||||
init {
|
init {
|
||||||
AppsChangeListener.registerBroadcastReceiver(this.context, object : BroadcastReceiver() {
|
AppsChangeListener.registerBroadcastReceiver(this.context, object : BroadcastReceiver() {
|
||||||
|
@ -136,6 +138,8 @@ class AndroidIntegration(context: Context): PlatformIntegration(maximumProtectio
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun getOverlayPermissionStatus(): RuntimePermissionStatus = overlay.getOverlayPermissionStatus()
|
||||||
|
|
||||||
override fun trySetLockScreenPassword(password: String): Boolean {
|
override fun trySetLockScreenPassword(password: String): Boolean {
|
||||||
if (BuildConfig.DEBUG) {
|
if (BuildConfig.DEBUG) {
|
||||||
Log.d(LOG_TAG, "set password")
|
Log.d(LOG_TAG, "set password")
|
||||||
|
@ -186,6 +190,14 @@ class AndroidIntegration(context: Context): PlatformIntegration(maximumProtectio
|
||||||
LockActivity.start(context, currentPackageName)
|
LockActivity.start(context, currentPackageName)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun setShowBlockingOverlay(show: Boolean) {
|
||||||
|
if (show) {
|
||||||
|
overlay.show()
|
||||||
|
} else {
|
||||||
|
overlay.hide()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun isScreenOn(): Boolean {
|
override fun isScreenOn(): Boolean {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH) {
|
||||||
return powerManager.isInteractive
|
return powerManager.isInteractive
|
||||||
|
|
|
@ -0,0 +1,81 @@
|
||||||
|
/*
|
||||||
|
* 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.app.Application
|
||||||
|
import android.content.Context
|
||||||
|
import android.view.WindowManager
|
||||||
|
import android.graphics.PixelFormat
|
||||||
|
import android.os.Build
|
||||||
|
import android.provider.Settings
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import io.timelimit.android.async.Threads
|
||||||
|
import io.timelimit.android.databinding.BlockingOverlayBinding
|
||||||
|
import io.timelimit.android.integration.platform.RuntimePermissionStatus
|
||||||
|
|
||||||
|
class OverlayUtil(private var application: Application) {
|
||||||
|
private val windowManager = application.getSystemService(Context.WINDOW_SERVICE) as WindowManager
|
||||||
|
private var currentView: BlockingOverlayBinding? = null
|
||||||
|
|
||||||
|
fun show() {
|
||||||
|
if (currentView != null) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (getOverlayPermissionStatus() == RuntimePermissionStatus.NotGranted) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
val view = BlockingOverlayBinding.inflate(LayoutInflater.from(application))
|
||||||
|
|
||||||
|
val params = WindowManager.LayoutParams(
|
||||||
|
WindowManager.LayoutParams.MATCH_PARENT,
|
||||||
|
WindowManager.LayoutParams.MATCH_PARENT,
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
|
||||||
|
WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY
|
||||||
|
else
|
||||||
|
WindowManager.LayoutParams.TYPE_SYSTEM_ALERT,
|
||||||
|
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
|
||||||
|
PixelFormat.TRANSLUCENT
|
||||||
|
)
|
||||||
|
|
||||||
|
windowManager.addView(view.root, params)
|
||||||
|
currentView = view
|
||||||
|
|
||||||
|
Threads.mainThreadHandler.postDelayed({
|
||||||
|
view.showWarningMessage = true
|
||||||
|
}, 2000)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun hide() {
|
||||||
|
if (currentView == null) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
windowManager.removeView(currentView!!.root)
|
||||||
|
currentView = null
|
||||||
|
}
|
||||||
|
|
||||||
|
fun isOverlayShown() = currentView?.root?.isShown ?: false
|
||||||
|
|
||||||
|
fun getOverlayPermissionStatus() = /*if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
|
||||||
|
if (Settings.canDrawOverlays(application))
|
||||||
|
RuntimePermissionStatus.Granted
|
||||||
|
else
|
||||||
|
*/RuntimePermissionStatus.NotGranted/*
|
||||||
|
else
|
||||||
|
RuntimePermissionStatus.NotRequired*/
|
||||||
|
}
|
|
@ -61,6 +61,10 @@ class DummyIntegration(
|
||||||
return notificationAccess
|
return notificationAccess
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun getOverlayPermissionStatus(): RuntimePermissionStatus {
|
||||||
|
return RuntimePermissionStatus.NotRequired
|
||||||
|
}
|
||||||
|
|
||||||
override fun trySetLockScreenPassword(password: String): Boolean {
|
override fun trySetLockScreenPassword(password: String): Boolean {
|
||||||
return false // it failed
|
return false // it failed
|
||||||
}
|
}
|
||||||
|
@ -72,6 +76,10 @@ class DummyIntegration(
|
||||||
launchLockScreenForPackage = currentPackageName
|
launchLockScreenForPackage = currentPackageName
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun setShowBlockingOverlay(show: Boolean) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
|
||||||
fun getAndResetShowAppLockScreen(): String? {
|
fun getAndResetShowAppLockScreen(): String? {
|
||||||
try {
|
try {
|
||||||
return launchLockScreenForPackage
|
return launchLockScreenForPackage
|
||||||
|
|
|
@ -95,7 +95,9 @@ class AppSetupLogic(private val appLogic: AppLogic) {
|
||||||
showDeviceConnected = false,
|
showDeviceConnected = false,
|
||||||
defaultUser = "",
|
defaultUser = "",
|
||||||
defaultUserTimeout = 0,
|
defaultUserTimeout = 0,
|
||||||
considerRebootManipulation = false
|
considerRebootManipulation = false,
|
||||||
|
currentOverlayPermission = RuntimePermissionStatus.NotGranted,
|
||||||
|
highestOverlayPermission = RuntimePermissionStatus.NotGranted
|
||||||
)
|
)
|
||||||
|
|
||||||
appLogic.database.device().addDeviceSync(device)
|
appLogic.database.device().addDeviceSync(device)
|
||||||
|
|
|
@ -35,7 +35,6 @@ import io.timelimit.android.integration.platform.android.AndroidIntegrationApps
|
||||||
import io.timelimit.android.livedata.*
|
import io.timelimit.android.livedata.*
|
||||||
import io.timelimit.android.sync.actions.UpdateDeviceStatusAction
|
import io.timelimit.android.sync.actions.UpdateDeviceStatusAction
|
||||||
import io.timelimit.android.sync.actions.apply.ApplyActionUtil
|
import io.timelimit.android.sync.actions.apply.ApplyActionUtil
|
||||||
import io.timelimit.android.ui.IsAppInForeground
|
|
||||||
import io.timelimit.android.util.TimeTextUtil
|
import io.timelimit.android.util.TimeTextUtil
|
||||||
import kotlinx.coroutines.sync.Mutex
|
import kotlinx.coroutines.sync.Mutex
|
||||||
import kotlinx.coroutines.sync.withLock
|
import kotlinx.coroutines.sync.withLock
|
||||||
|
@ -144,6 +143,7 @@ class BackgroundTaskLogic(val appLogic: AppLogic) {
|
||||||
usedTimeUpdateHelper?.commit(appLogic)
|
usedTimeUpdateHelper?.commit(appLogic)
|
||||||
liveDataCaches.removeAllItems()
|
liveDataCaches.removeAllItems()
|
||||||
appLogic.platformIntegration.setAppStatusMessage(null)
|
appLogic.platformIntegration.setAppStatusMessage(null)
|
||||||
|
appLogic.platformIntegration.setShowBlockingOverlay(false)
|
||||||
appLogic.enable.waitUntilValueMatches { it == true }
|
appLogic.enable.waitUntilValueMatches { it == true }
|
||||||
|
|
||||||
continue
|
continue
|
||||||
|
@ -165,12 +165,14 @@ class BackgroundTaskLogic(val appLogic: AppLogic) {
|
||||||
text = appLogic.context.getString(R.string.background_logic_timeout_text)
|
text = appLogic.context.getString(R.string.background_logic_timeout_text)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
appLogic.platformIntegration.setShowBlockingOverlay(false)
|
||||||
|
|
||||||
liveDataCaches.reportLoopDone()
|
liveDataCaches.reportLoopDone()
|
||||||
appLogic.timeApi.sleep(BACKGROUND_SERVICE_INTERVAL)
|
appLogic.timeApi.sleep(BACKGROUND_SERVICE_INTERVAL)
|
||||||
} else {
|
} else {
|
||||||
liveDataCaches.removeAllItems()
|
liveDataCaches.removeAllItems()
|
||||||
appLogic.platformIntegration.setAppStatusMessage(null)
|
appLogic.platformIntegration.setAppStatusMessage(null)
|
||||||
|
appLogic.platformIntegration.setShowBlockingOverlay(false)
|
||||||
|
|
||||||
val isChildSignedIn = deviceUserEntryLive.read().map { it != null && it.type == UserType.Child }
|
val isChildSignedIn = deviceUserEntryLive.read().map { it != null && it.type == UserType.Child }
|
||||||
|
|
||||||
|
@ -238,12 +240,14 @@ class BackgroundTaskLogic(val appLogic: AppLogic) {
|
||||||
appTitleCache.query(foregroundAppPackageName),
|
appTitleCache.query(foregroundAppPackageName),
|
||||||
appLogic.context.getString(R.string.background_logic_whitelisted)
|
appLogic.context.getString(R.string.background_logic_whitelisted)
|
||||||
))
|
))
|
||||||
|
appLogic.platformIntegration.setShowBlockingOverlay(false)
|
||||||
} else if (foregroundAppPackageName != null && temporarilyAllowedApps.contains(foregroundAppPackageName)) {
|
} else if (foregroundAppPackageName != null && temporarilyAllowedApps.contains(foregroundAppPackageName)) {
|
||||||
usedTimeUpdateHelper?.commit(appLogic)
|
usedTimeUpdateHelper?.commit(appLogic)
|
||||||
appLogic.platformIntegration.setAppStatusMessage(AppStatusMessage(
|
appLogic.platformIntegration.setAppStatusMessage(AppStatusMessage(
|
||||||
appTitleCache.query(foregroundAppPackageName),
|
appTitleCache.query(foregroundAppPackageName),
|
||||||
appLogic.context.getString(R.string.background_logic_temporarily_allowed)
|
appLogic.context.getString(R.string.background_logic_temporarily_allowed)
|
||||||
))
|
))
|
||||||
|
appLogic.platformIntegration.setShowBlockingOverlay(false)
|
||||||
} else if (foregroundAppPackageName != null) {
|
} else if (foregroundAppPackageName != null) {
|
||||||
val appCategory = appCategories.get(Pair(foregroundAppPackageName, categories.map { it.id })).waitForNullableValue()
|
val appCategory = appCategories.get(Pair(foregroundAppPackageName, categories.map { it.id })).waitForNullableValue()
|
||||||
val category = categories.find { it.id == appCategory?.categoryId }
|
val category = categories.find { it.id == appCategory?.categoryId }
|
||||||
|
@ -259,6 +263,7 @@ class BackgroundTaskLogic(val appLogic: AppLogic) {
|
||||||
))
|
))
|
||||||
appLogic.platformIntegration.setSuspendedApps(listOf(foregroundAppPackageName), true)
|
appLogic.platformIntegration.setSuspendedApps(listOf(foregroundAppPackageName), true)
|
||||||
appLogic.platformIntegration.showAppLockScreen(foregroundAppPackageName)
|
appLogic.platformIntegration.showAppLockScreen(foregroundAppPackageName)
|
||||||
|
appLogic.platformIntegration.setShowBlockingOverlay(true)
|
||||||
} else if (category.temporarilyBlocked or (parentCategory?.temporarilyBlocked == true)) {
|
} else if (category.temporarilyBlocked or (parentCategory?.temporarilyBlocked == true)) {
|
||||||
usedTimeUpdateHelper?.commit(appLogic)
|
usedTimeUpdateHelper?.commit(appLogic)
|
||||||
|
|
||||||
|
@ -267,6 +272,7 @@ class BackgroundTaskLogic(val appLogic: AppLogic) {
|
||||||
text = appLogic.context.getString(R.string.background_logic_opening_lockscreen)
|
text = appLogic.context.getString(R.string.background_logic_opening_lockscreen)
|
||||||
))
|
))
|
||||||
appLogic.platformIntegration.showAppLockScreen(foregroundAppPackageName)
|
appLogic.platformIntegration.showAppLockScreen(foregroundAppPackageName)
|
||||||
|
appLogic.platformIntegration.setShowBlockingOverlay(true)
|
||||||
} else {
|
} else {
|
||||||
// disable time limits temporarily feature
|
// disable time limits temporarily feature
|
||||||
if (realTime.shouldTrustTimeTemporarily && nowTimestamp < deviceUserEntry.disableLimitsUntil) {
|
if (realTime.shouldTrustTimeTemporarily && nowTimestamp < deviceUserEntry.disableLimitsUntil) {
|
||||||
|
@ -274,6 +280,7 @@ class BackgroundTaskLogic(val appLogic: AppLogic) {
|
||||||
title = appTitleCache.query(foregroundAppPackageName),
|
title = appTitleCache.query(foregroundAppPackageName),
|
||||||
text = appLogic.context.getString(R.string.background_logic_limits_disabled)
|
text = appLogic.context.getString(R.string.background_logic_limits_disabled)
|
||||||
))
|
))
|
||||||
|
appLogic.platformIntegration.setShowBlockingOverlay(false)
|
||||||
} else if (
|
} else if (
|
||||||
// check blocked time areas
|
// check blocked time areas
|
||||||
// directly blocked
|
// directly blocked
|
||||||
|
@ -295,6 +302,7 @@ class BackgroundTaskLogic(val appLogic: AppLogic) {
|
||||||
text = appLogic.context.getString(R.string.background_logic_opening_lockscreen)
|
text = appLogic.context.getString(R.string.background_logic_opening_lockscreen)
|
||||||
))
|
))
|
||||||
appLogic.platformIntegration.showAppLockScreen(foregroundAppPackageName)
|
appLogic.platformIntegration.showAppLockScreen(foregroundAppPackageName)
|
||||||
|
appLogic.platformIntegration.setShowBlockingOverlay(true)
|
||||||
} else {
|
} else {
|
||||||
// check time limits
|
// check time limits
|
||||||
val rules = timeLimitRules.get(category.id).waitForNonNullValue()
|
val rules = timeLimitRules.get(category.id).waitForNonNullValue()
|
||||||
|
@ -310,6 +318,7 @@ class BackgroundTaskLogic(val appLogic: AppLogic) {
|
||||||
category.title + " - " + appTitleCache.query(foregroundAppPackageName),
|
category.title + " - " + appTitleCache.query(foregroundAppPackageName),
|
||||||
appLogic.context.getString(R.string.background_logic_no_timelimit)
|
appLogic.context.getString(R.string.background_logic_no_timelimit)
|
||||||
))
|
))
|
||||||
|
appLogic.platformIntegration.setShowBlockingOverlay(false)
|
||||||
} else {
|
} else {
|
||||||
val isCurrentDevice = isThisDeviceTheCurrentDeviceLive.read().waitForNonNullValue()
|
val isCurrentDevice = isThisDeviceTheCurrentDeviceLive.read().waitForNonNullValue()
|
||||||
|
|
||||||
|
@ -321,6 +330,7 @@ class BackgroundTaskLogic(val appLogic: AppLogic) {
|
||||||
text = appLogic.context.getString(R.string.background_logic_opening_lockscreen)
|
text = appLogic.context.getString(R.string.background_logic_opening_lockscreen)
|
||||||
))
|
))
|
||||||
appLogic.platformIntegration.showAppLockScreen(foregroundAppPackageName)
|
appLogic.platformIntegration.showAppLockScreen(foregroundAppPackageName)
|
||||||
|
appLogic.platformIntegration.setShowBlockingOverlay(true)
|
||||||
} else if (realTime.shouldTrustTimeTemporarily) {
|
} else if (realTime.shouldTrustTimeTemporarily) {
|
||||||
val usedTimes = usedTimesOfCategoryAndWeekByFirstDayOfWeek.get(Pair(category.id, nowDate.dayOfEpoch - nowDate.dayOfWeek)).waitForNonNullValue()
|
val usedTimes = usedTimesOfCategoryAndWeekByFirstDayOfWeek.get(Pair(category.id, nowDate.dayOfEpoch - nowDate.dayOfWeek)).waitForNonNullValue()
|
||||||
val parentUsedTimes = parentCategory?.let {
|
val parentUsedTimes = parentCategory?.let {
|
||||||
|
@ -387,6 +397,7 @@ class BackgroundTaskLogic(val appLogic: AppLogic) {
|
||||||
category.title + " - " + appTitleCache.query(foregroundAppPackageName),
|
category.title + " - " + appTitleCache.query(foregroundAppPackageName),
|
||||||
appLogic.context.getString(R.string.background_logic_no_timelimit)
|
appLogic.context.getString(R.string.background_logic_no_timelimit)
|
||||||
))
|
))
|
||||||
|
appLogic.platformIntegration.setShowBlockingOverlay(false)
|
||||||
} else {
|
} else {
|
||||||
// time limited
|
// time limited
|
||||||
if (remaining.includingExtraTime > 0) {
|
if (remaining.includingExtraTime > 0) {
|
||||||
|
@ -397,6 +408,7 @@ class BackgroundTaskLogic(val appLogic: AppLogic) {
|
||||||
category.title + " - " + appTitleCache.query(foregroundAppPackageName),
|
category.title + " - " + appTitleCache.query(foregroundAppPackageName),
|
||||||
appLogic.context.getString(R.string.background_logic_using_extra_time, TimeTextUtil.remaining(remaining.includingExtraTime.toInt(), appLogic.context))
|
appLogic.context.getString(R.string.background_logic_using_extra_time, TimeTextUtil.remaining(remaining.includingExtraTime.toInt(), appLogic.context))
|
||||||
))
|
))
|
||||||
|
appLogic.platformIntegration.setShowBlockingOverlay(false)
|
||||||
|
|
||||||
if (isScreenOn) {
|
if (isScreenOn) {
|
||||||
newUsedTimeItemBatchUpdateHelper.addUsedTime(
|
newUsedTimeItemBatchUpdateHelper.addUsedTime(
|
||||||
|
@ -412,6 +424,7 @@ class BackgroundTaskLogic(val appLogic: AppLogic) {
|
||||||
category.title + " - " + appTitleCache.query(foregroundAppPackageName),
|
category.title + " - " + appTitleCache.query(foregroundAppPackageName),
|
||||||
TimeTextUtil.remaining(remaining.default.toInt(), appLogic.context)
|
TimeTextUtil.remaining(remaining.default.toInt(), appLogic.context)
|
||||||
))
|
))
|
||||||
|
appLogic.platformIntegration.setShowBlockingOverlay(false)
|
||||||
|
|
||||||
if (isScreenOn) {
|
if (isScreenOn) {
|
||||||
newUsedTimeItemBatchUpdateHelper.addUsedTime(
|
newUsedTimeItemBatchUpdateHelper.addUsedTime(
|
||||||
|
@ -431,6 +444,7 @@ class BackgroundTaskLogic(val appLogic: AppLogic) {
|
||||||
text = appLogic.context.getString(R.string.background_logic_opening_lockscreen)
|
text = appLogic.context.getString(R.string.background_logic_opening_lockscreen)
|
||||||
))
|
))
|
||||||
appLogic.platformIntegration.showAppLockScreen(foregroundAppPackageName)
|
appLogic.platformIntegration.showAppLockScreen(foregroundAppPackageName)
|
||||||
|
appLogic.platformIntegration.setShowBlockingOverlay(true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -443,6 +457,7 @@ class BackgroundTaskLogic(val appLogic: AppLogic) {
|
||||||
text = appLogic.context.getString(R.string.background_logic_opening_lockscreen)
|
text = appLogic.context.getString(R.string.background_logic_opening_lockscreen)
|
||||||
))
|
))
|
||||||
appLogic.platformIntegration.showAppLockScreen(foregroundAppPackageName)
|
appLogic.platformIntegration.showAppLockScreen(foregroundAppPackageName)
|
||||||
|
appLogic.platformIntegration.setShowBlockingOverlay(true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -452,6 +467,7 @@ class BackgroundTaskLogic(val appLogic: AppLogic) {
|
||||||
appLogic.context.getString(R.string.background_logic_idle_title),
|
appLogic.context.getString(R.string.background_logic_idle_title),
|
||||||
appLogic.context.getString(R.string.background_logic_idle_text)
|
appLogic.context.getString(R.string.background_logic_idle_text)
|
||||||
))
|
))
|
||||||
|
appLogic.platformIntegration.setShowBlockingOverlay(false)
|
||||||
}
|
}
|
||||||
} catch (ex: SecurityException) {
|
} catch (ex: SecurityException) {
|
||||||
// this is handled by an other main loop (with a delay)
|
// this is handled by an other main loop (with a delay)
|
||||||
|
@ -460,6 +476,7 @@ class BackgroundTaskLogic(val appLogic: AppLogic) {
|
||||||
appLogic.context.getString(R.string.background_logic_error),
|
appLogic.context.getString(R.string.background_logic_error),
|
||||||
appLogic.context.getString(R.string.background_logic_error_permission)
|
appLogic.context.getString(R.string.background_logic_error_permission)
|
||||||
))
|
))
|
||||||
|
appLogic.platformIntegration.setShowBlockingOverlay(false)
|
||||||
} catch (ex: Exception) {
|
} catch (ex: Exception) {
|
||||||
if (BuildConfig.DEBUG) {
|
if (BuildConfig.DEBUG) {
|
||||||
Log.w(LOG_TAG, "exception during running main loop", ex)
|
Log.w(LOG_TAG, "exception during running main loop", ex)
|
||||||
|
@ -469,6 +486,7 @@ class BackgroundTaskLogic(val appLogic: AppLogic) {
|
||||||
appLogic.context.getString(R.string.background_logic_error),
|
appLogic.context.getString(R.string.background_logic_error),
|
||||||
appLogic.context.getString(R.string.background_logic_error_internal)
|
appLogic.context.getString(R.string.background_logic_error_internal)
|
||||||
))
|
))
|
||||||
|
appLogic.platformIntegration.setShowBlockingOverlay(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
liveDataCaches.reportLoopDone()
|
liveDataCaches.reportLoopDone()
|
||||||
|
@ -542,6 +560,7 @@ class BackgroundTaskLogic(val appLogic: AppLogic) {
|
||||||
val protectionLevel = appLogic.platformIntegration.getCurrentProtectionLevel()
|
val protectionLevel = appLogic.platformIntegration.getCurrentProtectionLevel()
|
||||||
val usageStatsPermission = appLogic.platformIntegration.getForegroundAppPermissionStatus()
|
val usageStatsPermission = appLogic.platformIntegration.getForegroundAppPermissionStatus()
|
||||||
val notificationAccess = appLogic.platformIntegration.getNotificationAccessPermissionStatus()
|
val notificationAccess = appLogic.platformIntegration.getNotificationAccessPermissionStatus()
|
||||||
|
val overlayPermission = appLogic.platformIntegration.getOverlayPermissionStatus()
|
||||||
|
|
||||||
var changes = UpdateDeviceStatusAction.empty
|
var changes = UpdateDeviceStatusAction.empty
|
||||||
|
|
||||||
|
@ -567,6 +586,12 @@ class BackgroundTaskLogic(val appLogic: AppLogic) {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (overlayPermission != deviceEntry.currentOverlayPermission) {
|
||||||
|
changes = changes.copy(
|
||||||
|
newOverlayPermission = overlayPermission
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
if (changes != UpdateDeviceStatusAction.empty) {
|
if (changes != UpdateDeviceStatusAction.empty) {
|
||||||
ApplyActionUtil.applyAppLogicAction(
|
ApplyActionUtil.applyAppLogicAction(
|
||||||
action = changes,
|
action = changes,
|
||||||
|
|
|
@ -154,7 +154,9 @@ object ApplyServerDataStatus {
|
||||||
showDeviceConnected = newDevice.showDeviceConnected,
|
showDeviceConnected = newDevice.showDeviceConnected,
|
||||||
defaultUser = newDevice.defaultUser,
|
defaultUser = newDevice.defaultUser,
|
||||||
defaultUserTimeout = newDevice.defaultUserTimeout,
|
defaultUserTimeout = newDevice.defaultUserTimeout,
|
||||||
considerRebootManipulation = newDevice.considerRebootManipulation
|
considerRebootManipulation = newDevice.considerRebootManipulation,
|
||||||
|
currentOverlayPermission = newDevice.currentOverlayPermission,
|
||||||
|
highestOverlayPermission = newDevice.highestOverlayPermission
|
||||||
))
|
))
|
||||||
} else {
|
} else {
|
||||||
// eventually update old entry
|
// eventually update old entry
|
||||||
|
@ -181,7 +183,9 @@ object ApplyServerDataStatus {
|
||||||
showDeviceConnected = newDevice.showDeviceConnected,
|
showDeviceConnected = newDevice.showDeviceConnected,
|
||||||
defaultUser = newDevice.defaultUser,
|
defaultUser = newDevice.defaultUser,
|
||||||
defaultUserTimeout = newDevice.defaultUserTimeout,
|
defaultUserTimeout = newDevice.defaultUserTimeout,
|
||||||
considerRebootManipulation = newDevice.considerRebootManipulation
|
considerRebootManipulation = newDevice.considerRebootManipulation,
|
||||||
|
currentOverlayPermission = newDevice.currentOverlayPermission,
|
||||||
|
highestOverlayPermission = newDevice.highestOverlayPermission
|
||||||
)
|
)
|
||||||
|
|
||||||
if (updatedDeviceEntry != oldDeviceEntry) {
|
if (updatedDeviceEntry != oldDeviceEntry) {
|
||||||
|
|
|
@ -563,6 +563,7 @@ data class UpdateDeviceStatusAction(
|
||||||
val newProtectionLevel: ProtectionLevel?,
|
val newProtectionLevel: ProtectionLevel?,
|
||||||
val newUsageStatsPermissionStatus: RuntimePermissionStatus?,
|
val newUsageStatsPermissionStatus: RuntimePermissionStatus?,
|
||||||
val newNotificationAccessPermission: NewPermissionStatus?,
|
val newNotificationAccessPermission: NewPermissionStatus?,
|
||||||
|
val newOverlayPermission: RuntimePermissionStatus?,
|
||||||
val newAppVersion: Int?,
|
val newAppVersion: Int?,
|
||||||
val didReboot: Boolean
|
val didReboot: Boolean
|
||||||
): AppLogicAction() {
|
): AppLogicAction() {
|
||||||
|
@ -571,6 +572,7 @@ data class UpdateDeviceStatusAction(
|
||||||
private const val NEW_PROTECTION_LEVEL = "protectionLevel"
|
private const val NEW_PROTECTION_LEVEL = "protectionLevel"
|
||||||
private const val NEW_USAGE_STATS_PERMISSION_STATUS = "usageStats"
|
private const val NEW_USAGE_STATS_PERMISSION_STATUS = "usageStats"
|
||||||
private const val NEW_NOTIFICATION_ACCESS_PERMISSION = "notificationAccess"
|
private const val NEW_NOTIFICATION_ACCESS_PERMISSION = "notificationAccess"
|
||||||
|
private const val NEW_OVERLAY_PERMISSION = "overlayPermission"
|
||||||
private const val NEW_APP_VERSION = "appVersion"
|
private const val NEW_APP_VERSION = "appVersion"
|
||||||
private const val DID_REBOOT = "didReboot"
|
private const val DID_REBOOT = "didReboot"
|
||||||
|
|
||||||
|
@ -578,6 +580,7 @@ data class UpdateDeviceStatusAction(
|
||||||
newProtectionLevel = null,
|
newProtectionLevel = null,
|
||||||
newUsageStatsPermissionStatus = null,
|
newUsageStatsPermissionStatus = null,
|
||||||
newNotificationAccessPermission = null,
|
newNotificationAccessPermission = null,
|
||||||
|
newOverlayPermission = null,
|
||||||
newAppVersion = null,
|
newAppVersion = null,
|
||||||
didReboot = false
|
didReboot = false
|
||||||
)
|
)
|
||||||
|
@ -611,6 +614,12 @@ data class UpdateDeviceStatusAction(
|
||||||
.value(NewPermissionStatusUtil.serialize(newNotificationAccessPermission))
|
.value(NewPermissionStatusUtil.serialize(newNotificationAccessPermission))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (newOverlayPermission != null) {
|
||||||
|
writer
|
||||||
|
.name(NEW_OVERLAY_PERMISSION)
|
||||||
|
.value(RuntimePermissionStatusUtil.serialize(newOverlayPermission))
|
||||||
|
}
|
||||||
|
|
||||||
if (newAppVersion != null) {
|
if (newAppVersion != null) {
|
||||||
writer.name(NEW_APP_VERSION)
|
writer.name(NEW_APP_VERSION)
|
||||||
writer.value(newAppVersion)
|
writer.value(newAppVersion)
|
||||||
|
@ -631,6 +640,7 @@ data class IgnoreManipulationAction(
|
||||||
val ignoreAppDowngrade: Boolean,
|
val ignoreAppDowngrade: Boolean,
|
||||||
val ignoreNotificationAccessManipulation: Boolean,
|
val ignoreNotificationAccessManipulation: Boolean,
|
||||||
val ignoreUsageStatsAccessManipulation: Boolean,
|
val ignoreUsageStatsAccessManipulation: Boolean,
|
||||||
|
val ignoreOverlayPermissionManipulation: Boolean,
|
||||||
val ignoreReboot: Boolean,
|
val ignoreReboot: Boolean,
|
||||||
val ignoreHadManipulation: Boolean
|
val ignoreHadManipulation: Boolean
|
||||||
): ParentAction() {
|
): ParentAction() {
|
||||||
|
@ -642,6 +652,7 @@ data class IgnoreManipulationAction(
|
||||||
private const val IGNORE_APP_DOWNGRADE = "downgrade"
|
private const val IGNORE_APP_DOWNGRADE = "downgrade"
|
||||||
private const val IGNORE_NOTIFICATION_ACCESS = "notification"
|
private const val IGNORE_NOTIFICATION_ACCESS = "notification"
|
||||||
private const val IGNORE_USAGE_STATS_ACCESS = "usageStats"
|
private const val IGNORE_USAGE_STATS_ACCESS = "usageStats"
|
||||||
|
private const val IGNORE_OVERLAY_PERMISSION_MANIPULATION = "overlay"
|
||||||
private const val IGNORE_HAD_MANIPULATION = "hadManipulation"
|
private const val IGNORE_HAD_MANIPULATION = "hadManipulation"
|
||||||
private const val IGNORE_REBOOT = "reboot"
|
private const val IGNORE_REBOOT = "reboot"
|
||||||
}
|
}
|
||||||
|
@ -655,6 +666,7 @@ data class IgnoreManipulationAction(
|
||||||
(!ignoreAppDowngrade) &&
|
(!ignoreAppDowngrade) &&
|
||||||
(!ignoreNotificationAccessManipulation) &&
|
(!ignoreNotificationAccessManipulation) &&
|
||||||
(!ignoreUsageStatsAccessManipulation) &&
|
(!ignoreUsageStatsAccessManipulation) &&
|
||||||
|
(!ignoreOverlayPermissionManipulation) &&
|
||||||
(!ignoreReboot) &&
|
(!ignoreReboot) &&
|
||||||
(!ignoreHadManipulation)
|
(!ignoreHadManipulation)
|
||||||
|
|
||||||
|
@ -668,6 +680,7 @@ data class IgnoreManipulationAction(
|
||||||
writer.name(IGNORE_APP_DOWNGRADE).value(ignoreAppDowngrade)
|
writer.name(IGNORE_APP_DOWNGRADE).value(ignoreAppDowngrade)
|
||||||
writer.name(IGNORE_NOTIFICATION_ACCESS).value(ignoreNotificationAccessManipulation)
|
writer.name(IGNORE_NOTIFICATION_ACCESS).value(ignoreNotificationAccessManipulation)
|
||||||
writer.name(IGNORE_USAGE_STATS_ACCESS).value(ignoreUsageStatsAccessManipulation)
|
writer.name(IGNORE_USAGE_STATS_ACCESS).value(ignoreUsageStatsAccessManipulation)
|
||||||
|
writer.name(IGNORE_OVERLAY_PERMISSION_MANIPULATION).value(ignoreOverlayPermissionManipulation)
|
||||||
writer.name(IGNORE_HAD_MANIPULATION).value(ignoreHadManipulation)
|
writer.name(IGNORE_HAD_MANIPULATION).value(ignoreHadManipulation)
|
||||||
writer.name(IGNORE_REBOOT).value(ignoreReboot)
|
writer.name(IGNORE_REBOOT).value(ignoreReboot)
|
||||||
|
|
||||||
|
|
|
@ -150,6 +150,24 @@ object LocalDatabaseAppLogicActionDispatcher {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (action.newOverlayPermission != null) {
|
||||||
|
if (device.currentOverlayPermission != action.newOverlayPermission) {
|
||||||
|
device = device.copy(
|
||||||
|
currentOverlayPermission = action.newOverlayPermission
|
||||||
|
)
|
||||||
|
|
||||||
|
if (RuntimePermissionStatusUtil.toInt(action.newOverlayPermission) > RuntimePermissionStatusUtil.toInt(device.highestOverlayPermission)) {
|
||||||
|
device = device.copy(
|
||||||
|
highestOverlayPermission = action.newOverlayPermission
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (device.currentOverlayPermission != device.highestOverlayPermission) {
|
||||||
|
device = device.copy(hadManipulation = true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (action.newAppVersion != null) {
|
if (action.newAppVersion != null) {
|
||||||
if (device.currentAppVersion != action.newAppVersion) {
|
if (device.currentAppVersion != action.newAppVersion) {
|
||||||
device = device.copy(
|
device = device.copy(
|
||||||
|
|
|
@ -290,6 +290,10 @@ object LocalDatabaseParentActionDispatcher {
|
||||||
deviceEntry = deviceEntry.copy(highestUsageStatsPermission = deviceEntry.currentUsageStatsPermission)
|
deviceEntry = deviceEntry.copy(highestUsageStatsPermission = deviceEntry.currentUsageStatsPermission)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (action.ignoreOverlayPermissionManipulation) {
|
||||||
|
deviceEntry = deviceEntry.copy(highestOverlayPermission = deviceEntry.currentOverlayPermission)
|
||||||
|
}
|
||||||
|
|
||||||
if (action.ignoreReboot) {
|
if (action.ignoreReboot) {
|
||||||
deviceEntry = deviceEntry.copy(manipulationDidReboot = false)
|
deviceEntry = deviceEntry.copy(manipulationDidReboot = false)
|
||||||
}
|
}
|
||||||
|
|
|
@ -178,7 +178,9 @@ data class ServerDeviceData(
|
||||||
val showDeviceConnected: Boolean,
|
val showDeviceConnected: Boolean,
|
||||||
val defaultUser: String,
|
val defaultUser: String,
|
||||||
val defaultUserTimeout: Int,
|
val defaultUserTimeout: Int,
|
||||||
val considerRebootManipulation: Boolean
|
val considerRebootManipulation: Boolean,
|
||||||
|
val currentOverlayPermission: RuntimePermissionStatus,
|
||||||
|
val highestOverlayPermission: RuntimePermissionStatus
|
||||||
) {
|
) {
|
||||||
companion object {
|
companion object {
|
||||||
private const val DEVICE_ID = "deviceId"
|
private const val DEVICE_ID = "deviceId"
|
||||||
|
@ -204,6 +206,8 @@ data class ServerDeviceData(
|
||||||
private const val DEFAULT_USER = "defUser"
|
private const val DEFAULT_USER = "defUser"
|
||||||
private const val DEFAULT_USER_TIMEOUT = "defUserTimeout"
|
private const val DEFAULT_USER_TIMEOUT = "defUserTimeout"
|
||||||
private const val CONSIDER_REBOOT_MANIPULATION = "rebootIsManipulation"
|
private const val CONSIDER_REBOOT_MANIPULATION = "rebootIsManipulation"
|
||||||
|
private const val CURRENT_OVERLAY_PERMISSION = "cOverlay"
|
||||||
|
private const val HIGHEST_OVERLAY_PERMISSION = "hOverlay"
|
||||||
|
|
||||||
fun parse(reader: JsonReader): ServerDeviceData {
|
fun parse(reader: JsonReader): ServerDeviceData {
|
||||||
var deviceId: String? = null
|
var deviceId: String? = null
|
||||||
|
@ -229,6 +233,8 @@ data class ServerDeviceData(
|
||||||
var defaultUser: String? = null
|
var defaultUser: String? = null
|
||||||
var defaultUserTimeout: Int? = null
|
var defaultUserTimeout: Int? = null
|
||||||
var considerRebootManipulation: Boolean? = null
|
var considerRebootManipulation: Boolean? = null
|
||||||
|
var currentOverlayPermission: RuntimePermissionStatus? = null
|
||||||
|
var highestOverlayPermission: RuntimePermissionStatus? = null
|
||||||
|
|
||||||
reader.beginObject()
|
reader.beginObject()
|
||||||
while (reader.hasNext()) {
|
while (reader.hasNext()) {
|
||||||
|
@ -256,6 +262,8 @@ data class ServerDeviceData(
|
||||||
DEFAULT_USER -> defaultUser = reader.nextString()
|
DEFAULT_USER -> defaultUser = reader.nextString()
|
||||||
DEFAULT_USER_TIMEOUT -> defaultUserTimeout = reader.nextInt()
|
DEFAULT_USER_TIMEOUT -> defaultUserTimeout = reader.nextInt()
|
||||||
CONSIDER_REBOOT_MANIPULATION -> considerRebootManipulation = reader.nextBoolean()
|
CONSIDER_REBOOT_MANIPULATION -> considerRebootManipulation = reader.nextBoolean()
|
||||||
|
CURRENT_OVERLAY_PERMISSION -> currentOverlayPermission = RuntimePermissionStatusUtil.parse(reader.nextString())
|
||||||
|
HIGHEST_OVERLAY_PERMISSION -> highestOverlayPermission = RuntimePermissionStatusUtil.parse(reader.nextString())
|
||||||
else -> reader.skipValue()
|
else -> reader.skipValue()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -284,7 +292,9 @@ data class ServerDeviceData(
|
||||||
showDeviceConnected = showDeviceConnected!!,
|
showDeviceConnected = showDeviceConnected!!,
|
||||||
defaultUser = defaultUser!!,
|
defaultUser = defaultUser!!,
|
||||||
defaultUserTimeout = defaultUserTimeout!!,
|
defaultUserTimeout = defaultUserTimeout!!,
|
||||||
considerRebootManipulation = considerRebootManipulation!!
|
considerRebootManipulation = considerRebootManipulation!!,
|
||||||
|
currentOverlayPermission = currentOverlayPermission!!,
|
||||||
|
highestOverlayPermission = highestOverlayPermission!!
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,7 @@ package io.timelimit.android.ui.manage.device.manage
|
||||||
import android.app.admin.DevicePolicyManager
|
import android.app.admin.DevicePolicyManager
|
||||||
import android.content.ComponentName
|
import android.content.ComponentName
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
|
import android.net.Uri
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.provider.Settings
|
import android.provider.Settings
|
||||||
|
@ -186,6 +187,14 @@ class ManageDeviceFragment : Fragment(), FragmentWithCustomTitle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun openDrawOverOtherAppsScreen() {
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||||
|
startActivity(
|
||||||
|
Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + context!!.packageName))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun manageDeviceAdmin() {
|
override fun manageDeviceAdmin() {
|
||||||
if (binding.isThisDevice == true) {
|
if (binding.isThisDevice == true) {
|
||||||
val protectionLevel = logic.platformIntegration.getCurrentProtectionLevel()
|
val protectionLevel = logic.platformIntegration.getCurrentProtectionLevel()
|
||||||
|
@ -269,6 +278,7 @@ class ManageDeviceFragment : Fragment(), FragmentWithCustomTitle {
|
||||||
binding.usageStatsAccess = device.currentUsageStatsPermission
|
binding.usageStatsAccess = device.currentUsageStatsPermission
|
||||||
binding.notificationAccessPermission = device.currentNotificationAccessPermission
|
binding.notificationAccessPermission = device.currentNotificationAccessPermission
|
||||||
binding.protectionLevel = device.currentProtectionLevel
|
binding.protectionLevel = device.currentProtectionLevel
|
||||||
|
binding.overlayPermission = device.currentOverlayPermission
|
||||||
binding.didAppDowngrade = device.currentAppVersion < device.highestAppVersion
|
binding.didAppDowngrade = device.currentAppVersion < device.highestAppVersion
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -354,6 +364,7 @@ interface ManageDeviceFragmentHandlers {
|
||||||
fun changeNetworkTimeVerification(newValue: NetworkTime)
|
fun changeNetworkTimeVerification(newValue: NetworkTime)
|
||||||
fun openUsageStatsSettings()
|
fun openUsageStatsSettings()
|
||||||
fun openNotificationAccessSettings()
|
fun openNotificationAccessSettings()
|
||||||
|
fun openDrawOverOtherAppsScreen()
|
||||||
fun manageDeviceAdmin()
|
fun manageDeviceAdmin()
|
||||||
fun editDeviceTitle()
|
fun editDeviceTitle()
|
||||||
fun showAuthenticationScreen()
|
fun showAuthenticationScreen()
|
||||||
|
|
|
@ -41,6 +41,7 @@ object ManageDeviceManipulation {
|
||||||
binding.hasManipulatedDeviceAdmin = device?.manipulationOfProtectionLevel ?: false
|
binding.hasManipulatedDeviceAdmin = device?.manipulationOfProtectionLevel ?: false
|
||||||
binding.hasManipulatedUsageStatsAccess = device?.manipulationOfUsageStats ?: false
|
binding.hasManipulatedUsageStatsAccess = device?.manipulationOfUsageStats ?: false
|
||||||
binding.hasManipulatedNotificationAccess = device?.manipulationOfNotificationAccess ?: false
|
binding.hasManipulatedNotificationAccess = device?.manipulationOfNotificationAccess ?: false
|
||||||
|
binding.hasManipulatedOverlayPermission = device?.manipulationOfOverlayPermission ?: false
|
||||||
binding.hasManipulationReboot = device?.manipulationDidReboot ?: false
|
binding.hasManipulationReboot = device?.manipulationDidReboot ?: false
|
||||||
binding.hasHadManipulation = (device?.hadManipulation ?: false) and (! (device?.hasActiveManipulationWarning ?: false))
|
binding.hasHadManipulation = (device?.hadManipulation ?: false) and (! (device?.hasActiveManipulationWarning ?: false))
|
||||||
binding.hasAnyManipulation = device?.hasAnyManipulation ?: false
|
binding.hasAnyManipulation = device?.hasAnyManipulation ?: false
|
||||||
|
@ -62,6 +63,7 @@ object ManageDeviceManipulation {
|
||||||
binding.deviceAdminDisabledCheckbox,
|
binding.deviceAdminDisabledCheckbox,
|
||||||
binding.usageAccessCheckbox,
|
binding.usageAccessCheckbox,
|
||||||
binding.notificationAccessCheckbox,
|
binding.notificationAccessCheckbox,
|
||||||
|
binding.overlayPermissionCheckbox,
|
||||||
binding.rebootCheckbox,
|
binding.rebootCheckbox,
|
||||||
binding.hadManipulationCheckbox
|
binding.hadManipulationCheckbox
|
||||||
)
|
)
|
||||||
|
@ -80,6 +82,7 @@ object ManageDeviceManipulation {
|
||||||
ignoreNotificationAccessManipulation = binding.notificationAccessCheckbox.isChecked && binding.hasManipulatedNotificationAccess == true,
|
ignoreNotificationAccessManipulation = binding.notificationAccessCheckbox.isChecked && binding.hasManipulatedNotificationAccess == true,
|
||||||
ignoreDeviceAdminManipulationAttempt = binding.deviceAdminDisableAttemptCheckbox.isChecked && binding.hasTriedManipulatingDeviceAdmin == true,
|
ignoreDeviceAdminManipulationAttempt = binding.deviceAdminDisableAttemptCheckbox.isChecked && binding.hasTriedManipulatingDeviceAdmin == true,
|
||||||
ignoreDeviceAdminManipulation = binding.deviceAdminDisabledCheckbox.isChecked && binding.hasManipulatedDeviceAdmin == true,
|
ignoreDeviceAdminManipulation = binding.deviceAdminDisabledCheckbox.isChecked && binding.hasManipulatedDeviceAdmin == true,
|
||||||
|
ignoreOverlayPermissionManipulation = binding.overlayPermissionCheckbox.isChecked && binding.hasManipulatedOverlayPermission == true,
|
||||||
ignoreAppDowngrade = binding.appVersionCheckbox.isChecked && binding.hasManipulatedAppVersion == true,
|
ignoreAppDowngrade = binding.appVersionCheckbox.isChecked && binding.hasManipulatedAppVersion == true,
|
||||||
ignoreReboot = binding.rebootCheckbox.isChecked && binding.hasManipulationReboot == true,
|
ignoreReboot = binding.rebootCheckbox.isChecked && binding.hasManipulationReboot == true,
|
||||||
ignoreHadManipulation = binding.hadManipulationCheckbox.isChecked || (
|
ignoreHadManipulation = binding.hadManipulationCheckbox.isChecked || (
|
||||||
|
|
|
@ -35,6 +35,8 @@ import io.timelimit.android.integration.platform.android.AdminReceiver
|
||||||
import io.timelimit.android.logic.AppLogic
|
import io.timelimit.android.logic.AppLogic
|
||||||
import io.timelimit.android.logic.DefaultAppLogic
|
import io.timelimit.android.logic.DefaultAppLogic
|
||||||
import io.timelimit.android.ui.manage.device.manage.InformAboutDeviceOwnerDialogFragment
|
import io.timelimit.android.ui.manage.device.manage.InformAboutDeviceOwnerDialogFragment
|
||||||
|
import android.net.Uri
|
||||||
|
|
||||||
|
|
||||||
class SetupDevicePermissionsFragment : Fragment() {
|
class SetupDevicePermissionsFragment : Fragment() {
|
||||||
private val logic: AppLogic by lazy { DefaultAppLogic.with(context!!) }
|
private val logic: AppLogic by lazy { DefaultAppLogic.with(context!!) }
|
||||||
|
@ -93,6 +95,14 @@ class SetupDevicePermissionsFragment : Fragment() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun openDrawOverOtherAppsScreen() {
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||||
|
startActivity(
|
||||||
|
Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + context!!.packageName))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun gotoNextStep() {
|
override fun gotoNextStep() {
|
||||||
navigation.safeNavigate(
|
navigation.safeNavigate(
|
||||||
SetupDevicePermissionsFragmentDirections
|
SetupDevicePermissionsFragmentDirections
|
||||||
|
@ -113,6 +123,7 @@ class SetupDevicePermissionsFragment : Fragment() {
|
||||||
binding.notificationAccessPermission = platform.getNotificationAccessPermissionStatus()
|
binding.notificationAccessPermission = platform.getNotificationAccessPermissionStatus()
|
||||||
binding.protectionLevel = platform.getCurrentProtectionLevel()
|
binding.protectionLevel = platform.getCurrentProtectionLevel()
|
||||||
binding.usageStatsAccess = platform.getForegroundAppPermissionStatus()
|
binding.usageStatsAccess = platform.getForegroundAppPermissionStatus()
|
||||||
|
binding.overlayPermission = platform.getOverlayPermissionStatus()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
|
@ -126,5 +137,6 @@ interface SetupDevicePermissionsHandlers {
|
||||||
fun manageDeviceAdmin()
|
fun manageDeviceAdmin()
|
||||||
fun openUsageStatsSettings()
|
fun openUsageStatsSettings()
|
||||||
fun openNotificationAccessSettings()
|
fun openNotificationAccessSettings()
|
||||||
|
fun openDrawOverOtherAppsScreen()
|
||||||
fun gotoNextStep()
|
fun gotoNextStep()
|
||||||
}
|
}
|
||||||
|
|
64
app/src/main/res/layout/blocking_overlay.xml
Normal file
64
app/src/main/res/layout/blocking_overlay.xml
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
<?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/>.
|
||||||
|
-->
|
||||||
|
<layout>
|
||||||
|
<data>
|
||||||
|
<variable
|
||||||
|
name="showWarningMessage"
|
||||||
|
type="boolean" />
|
||||||
|
|
||||||
|
<import type="android.view.View" />
|
||||||
|
</data>
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:background="@color/white"
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_centerInParent="true"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_gravity="center_horizontal"
|
||||||
|
android:src="@mipmap/ic_launcher"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:visibility="@{showWarningMessage ? View.VISIBLE : View.GONE}"
|
||||||
|
android:layout_margin="16dp"
|
||||||
|
android:gravity="center_horizontal"
|
||||||
|
android:textAppearance="?android:textAppearanceMedium"
|
||||||
|
android:text="@string/lock_overlay_warning"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_margin="8dp"
|
||||||
|
android:gravity="center_horizontal"
|
||||||
|
android:textAppearance="?android:textAppearanceSmall"
|
||||||
|
android:text="@string/app_name"
|
||||||
|
android:layout_alignParentBottom="true"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content" />
|
||||||
|
|
||||||
|
</RelativeLayout>
|
||||||
|
</layout>
|
|
@ -54,6 +54,10 @@
|
||||||
name="protectionLevel"
|
name="protectionLevel"
|
||||||
type="io.timelimit.android.integration.platform.ProtectionLevel" />
|
type="io.timelimit.android.integration.platform.ProtectionLevel" />
|
||||||
|
|
||||||
|
<variable
|
||||||
|
name="overlayPermission"
|
||||||
|
type="RuntimePermissionStatus" />
|
||||||
|
|
||||||
<variable
|
<variable
|
||||||
name="handlers"
|
name="handlers"
|
||||||
type="io.timelimit.android.ui.manage.device.manage.ManageDeviceFragmentHandlers" />
|
type="io.timelimit.android.ui.manage.device.manage.ManageDeviceFragmentHandlers" />
|
||||||
|
@ -390,6 +394,73 @@
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</androidx.cardview.widget.CardView>
|
</androidx.cardview.widget.CardView>
|
||||||
|
|
||||||
|
<androidx.cardview.widget.CardView
|
||||||
|
android:visibility="gone"
|
||||||
|
android:onClick="@{() -> handlers.openDrawOverOtherAppsScreen()}"
|
||||||
|
android:foreground="?selectableItemBackground"
|
||||||
|
android:clickable="@{safeUnbox(isThisDevice) && (overlayPermission != RuntimePermissionStatus.NotRequired)}"
|
||||||
|
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_permissions_overlay_title"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:textAppearance="?android:textAppearanceMedium"
|
||||||
|
android:text="@string/manage_device_permissions_overlay_text"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:visibility="@{overlayPermission == RuntimePermissionStatus.Granted ? 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="@{overlayPermission == RuntimePermissionStatus.NotGranted ? 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="@{overlayPermission == RuntimePermissionStatus.NotRequired ? View.VISIBLE : View.GONE}"
|
||||||
|
android:textColor="@color/green"
|
||||||
|
android:textAppearance="?android:textAppearanceMedium"
|
||||||
|
android:text="@string/manage_device_permission_status_not_required"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:visibility="@{(( overlayPermission != RuntimePermissionStatus.NotRequired) && (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) || (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
|
<androidx.cardview.widget.CardView
|
||||||
android:visibility="@{BuildConfig.hasServer ? View.VISIBLE : View.GONE}"
|
android:visibility="@{BuildConfig.hasServer ? View.VISIBLE : View.GONE}"
|
||||||
app:cardUseCompatPadding="true"
|
app:cardUseCompatPadding="true"
|
||||||
|
|
|
@ -30,6 +30,10 @@
|
||||||
name="protectionLevel"
|
name="protectionLevel"
|
||||||
type="io.timelimit.android.integration.platform.ProtectionLevel" />
|
type="io.timelimit.android.integration.platform.ProtectionLevel" />
|
||||||
|
|
||||||
|
<variable
|
||||||
|
name="overlayPermission"
|
||||||
|
type="RuntimePermissionStatus" />
|
||||||
|
|
||||||
<variable
|
<variable
|
||||||
name="handlers"
|
name="handlers"
|
||||||
type="io.timelimit.android.ui.setup.SetupDevicePermissionsHandlers" />
|
type="io.timelimit.android.ui.setup.SetupDevicePermissionsHandlers" />
|
||||||
|
@ -229,6 +233,65 @@
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</androidx.cardview.widget.CardView>
|
</androidx.cardview.widget.CardView>
|
||||||
|
|
||||||
|
<androidx.cardview.widget.CardView
|
||||||
|
android:visibility="gone"
|
||||||
|
android:onClick="@{() -> handlers.openDrawOverOtherAppsScreen()}"
|
||||||
|
android:foreground="?selectableItemBackground"
|
||||||
|
android:clickable="@{usageStatsAccess != RuntimePermissionStatus.NotRequired}"
|
||||||
|
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_permissions_overlay_title"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:textAppearance="?android:textAppearanceMedium"
|
||||||
|
android:text="@string/manage_device_permissions_overlay_text"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:visibility="@{overlayPermission == RuntimePermissionStatus.Granted ? 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="@{overlayPermission == RuntimePermissionStatus.NotGranted ? 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="@{overlayPermission == RuntimePermissionStatus.NotRequired ? View.VISIBLE : View.GONE}"
|
||||||
|
android:textColor="@color/green"
|
||||||
|
android:textAppearance="?android:textAppearanceMedium"
|
||||||
|
android:text="@string/manage_device_permission_status_not_required"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:visibility="@{overlayPermission != RuntimePermissionStatus.NotRequired ? 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" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
</androidx.cardview.widget.CardView>
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:orientation="horizontal"
|
android:orientation="horizontal"
|
||||||
|
|
|
@ -33,6 +33,10 @@
|
||||||
name="hasManipulatedNotificationAccess"
|
name="hasManipulatedNotificationAccess"
|
||||||
type="Boolean" />
|
type="Boolean" />
|
||||||
|
|
||||||
|
<variable
|
||||||
|
name="hasManipulatedOverlayPermission"
|
||||||
|
type="Boolean" />
|
||||||
|
|
||||||
<variable
|
<variable
|
||||||
name="hasManipulatedAppVersion"
|
name="hasManipulatedAppVersion"
|
||||||
type="Boolean" />
|
type="Boolean" />
|
||||||
|
@ -107,6 +111,13 @@
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content" />
|
android:layout_height="wrap_content" />
|
||||||
|
|
||||||
|
<CheckBox
|
||||||
|
android:visibility="@{safeUnbox(hasManipulatedOverlayPermission) ? View.VISIBLE : View.GONE}"
|
||||||
|
android:id="@+id/overlay_permission_checkbox"
|
||||||
|
android:text="@string/manage_device_manipulation_overlay_permission"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content" />
|
||||||
|
|
||||||
<CheckBox
|
<CheckBox
|
||||||
android:visibility="@{safeUnbox(hasManipulatedAppVersion) ? View.VISIBLE : View.GONE}"
|
android:visibility="@{safeUnbox(hasManipulatedAppVersion) ? View.VISIBLE : View.GONE}"
|
||||||
android:id="@+id/app_version_checkbox"
|
android:id="@+id/app_version_checkbox"
|
||||||
|
|
|
@ -83,4 +83,9 @@
|
||||||
<string name="lock_reason_short_missing_network_time">Netzwerkzeit erforderlich</string>
|
<string name="lock_reason_short_missing_network_time">Netzwerkzeit erforderlich</string>
|
||||||
<string name="lock_reason_short_requires_current_device">nicht als aktuelles Gerät gewählt</string>
|
<string name="lock_reason_short_requires_current_device">nicht als aktuelles Gerät gewählt</string>
|
||||||
<string name="lock_reason_short_notification_blocking">alle Benachrichtigungen werden blockiert</string>
|
<string name="lock_reason_short_notification_blocking">alle Benachrichtigungen werden blockiert</string>
|
||||||
|
|
||||||
|
<string name="lock_overlay_warning">
|
||||||
|
Öffnen des Sperrbildschirms fehlgeschlagen.
|
||||||
|
Versuche es, den Home- oder Anwendungslisten-Button zu verwenden, um diesen Bildschirm zu verlassen.
|
||||||
|
</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
<string name="manage_device_manipulation_device_admin_disable_attempt">Geräteadministrator-Deaktivierung wurde versucht</string>
|
<string name="manage_device_manipulation_device_admin_disable_attempt">Geräteadministrator-Deaktivierung wurde versucht</string>
|
||||||
<string name="manage_device_manipulation_usage_stats_access">Nutzungsdatenzugriff</string>
|
<string name="manage_device_manipulation_usage_stats_access">Nutzungsdatenzugriff</string>
|
||||||
<string name="manage_device_manipulation_notification_access">Benachrichtigungszugriff</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_app_version">ältere App-Version installiert</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_reboot">Gerät wurde neu gestartet</string>
|
||||||
<string name="manage_device_manipulation_existed">Es gab eine Manipulation, die wieder beendet wurde</string>
|
<string name="manage_device_manipulation_existed">Es gab eine Manipulation, die wieder beendet wurde</string>
|
||||||
|
|
|
@ -47,6 +47,11 @@
|
||||||
deren Benachrichtigungen zu sperren.
|
deren Benachrichtigungen zu sperren.
|
||||||
</string>
|
</string>
|
||||||
|
|
||||||
|
<string name="manage_device_permissions_overlay_title">Über anderen Apps anzeigen</string>
|
||||||
|
<string name="manage_device_permissions_overlay_text">
|
||||||
|
Das Anzeigen über anderen Apps 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_title">Geräte-Administrator</string>
|
||||||
<string name="manage_device_permission_device_admin_text_disabled">
|
<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.
|
Die Geräte-Administrator-Berechtigung wurde nicht gewährt. TimeLimit kann jederzeit über die Systemeinstellungen beendet werden.
|
||||||
|
|
|
@ -87,4 +87,9 @@
|
||||||
<string name="lock_reason_short_missing_network_time">missing network time</string>
|
<string name="lock_reason_short_missing_network_time">missing network time</string>
|
||||||
<string name="lock_reason_short_requires_current_device">device must be the current device</string>
|
<string name="lock_reason_short_requires_current_device">device must be the current device</string>
|
||||||
<string name="lock_reason_short_notification_blocking">all notifications are blocked</string>
|
<string name="lock_reason_short_notification_blocking">all notifications are blocked</string>
|
||||||
|
|
||||||
|
<string name="lock_overlay_warning">
|
||||||
|
Failed to open the lock screen.
|
||||||
|
You can try using the home or overview button to leave this screen.
|
||||||
|
</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
<string name="manage_device_manipulation_device_admin_disable_attempt">disabling devcie admin was attempted</string>
|
<string name="manage_device_manipulation_device_admin_disable_attempt">disabling devcie admin was attempted</string>
|
||||||
<string name="manage_device_manipulation_usage_stats_access">usage stats access</string>
|
<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_notification_access">notification access</string>
|
||||||
|
<string name="manage_device_manipulation_overlay_permission">draw over other Apps permission</string>
|
||||||
<string name="manage_device_manipulation_app_version">older App version installed</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_reboot">device was rebooted</string>
|
||||||
<string name="manage_device_manipulation_existed">there was a manipulation which was stopped again</string>
|
<string name="manage_device_manipulation_existed">there was a manipulation which was stopped again</string>
|
||||||
|
|
|
@ -47,6 +47,11 @@
|
||||||
Notifications and their contents are not saved.
|
Notifications and their contents are not saved.
|
||||||
</string>
|
</string>
|
||||||
|
|
||||||
|
<string name="manage_device_permissions_overlay_title">Draw over other Apps</string>
|
||||||
|
<string name="manage_device_permissions_overlay_text">
|
||||||
|
Enabling drawing on top of other Apps can improve blocking in some cases.
|
||||||
|
</string>
|
||||||
|
|
||||||
<string name="manage_device_permission_device_admin_title">Device admin</string>
|
<string name="manage_device_permission_device_admin_title">Device admin</string>
|
||||||
<string name="manage_device_permission_device_admin_text_disabled">
|
<string name="manage_device_permission_device_admin_text_disabled">
|
||||||
The device admin permission was not granted.
|
The device admin permission was not granted.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue