Self grant runtime permissions

This commit is contained in:
Jonas Lochmann 2024-04-15 02:00:00 +02:00
parent 82e8f65f0d
commit 141c967b74
No known key found for this signature in database
GPG key ID: 8B8C9AEE10FA5B36
7 changed files with 87 additions and 9 deletions

View file

@ -1,5 +1,5 @@
/*
* TimeLimit Copyright <C> 2019 - 2023 Jonas Lochmann
* TimeLimit Copyright <C> 2019 - 2024 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
@ -25,4 +25,7 @@ interface DeviceOwnerApi {
fun setOrganizationName(name: String)
fun transferOwnership(packageName: String, dryRun: Boolean = false)
// returns true on success; never throws
fun grantLocationAccess(): Boolean
}

View file

@ -1,5 +1,5 @@
/*
* TimeLimit Copyright <C> 2019 - 2023 Jonas Lochmann
* TimeLimit Copyright <C> 2019 - 2024 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
@ -15,6 +15,7 @@
*/
package io.timelimit.android.integration.platform.android
import android.Manifest
import android.app.admin.DeviceAdminReceiver
import android.app.admin.DevicePolicyManager
import android.content.ComponentName
@ -124,4 +125,14 @@ class AndroidDeviceOwnerApi(
devicePolicyManager.setDelegatedScopes(componentName, packageName, emptyList())
devicePolicyManager.transferOwnership(componentName, targetComponentName, null)
}
override fun grantLocationAccess(): Boolean {
if (VERSION.SDK_INT < VERSION_CODES.LOLLIPOP) return false
if (!devicePolicyManager.isDeviceOwnerApp(componentName.packageName)) return false
return devicePolicyManager.setPermissionGrantState(
componentName, componentName.packageName, Manifest.permission.ACCESS_FINE_LOCATION,
DevicePolicyManager.PERMISSION_GRANT_STATE_GRANTED
)
}
}

View file

@ -1,5 +1,5 @@
/*
* TimeLimit Copyright <C> 2019 - 2023 Jonas Lochmann
* TimeLimit Copyright <C> 2019 - 2024 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
@ -15,6 +15,7 @@
*/
package io.timelimit.android.integration.platform.android
import android.Manifest
import android.annotation.TargetApi
import android.app.ActivityManager
import android.app.Application
@ -40,6 +41,7 @@ import android.widget.Toast
import androidx.collection.LruCache
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import androidx.core.content.ContextCompat
import androidx.fragment.app.FragmentActivity
import androidx.lifecycle.LiveData
import io.timelimit.android.BuildConfig
@ -511,6 +513,40 @@ class AndroidIntegration(context: Context): PlatformIntegration(maximumProtectio
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
policyManager.addUserRestriction(deviceAdmin, UserManager.DISALLOW_SAFE_BOOT)
}
policyManager.getPermissionGrantState(
deviceAdmin,
context.packageName,
Manifest.permission.ACCESS_FINE_LOCATION,
).let {
if (it == DevicePolicyManager.PERMISSION_GRANT_STATE_DEFAULT) {
policyManager.setPermissionGrantState(
deviceAdmin,
context.packageName,
Manifest.permission.ACCESS_FINE_LOCATION,
if (ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED)
DevicePolicyManager.PERMISSION_GRANT_STATE_GRANTED
else
DevicePolicyManager.PERMISSION_GRANT_STATE_DENIED
)
}
}
policyManager.setPermissionGrantState(
deviceAdmin,
context.packageName,
Manifest.permission.CALL_PHONE,
DevicePolicyManager.PERMISSION_GRANT_STATE_GRANTED
)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
policyManager.setPermissionGrantState(
deviceAdmin,
context.packageName,
Manifest.permission.POST_NOTIFICATIONS,
DevicePolicyManager.PERMISSION_GRANT_STATE_GRANTED
)
}
} else /* disable lockdown */ {
// enable problematic features
policyManager.clearUserRestriction(deviceAdmin, UserManager.DISALLOW_ADD_USER)
@ -520,6 +556,29 @@ class AndroidIntegration(context: Context): PlatformIntegration(maximumProtectio
policyManager.clearUserRestriction(deviceAdmin, UserManager.DISALLOW_SAFE_BOOT)
}
policyManager.setPermissionGrantState(
deviceAdmin,
context.packageName,
Manifest.permission.ACCESS_FINE_LOCATION,
DevicePolicyManager.PERMISSION_GRANT_STATE_DEFAULT
)
policyManager.setPermissionGrantState(
deviceAdmin,
context.packageName,
Manifest.permission.CALL_PHONE,
DevicePolicyManager.PERMISSION_GRANT_STATE_DEFAULT
)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
policyManager.setPermissionGrantState(
deviceAdmin,
context.packageName,
Manifest.permission.POST_NOTIFICATIONS,
DevicePolicyManager.PERMISSION_GRANT_STATE_DEFAULT
)
}
enableSystemApps()
stopSuspendingForAllApps()
setBlockedFeatures(emptySet())

View file

@ -207,5 +207,7 @@ class DummyIntegration(
override fun setOrganizationName(name: String) = throw SecurityException()
override fun transferOwnership(packageName: String, dryRun: Boolean) = throw IllegalStateException("unsupported operation")
override fun grantLocationAccess(): Boolean = false
}
}

View file

@ -1,5 +1,5 @@
/*
* TimeLimit Copyright <C> 2019 - 2022 Jonas Lochmann
* TimeLimit Copyright <C> 2019 - 2024 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
@ -124,7 +124,7 @@ class LockActionFragment : Fragment() {
override fun setThisDeviceAsCurrentDevice() = this@LockActionFragment.setThisDeviceAsCurrentDevice()
override fun requestLocationPermission() {
RequestWifiPermission.doRequest(this@LockActionFragment, LOCATION_REQUEST_CODE)
RequestWifiPermission.doRequest(this@LockActionFragment, LOCATION_REQUEST_CODE, auth.logic.platformIntegration)
}
override fun disableLimitsTemporarily() {

View file

@ -1,5 +1,5 @@
/*
* TimeLimit Copyright <C> 2019 - 2023 Jonas Lochmann
* TimeLimit Copyright <C> 2019 - 2024 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
@ -117,7 +117,7 @@ object ManageCategoryNetworksView {
}
view.grantPermissionButton.setOnClickListener {
RequestWifiPermission.doRequest(fragment, permissionRequestCode)
RequestWifiPermission.doRequest(fragment, permissionRequestCode, auth.logic.platformIntegration)
}
isFullVersionLive.observe(lifecycleOwner, Observer { isFullVersion ->

View file

@ -1,5 +1,5 @@
/*
* TimeLimit Copyright <C> 2019 - 2020 Jonas Lochmann
* TimeLimit Copyright <C> 2019 - 2024 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
@ -26,6 +26,7 @@ import android.widget.Toast
import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment
import io.timelimit.android.R
import io.timelimit.android.integration.platform.PlatformIntegration
object RequestWifiPermission {
private fun isLocationEnabled(context: Context): Boolean = if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P)
@ -36,8 +37,10 @@ object RequestWifiPermission {
locationManager.isLocationEnabled
}
fun doRequest(fragment: Fragment, permissionRequestCode: Int) {
fun doRequest(fragment: Fragment, permissionRequestCode: Int, platformIntegration: PlatformIntegration) {
if (ContextCompat.checkSelfPermission(fragment.requireContext(), Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
if (platformIntegration.deviceOwner.grantLocationAccess()) return
fragment.requestPermissions(arrayOf(Manifest.permission.ACCESS_FINE_LOCATION), permissionRequestCode)
} else if (!isLocationEnabled(fragment.requireContext())) {
Toast.makeText(fragment.requireContext(), R.string.category_networks_toast_enable_location_service, Toast.LENGTH_SHORT).show()