summaryrefslogtreecommitdiff
path: root/permissionseos/src/main/java/foundation/e/advancedprivacy/externalinterfaces/permissions/PermissionsPrivacyModuleImpl.kt
diff options
context:
space:
mode:
Diffstat (limited to 'permissionseos/src/main/java/foundation/e/advancedprivacy/externalinterfaces/permissions/PermissionsPrivacyModuleImpl.kt')
-rw-r--r--permissionseos/src/main/java/foundation/e/advancedprivacy/externalinterfaces/permissions/PermissionsPrivacyModuleImpl.kt258
1 files changed, 258 insertions, 0 deletions
diff --git a/permissionseos/src/main/java/foundation/e/advancedprivacy/externalinterfaces/permissions/PermissionsPrivacyModuleImpl.kt b/permissionseos/src/main/java/foundation/e/advancedprivacy/externalinterfaces/permissions/PermissionsPrivacyModuleImpl.kt
new file mode 100644
index 0000000..0d32bce
--- /dev/null
+++ b/permissionseos/src/main/java/foundation/e/advancedprivacy/externalinterfaces/permissions/PermissionsPrivacyModuleImpl.kt
@@ -0,0 +1,258 @@
+/*
+ * Copyright (C) 2021 E FOUNDATION, 2022 MURENA SAS
+ *
+ * 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, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 foundation.e.advancedprivacy.permissions.externalinterfaces
+
+import android.annotation.TargetApi
+import android.app.AppOpsManager
+import android.app.AppOpsManager.OP_NONE
+import android.app.AppOpsManager.strOpToOp
+import android.app.NotificationChannel
+import android.content.Context
+import android.content.pm.PackageInfo
+import android.content.pm.PackageManager
+import android.content.pm.UserInfo
+import android.graphics.drawable.Drawable
+import android.net.IConnectivityManager
+import android.net.VpnManager
+import android.net.VpnManager.TYPE_VPN_SERVICE
+import android.os.Build
+import android.os.ServiceManager
+import android.os.UserHandle
+import android.os.UserManager
+import android.util.Log
+import foundation.e.advancedprivacy.domain.entities.AppOpModes
+import foundation.e.advancedprivacy.domain.entities.ApplicationDescription
+import foundation.e.advancedprivacy.domain.entities.ProfileType.MAIN
+import foundation.e.advancedprivacy.domain.entities.ProfileType.WORK
+import foundation.e.advancedprivacy.externalinterfaces.permissions.PermissionsPrivacyModuleBase
+
+/**
+ * Implements [IPermissionsPrivacyModule] with all privileges of a system app.
+ */
+class PermissionsPrivacyModuleImpl(context: Context) : PermissionsPrivacyModuleBase(context) {
+
+ private val appOpsManager: AppOpsManager
+ get() = context.getSystemService(Context.APP_OPS_SERVICE) as AppOpsManager
+
+ /**
+ * @see IPermissionsPrivacyModule.toggleDangerousPermission
+ * Always return true, permission is set using privileged capacities.
+ */
+ override fun toggleDangerousPermission(
+ appDesc: ApplicationDescription,
+ permissionName: String,
+ grant: Boolean
+ ): Boolean {
+ try {
+ if (grant) {
+ context.packageManager.grantRuntimePermission(
+ appDesc.packageName,
+ permissionName,
+ android.os.Process.myUserHandle()
+ )
+ } else {
+ context.packageManager.revokeRuntimePermission(
+ appDesc.packageName,
+ permissionName,
+ android.os.Process.myUserHandle()
+ )
+ }
+ } catch (e: Exception) {
+ Log.e("Permissions-e", "Exception while setting permission", e)
+ return false
+ }
+
+ return true
+ }
+
+ override fun setAppOpMode(
+ appDesc: ApplicationDescription,
+ appOpPermissionName: String,
+ status: AppOpModes
+ ): Boolean {
+ val op = strOpToOp(appOpPermissionName)
+ if (op != OP_NONE) {
+ appOpsManager.setMode(op, appDesc.uid, appDesc.packageName, status.modeValue)
+ }
+ return true
+ }
+
+ override fun getApplications(
+ filter: ((PackageInfo) -> Boolean)?
+ ): List<ApplicationDescription> {
+ val pm = context.packageManager
+ val mainUserId = UserHandle.myUserId()
+ val workProfileId = getWorkProfile()?.id
+
+ val userIds = listOf(mainUserId, workProfileId).filterNotNull()
+ return userIds.map { profileId ->
+ pm.getInstalledPackagesAsUser(PackageManager.GET_PERMISSIONS, profileId)
+ .filter { filter?.invoke(it) ?: true }
+ .map {
+ buildApplicationDescription(
+ appInfo = it.applicationInfo,
+ profileId = profileId,
+ profileType = if (profileId == mainUserId) MAIN else WORK
+ )
+ }
+ }.flatten()
+ }
+
+ override fun getApplicationIcon(app: ApplicationDescription): Drawable? {
+ return if (app.profileType == WORK) {
+ getWorkProfile()?.let { workProfile ->
+ val pm = context.packageManager
+ getApplicationIcon(
+ pm.getApplicationInfoAsUser(app.packageName, 0, workProfile.id)
+ )?.let {
+ pm.getUserBadgedIcon(it, workProfile.getUserHandle())
+ }
+ }
+ } else getApplicationIcon(app.packageName)
+ }
+
+ override fun setBlockable(notificationChannel: NotificationChannel) {
+ when (Build.VERSION.SDK_INT) {
+ 29 -> notificationChannel.setBlockableSystem(true)
+ 30, 31, 32, 33 -> notificationChannel.setBlockable(true)
+ else -> {
+ Log.e("Permissions-e", "Bad android sdk version")
+ }
+ }
+ }
+
+ override fun setVpnPackageAuthorization(packageName: String): Boolean {
+ return when (Build.VERSION.SDK_INT) {
+ 29 -> setVpnPackageAuthorizationSDK29(packageName)
+ 30 -> setVpnPackageAuthorizationSDK30(packageName)
+ 31, 32, 33 -> setVpnPackageAuthorizationSDK32(packageName)
+ else -> {
+ Log.e("Permissions-e", "Bad android sdk version")
+ false
+ }
+ }
+ }
+
+ @TargetApi(29)
+ private fun setVpnPackageAuthorizationSDK29(packageName: String): Boolean {
+ val service: IConnectivityManager = IConnectivityManager.Stub.asInterface(
+ ServiceManager.getService(Context.CONNECTIVITY_SERVICE)
+ )
+
+ try {
+ if (service.prepareVpn(null, packageName, UserHandle.myUserId())) {
+ // Authorize this app to initiate VPN connections in the future without user
+ // intervention.
+ service.setVpnPackageAuthorization(packageName, UserHandle.myUserId(), true)
+ return true
+ }
+ } catch (e: java.lang.Exception) {
+ Log.e("Permissions-e", "Exception while setting VpnPackageAuthorization", e)
+ } catch (e: NoSuchMethodError) {
+ Log.e("Permissions-e", "Bad android sdk version", e)
+ }
+ return false
+ }
+
+ @TargetApi(30)
+ private fun setVpnPackageAuthorizationSDK30(packageName: String): Boolean {
+ val service: IConnectivityManager = IConnectivityManager.Stub.asInterface(
+ ServiceManager.getService(Context.CONNECTIVITY_SERVICE)
+ )
+
+ try {
+ if (service.prepareVpn(null, packageName, UserHandle.myUserId())) {
+ // Authorize this app to initiate VPN connections in the future without user
+ // intervention.
+ service.setVpnPackageAuthorization(packageName, UserHandle.myUserId(), TYPE_VPN_SERVICE)
+ return true
+ }
+ } catch (e: java.lang.Exception) {
+ Log.e("Permissions-e", "Exception while setting VpnPackageAuthorization", e)
+ } catch (e: NoSuchMethodError) {
+ Log.e("Permissions-e", "Bad android sdk version", e)
+ }
+ return false
+ }
+
+ @TargetApi(31)
+ private fun setVpnPackageAuthorizationSDK32(packageName: String): Boolean {
+ val vpnManager = context.getSystemService(Context.VPN_MANAGEMENT_SERVICE) as VpnManager
+
+ try {
+ if (vpnManager.prepareVpn(null, packageName, UserHandle.myUserId())) {
+ // Authorize this app to initiate VPN connections in the future without user
+ // intervention.
+ vpnManager.setVpnPackageAuthorization(packageName, UserHandle.myUserId(), TYPE_VPN_SERVICE)
+ return true
+ }
+ } catch (e: java.lang.Exception) {
+ Log.e("Permissions-e", "Exception while setting VpnPackageAuthorization", e)
+ } catch (e: NoSuchMethodError) {
+ Log.e("Permissions-e", "Bad android sdk version", e)
+ }
+ return false
+ }
+
+ override fun getAlwaysOnVpnPackage(): String? {
+ return when (Build.VERSION.SDK_INT) {
+ 29, 30 -> getAlwaysOnVpnPackageSDK29()
+ 31, 32, 33 -> getAlwaysOnVpnPackageSDK32()
+ else -> {
+ Log.e("Permissions-e", "Bad android sdk version")
+ null
+ }
+ }
+ }
+
+ @TargetApi(29)
+ private fun getAlwaysOnVpnPackageSDK29(): String? {
+ val service: IConnectivityManager = IConnectivityManager.Stub.asInterface(
+ ServiceManager.getService(Context.CONNECTIVITY_SERVICE)
+ )
+
+ return try {
+ service.getAlwaysOnVpnPackage(UserHandle.myUserId())
+ } catch (e: java.lang.Exception) {
+ Log.e("Permissions-e", "Bad android sdk version ", e)
+ return null
+ }
+ }
+
+ @TargetApi(31)
+ private fun getAlwaysOnVpnPackageSDK32(): String? {
+ val vpnManager = context.getSystemService(Context.VPN_MANAGEMENT_SERVICE) as VpnManager
+ return try {
+ vpnManager.getAlwaysOnVpnPackageForUser(UserHandle.myUserId())
+ } catch (e: java.lang.Exception) {
+ Log.e("Permissions-e", "Bad android sdk version ", e)
+ return null
+ }
+ }
+
+ private fun getWorkProfile(): UserInfo? {
+ val userManager: UserManager = context.getSystemService(UserManager::class.java)
+ val userId = UserHandle.myUserId()
+ for (user in userManager.getProfiles(UserHandle.myUserId())) {
+ if (user.id != userId && userManager.isManagedProfile(user.id)) {
+ return user
+ }
+ }
+ return null
+ }
+}