From 9d55978063947d5865bb3fa4e0c2ebef78f78812 Mon Sep 17 00:00:00 2001
From: Guillaume Jacquart <guillaume.jacquart@hoodbrains.com>
Date: Mon, 6 Nov 2023 08:14:27 +0000
Subject: epic18: Manage VPN services for Tor or Tracker control

---
 permissionseos/.gitignore                          |   1 +
 permissionseos/build.gradle                        |  32 +++
 permissionseos/consumer-rules.pro                  |   0
 permissionseos/libs/hidden-apis-stub/.gitignore    |   1 +
 permissionseos/libs/hidden-apis-stub/build.gradle  |  35 +++
 .../hidden-apis-stub/src/main/AndroidManifest.xml  |  24 ++
 .../src/main/java/android/app/AppOpsManager.java   |  46 ++++
 .../main/java/android/app/NotificationChannel.java |  34 +++
 .../java/android/content/pm/PackageManager.java    | 104 +++++++++
 .../src/main/java/android/content/pm/UserInfo.java |  36 +++
 .../java/android/net/IConnectivityManager.java     |  65 ++++++
 .../src/main/java/android/net/VpnManager.java      |  64 +++++
 .../src/main/java/android/os/ServiceManager.java   |  24 ++
 .../src/main/java/android/os/UserHandle.java       |  24 ++
 .../src/main/java/android/os/UserManager.java      |  48 ++++
 permissionseos/proguard-rules.pro                  |  21 ++
 permissionseos/src/main/AndroidManifest.xml        |  59 +++++
 .../permissions/PermissionsPrivacyModuleImpl.kt    | 258 +++++++++++++++++++++
 18 files changed, 876 insertions(+)
 create mode 100644 permissionseos/.gitignore
 create mode 100644 permissionseos/build.gradle
 create mode 100644 permissionseos/consumer-rules.pro
 create mode 100644 permissionseos/libs/hidden-apis-stub/.gitignore
 create mode 100644 permissionseos/libs/hidden-apis-stub/build.gradle
 create mode 100644 permissionseos/libs/hidden-apis-stub/src/main/AndroidManifest.xml
 create mode 100644 permissionseos/libs/hidden-apis-stub/src/main/java/android/app/AppOpsManager.java
 create mode 100644 permissionseos/libs/hidden-apis-stub/src/main/java/android/app/NotificationChannel.java
 create mode 100644 permissionseos/libs/hidden-apis-stub/src/main/java/android/content/pm/PackageManager.java
 create mode 100644 permissionseos/libs/hidden-apis-stub/src/main/java/android/content/pm/UserInfo.java
 create mode 100644 permissionseos/libs/hidden-apis-stub/src/main/java/android/net/IConnectivityManager.java
 create mode 100644 permissionseos/libs/hidden-apis-stub/src/main/java/android/net/VpnManager.java
 create mode 100644 permissionseos/libs/hidden-apis-stub/src/main/java/android/os/ServiceManager.java
 create mode 100644 permissionseos/libs/hidden-apis-stub/src/main/java/android/os/UserHandle.java
 create mode 100644 permissionseos/libs/hidden-apis-stub/src/main/java/android/os/UserManager.java
 create mode 100644 permissionseos/proguard-rules.pro
 create mode 100644 permissionseos/src/main/AndroidManifest.xml
 create mode 100644 permissionseos/src/main/java/foundation/e/advancedprivacy/externalinterfaces/permissions/PermissionsPrivacyModuleImpl.kt

(limited to 'permissionseos')

diff --git a/permissionseos/.gitignore b/permissionseos/.gitignore
new file mode 100644
index 0000000..42afabf
--- /dev/null
+++ b/permissionseos/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/permissionseos/build.gradle b/permissionseos/build.gradle
new file mode 100644
index 0000000..d57ea9c
--- /dev/null
+++ b/permissionseos/build.gradle
@@ -0,0 +1,32 @@
+apply plugin: 'com.android.library'
+apply plugin: 'kotlin-android'
+
+android {
+    compileSdkVersion buildConfig.compileSdk
+
+    defaultConfig {
+        minSdkVersion buildConfig.minSdk
+        targetSdkVersion buildConfig.targetSdk
+
+        consumerProguardFiles "consumer-rules.pro"
+    }
+
+    buildTypes {
+        release {
+            minifyEnabled false
+            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+        }
+    }
+    compileOptions {
+        sourceCompatibility JavaVersion.VERSION_1_8
+        targetCompatibility JavaVersion.VERSION_1_8
+    }
+}
+
+dependencies {
+    compileOnly project(':permissionseos:libs:hidden-apis-stub')
+
+    implementation(libs.bundles.kotlin.android.coroutines)
+    implementation project(':core')
+
+}
diff --git a/permissionseos/consumer-rules.pro b/permissionseos/consumer-rules.pro
new file mode 100644
index 0000000..e69de29
diff --git a/permissionseos/libs/hidden-apis-stub/.gitignore b/permissionseos/libs/hidden-apis-stub/.gitignore
new file mode 100644
index 0000000..42afabf
--- /dev/null
+++ b/permissionseos/libs/hidden-apis-stub/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/permissionseos/libs/hidden-apis-stub/build.gradle b/permissionseos/libs/hidden-apis-stub/build.gradle
new file mode 100644
index 0000000..2043edc
--- /dev/null
+++ b/permissionseos/libs/hidden-apis-stub/build.gradle
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2022 E FOUNDATION
+ *
+ * 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/>.
+ */
+
+plugins {
+    id 'com.android.library'
+}
+
+android {
+    compileSdkVersion buildConfig.compileSdk
+}
+
+
+java {
+    sourceCompatibility = JavaVersion.VERSION_1_7
+    targetCompatibility = JavaVersion.VERSION_1_7
+}
+
+dependencies {
+    implementation 'org.jetbrains:annotations:15.0'
+    implementation 'androidx.annotation:annotation:1.5.0'
+}
diff --git a/permissionseos/libs/hidden-apis-stub/src/main/AndroidManifest.xml b/permissionseos/libs/hidden-apis-stub/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..61f315a
--- /dev/null
+++ b/permissionseos/libs/hidden-apis-stub/src/main/AndroidManifest.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2022 E FOUNDATION
+  ~
+  ~ 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/>.
+  -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    package="foundation.e.advancedprivacy.hidden.apis"
+    tools:ignore="ProtectedPermissions">
+
+</manifest>
diff --git a/permissionseos/libs/hidden-apis-stub/src/main/java/android/app/AppOpsManager.java b/permissionseos/libs/hidden-apis-stub/src/main/java/android/app/AppOpsManager.java
new file mode 100644
index 0000000..753b456
--- /dev/null
+++ b/permissionseos/libs/hidden-apis-stub/src/main/java/android/app/AppOpsManager.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2022 E FOUNDATION
+ *
+ * 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 android.app;
+
+import android.annotation.TargetApi;
+
+import androidx.annotation.DeprecatedSinceApi;
+import androidx.annotation.NonNull;
+
+// Stub based on:
+// https://gitlab.e.foundation/e/os/android_frameworks_base/-/blob/[SDK_VERSION]/core/java/android/app/AppOpsManager.java
+public class AppOpsManager {
+
+    public static final int OP_NONE = -1;
+
+    @TargetApi(29)
+    @DeprecatedSinceApi(
+            api = 34,
+            message = "Check disponibility in SDK34"
+    )
+    public static int strOpToOp(@NonNull String op) {
+        return 0;
+    }
+
+    @TargetApi(29)
+    @DeprecatedSinceApi(
+            api = 34,
+            message = "Check disponibility in SDK34"
+    )
+    public void setMode(int code, int uid, String packageName, int mode) {}
+}
diff --git a/permissionseos/libs/hidden-apis-stub/src/main/java/android/app/NotificationChannel.java b/permissionseos/libs/hidden-apis-stub/src/main/java/android/app/NotificationChannel.java
new file mode 100644
index 0000000..9e8d65a
--- /dev/null
+++ b/permissionseos/libs/hidden-apis-stub/src/main/java/android/app/NotificationChannel.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 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 android.app;
+
+import android.annotation.TargetApi;
+
+import androidx.annotation.DeprecatedSinceApi;
+
+public class NotificationChannel {
+
+    @TargetApi(29)
+    @DeprecatedSinceApi(api = 30, message = "Use setBlockable() instead.")
+    public void setBlockableSystem(boolean blockableSystem) {}
+
+    // Public in API 33.
+    @TargetApi(30)
+    public void setBlockable(boolean blockableSystem) {}
+
+}
diff --git a/permissionseos/libs/hidden-apis-stub/src/main/java/android/content/pm/PackageManager.java b/permissionseos/libs/hidden-apis-stub/src/main/java/android/content/pm/PackageManager.java
new file mode 100644
index 0000000..c6232ce
--- /dev/null
+++ b/permissionseos/libs/hidden-apis-stub/src/main/java/android/content/pm/PackageManager.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 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 android.content.pm;
+
+import android.annotation.TargetApi;
+import android.graphics.drawable.Drawable;
+import android.os.UserHandle;
+
+import androidx.annotation.DeprecatedSinceApi;
+import androidx.annotation.NonNull;
+import androidx.annotation.RequiresPermission;
+
+import java.util.List;
+import android.util.AndroidException;
+
+// Stub based on:
+// https://gitlab.e.foundation/e/os/android_frameworks_base/-/blob/[SDK_VERSION]/core/java/android/content/pm/PackageManager.java
+public abstract class PackageManager {
+
+    @TargetApi(29)
+    @DeprecatedSinceApi(
+            api = 34,
+            message = "Check availability in SDK34"
+    )
+    public static class NameNotFoundException extends AndroidException {
+        public NameNotFoundException() {
+        }
+
+        public NameNotFoundException(String name) {
+            super(name);
+        }
+    }
+
+
+    @TargetApi(29)
+    @DeprecatedSinceApi(
+            api = 34,
+            message = "Check disponibility in SDK34"
+    )
+    @RequiresPermission("android.permission.GRANT_RUNTIME_PERMISSIONS")
+    public abstract void grantRuntimePermission(
+        @NonNull String packageName,
+        @NonNull String permissionName,
+        @NonNull UserHandle user
+    );
+
+    @TargetApi(29)
+    @DeprecatedSinceApi(
+            api = 34,
+            message = "Check disponibility in SDK34"
+    )
+    @RequiresPermission("android.permission.REVOKE_RUNTIME_PERMISSIONS")
+    public abstract void revokeRuntimePermission(
+        @NonNull String packageName,
+        @NonNull String permissionName,
+        @NonNull UserHandle user
+    );
+
+    @TargetApi(29)
+    @DeprecatedSinceApi(
+        api = 33,
+        message = "@deprecated Use {@link #getApplicationInfoAsUser(String, ApplicationInfoFlags, int)} instead."
+    )
+    public abstract ApplicationInfo getApplicationInfoAsUser(
+        @NonNull String packageName,
+        int flags,
+        int userId
+    ) throws NameNotFoundException;
+
+
+    @TargetApi(29)
+    @DeprecatedSinceApi(
+            api = 34,
+            message = "Check disponibility in SDK34"
+    )
+    @RequiresPermission("android.permission.INTERACT_ACROSS_USERS_FULL")
+    public abstract List<PackageInfo> getInstalledPackagesAsUser(int flags, int userId);
+
+    // Public
+    public abstract List<PackageInfo> getInstalledPackages(int flags);
+
+    @NonNull
+    public abstract Drawable getUserBadgedIcon(
+        @NonNull Drawable drawable,
+        @NonNull UserHandle user
+    );
+
+    public static final int GET_PERMISSIONS = 0x00001000;
+}
diff --git a/permissionseos/libs/hidden-apis-stub/src/main/java/android/content/pm/UserInfo.java b/permissionseos/libs/hidden-apis-stub/src/main/java/android/content/pm/UserInfo.java
new file mode 100644
index 0000000..28a3732
--- /dev/null
+++ b/permissionseos/libs/hidden-apis-stub/src/main/java/android/content/pm/UserInfo.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 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 android.content.pm;
+
+import android.annotation.TargetApi;
+import android.os.UserHandle;
+
+import androidx.annotation.DeprecatedSinceApi;
+
+public class UserInfo {
+    public int id;
+
+    @TargetApi(29)
+    @DeprecatedSinceApi(
+            api = 34,
+            message = "Check availability in SDK34"
+    )
+    public UserHandle getUserHandle() {
+        return null;
+    }
+}
diff --git a/permissionseos/libs/hidden-apis-stub/src/main/java/android/net/IConnectivityManager.java b/permissionseos/libs/hidden-apis-stub/src/main/java/android/net/IConnectivityManager.java
new file mode 100644
index 0000000..53440e0
--- /dev/null
+++ b/permissionseos/libs/hidden-apis-stub/src/main/java/android/net/IConnectivityManager.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2022 E FOUNDATION
+ *
+ * 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 android.net;
+
+import android.annotation.TargetApi;
+
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.RemoteException;
+
+import androidx.annotation.DeprecatedSinceApi;
+
+// Stub based on:
+// https://gitlab.e.foundation/e/os/android_frameworks_base/-/blob/[SDK_VERSION]/core/java/android/net/IConnectivityManager.java
+public interface IConnectivityManager {
+
+    @TargetApi(29)
+    @DeprecatedSinceApi(
+            api = 31,
+            message = "Moved to android.net.VpnManager"
+    )
+    boolean prepareVpn(String oldPackage, String newPackage, int userId) throws RemoteException;
+
+    @TargetApi(29)
+    @DeprecatedSinceApi(
+        api = 30,
+        message = "Use instead setVpnPackageAuthorization(String packageName, int userId, int vpnType)"
+    )
+    void setVpnPackageAuthorization(String packageName, int userId, boolean authorized) throws RemoteException;
+
+    @TargetApi(30)
+    @DeprecatedSinceApi(
+            api = 31,
+            message = "Moved to android.net.VpnManager"
+    )
+    void setVpnPackageAuthorization(String packageName, int userId, int vpnType) throws RemoteException;
+
+    @TargetApi(29)
+    @DeprecatedSinceApi(
+            api = 31,
+            message = "Moved to android.net.VpnManager"
+    )
+    public String getAlwaysOnVpnPackage(int userId) throws RemoteException;
+
+    public abstract static class Stub extends Binder implements IConnectivityManager {
+        public static IConnectivityManager asInterface(IBinder obj) {
+            return null;
+        }
+    }
+}
diff --git a/permissionseos/libs/hidden-apis-stub/src/main/java/android/net/VpnManager.java b/permissionseos/libs/hidden-apis-stub/src/main/java/android/net/VpnManager.java
new file mode 100644
index 0000000..dab2173
--- /dev/null
+++ b/permissionseos/libs/hidden-apis-stub/src/main/java/android/net/VpnManager.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2022 E FOUNDATION
+ *
+ * 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 android.net;
+
+import android.annotation.TargetApi;
+
+import androidx.annotation.DeprecatedSinceApi;
+import androidx.annotation.Nullable;
+import androidx.annotation.RequiresPermission;
+
+// Stub based on:
+// https://gitlab.e.foundation/e/os/android_frameworks_base/-/blob/[SDK_VERSION]/core/java/android/net/VpnManager.java
+public class VpnManager {
+    public static final int TYPE_VPN_SERVICE = 1;
+
+    @TargetApi(31)
+    @DeprecatedSinceApi(
+            api = 34,
+            message = "Check disponibility in SDK34"
+    )
+    public boolean prepareVpn(
+        @Nullable String oldPackage,
+        @Nullable String newPackage,
+        int userId
+    ) {
+        return true;
+    }
+
+    @TargetApi(31)
+    @DeprecatedSinceApi(
+            api = 34,
+            message = "Check disponibility in SDK34"
+    )
+    public void setVpnPackageAuthorization(
+            String packageName,
+            int userId,
+            int vpnType
+    ) {}
+
+    @TargetApi(31)
+    @DeprecatedSinceApi(
+            api = 34,
+            message = "Check disponibility in SDK34"
+    )
+    @RequiresPermission("android.permission.CONTROL_ALWAYS_ON_VPN")
+    public String getAlwaysOnVpnPackageForUser(int userId) {
+        return null;
+    }
+}
diff --git a/permissionseos/libs/hidden-apis-stub/src/main/java/android/os/ServiceManager.java b/permissionseos/libs/hidden-apis-stub/src/main/java/android/os/ServiceManager.java
new file mode 100644
index 0000000..4696b79
--- /dev/null
+++ b/permissionseos/libs/hidden-apis-stub/src/main/java/android/os/ServiceManager.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2022 E FOUNDATION
+ *
+ * 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 android.os;
+
+public class ServiceManager {
+    public static IBinder getService(String name) {
+        return null;
+    }
+}
diff --git a/permissionseos/libs/hidden-apis-stub/src/main/java/android/os/UserHandle.java b/permissionseos/libs/hidden-apis-stub/src/main/java/android/os/UserHandle.java
new file mode 100644
index 0000000..df56daf
--- /dev/null
+++ b/permissionseos/libs/hidden-apis-stub/src/main/java/android/os/UserHandle.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2022 E FOUNDATION
+ *
+ * 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 android.os;
+
+public class UserHandle {
+    public static /*@UserIdInt*/ int myUserId() {
+        return 0;
+    }
+}
diff --git a/permissionseos/libs/hidden-apis-stub/src/main/java/android/os/UserManager.java b/permissionseos/libs/hidden-apis-stub/src/main/java/android/os/UserManager.java
new file mode 100644
index 0000000..be6797e
--- /dev/null
+++ b/permissionseos/libs/hidden-apis-stub/src/main/java/android/os/UserManager.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 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 android.os;
+
+import android.annotation.TargetApi;
+import android.content.pm.UserInfo;
+
+import androidx.annotation.DeprecatedSinceApi;
+import androidx.annotation.RequiresPermission;
+import java.util.List;
+
+public class UserManager {
+
+    @TargetApi(29)
+    @DeprecatedSinceApi(
+            api = 34,
+            message = "Check availability in SDK34"
+    )
+    @RequiresPermission("android.permission.MANAGE_USERS")
+    public List<UserInfo> getProfiles(int userHandle) {
+        return null;
+    }
+
+    @TargetApi(29)
+    @DeprecatedSinceApi(
+            api = 34,
+            message = "Check availability in SDK34"
+    )
+    @RequiresPermission("android.permission.MANAGE_USERS")
+    public boolean isManagedProfile(int userId) {
+        return false;
+    }
+}
diff --git a/permissionseos/proguard-rules.pro b/permissionseos/proguard-rules.pro
new file mode 100644
index 0000000..481bb43
--- /dev/null
+++ b/permissionseos/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+#   http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+#   public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
\ No newline at end of file
diff --git a/permissionseos/src/main/AndroidManifest.xml b/permissionseos/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..ed25c1c
--- /dev/null
+++ b/permissionseos/src/main/AndroidManifest.xml
@@ -0,0 +1,59 @@
+<!--
+  ~ Copyright  (C) 2023 MURENA SAS
+  ~ Copyright (C) 2022 E FOUNDATION
+  ~
+  ~ 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/>.
+  -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    package="foundation.e.advancedprivacy.permissions.eos">
+
+    <uses-permission android:name="android.permission.MANAGE_APP_OPS_MODES"
+        tools:ignore="ProtectedPermissions" />
+    <uses-permission
+        android:name="android.permission.GRANT_RUNTIME_PERMISSIONS"
+        tools:ignore="ProtectedPermissions"
+        />
+    <uses-permission
+        android:name="android.permission.REVOKE_RUNTIME_PERMISSIONS"
+        tools:ignore="ProtectedPermissions"
+        />
+
+    <!-- The following permission have privileged protection level.
+        These permissions are granted only if the app is privileged by the system,
+         like installed in /system/priv-app and a privapp-permissions in /system/etc/permissions/
+        (see eprivavymoduledemo for an example) -->
+    <uses-permission
+        android:name="android.permission.UPDATE_APP_OPS_STATS"
+        tools:ignore="ProtectedPermissions"
+        />
+    <uses-permission android:name="android.permission.WATCH_APPOPS"
+        tools:ignore="ProtectedPermissions"
+        />
+    <uses-permission
+        android:name="android.permission.GET_APP_OPS_STATS"
+        tools:ignore="ProtectedPermissions"
+        />
+    <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS"
+        tools:ignore="ProtectedPermissions"
+        />
+    <uses-permission android:name="android.permission.CONTROL_VPN"
+        tools:ignore="ProtectedPermissions" />
+    <uses-permission android:name="android.permission.CONTROL_ALWAYS_ON_VPN"
+        tools:ignore="ProtectedPermissions" />
+    <uses-permission android:name="android.permission.MANAGE_USERS"
+        tools:ignore="ProtectedPermissions" />
+    <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL"
+        tools:ignore="ProtectedPermissions" />
+</manifest>
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
+    }
+}
-- 
cgit v1.2.1