diff --git a/api/src/main/java/io/github/libxposed/api/XposedContext.java b/api/src/main/java/io/github/libxposed/api/XposedContext.java
deleted file mode 100644
index db2401c..0000000
--- a/api/src/main/java/io/github/libxposed/api/XposedContext.java
+++ /dev/null
@@ -1,12 +0,0 @@
-package io.github.libxposed.api;
-
-import android.content.Context;
-
-/**
- * Independent {@link Context} for each Xposed module loaded into the target process.
- * This class should be extended by the Xposed framework as the implementation of Xposed interfaces.
- * Modules should not use this class directly.
- */
-public abstract class XposedContext extends Context implements XposedInterface {
-
-}
diff --git a/api/src/main/java/io/github/libxposed/api/XposedContextWrapper.java b/api/src/main/java/io/github/libxposed/api/XposedContextWrapper.java
deleted file mode 100644
index d4cb5fc..0000000
--- a/api/src/main/java/io/github/libxposed/api/XposedContextWrapper.java
+++ /dev/null
@@ -1,209 +0,0 @@
-package io.github.libxposed.api;
-
-import android.annotation.SuppressLint;
-import android.content.Context;
-import android.content.ContextWrapper;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-import java.io.IOException;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.nio.ByteBuffer;
-
-import io.github.libxposed.api.utils.DexParser;
-
-/**
- * Wrap of {@link XposedContext} used by the modules for the purpose of shielding framework implementation details.
- */
-@SuppressWarnings({"unused"})
-@SuppressLint("DiscouragedApi")
-public class XposedContextWrapper extends ContextWrapper implements XposedInterface {
-
- XposedContextWrapper(@NonNull XposedContext base) {
- super(base);
- }
-
- XposedContextWrapper(@NonNull XposedContextWrapper base) {
- super(base);
- }
-
- /**
- * Gets the Xposed API version of current implementation.
- *
- * @return API version
- */
- public final int getAPIVersion() {
- return API;
- }
-
- /**
- * Gets the implementation {@link XposedContext}. Should not be used by modules.
- */
- @NonNull
- @Override
- public final XposedContext getBaseContext() {
- return (XposedContext) super.getBaseContext();
- }
-
- /**
- * {@inheritDoc}
- */
- @NonNull
- @Override
- public final String getFrameworkName() {
- return getBaseContext().getFrameworkName();
- }
-
- /**
- * {@inheritDoc}
- */
- @NonNull
- @Override
- public final String getFrameworkVersion() {
- return getBaseContext().getFrameworkVersion();
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public final long getFrameworkVersionCode() {
- return getBaseContext().getFrameworkVersionCode();
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public final int getFrameworkPrivilege() {
- return getBaseContext().getFrameworkPrivilege();
- }
-
- /**
- * {@inheritDoc}
- */
- @NonNull
- @Override
- public final MethodUnhooker hook(@NonNull Method origin, @NonNull Class extends Hooker> hooker) {
- return getBaseContext().hook(origin, hooker);
- }
-
- /**
- * {@inheritDoc}
- */
- @NonNull
- @Override
- public final MethodUnhooker hook(@NonNull Method origin, int priority, @NonNull Class extends Hooker> hooker) {
- return getBaseContext().hook(origin, priority, hooker);
- }
-
- /**
- * {@inheritDoc}
- */
- @NonNull
- @Override
- public final MethodUnhooker> hook(@NonNull Constructor origin, @NonNull Class extends Hooker> hooker) {
- return getBaseContext().hook(origin, hooker);
- }
-
- /**
- * {@inheritDoc}
- */
- @NonNull
- @Override
- public final MethodUnhooker> hook(@NonNull Constructor origin, int priority, @NonNull Class extends Hooker> hooker) {
- return getBaseContext().hook(origin, priority, hooker);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public final boolean deoptimize(@NonNull Method method) {
- return getBaseContext().deoptimize(method);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public final boolean deoptimize(@NonNull Constructor constructor) {
- return getBaseContext().deoptimize(constructor);
- }
-
- /**
- * {@inheritDoc}
- */
- @Nullable
- @Override
- public final Object invokeOrigin(@NonNull Method method, @Nullable Object thisObject, Object... args) throws InvocationTargetException, IllegalArgumentException, IllegalAccessException {
- return getBaseContext().invokeOrigin(method, thisObject, args);
- }
-
- /**
- * {@inheritDoc}
- */
- @Nullable
- @Override
- public final Object invokeSpecial(@NonNull Method method, @NonNull Object thisObject, Object... args) throws InvocationTargetException, IllegalArgumentException, IllegalAccessException {
- return getBaseContext().invokeSpecial(method, thisObject, args);
- }
-
- /**
- * {@inheritDoc}
- */
- @NonNull
- @Override
- public final T newInstanceOrigin(@NonNull Constructor constructor, Object... args) throws InvocationTargetException, IllegalArgumentException, IllegalAccessException, InstantiationException {
- return getBaseContext().newInstanceOrigin(constructor, args);
- }
-
- /**
- * {@inheritDoc}
- */
- @NonNull
- @Override
- public final U newInstanceSpecial(@NonNull Constructor constructor, @NonNull Class subClass, Object... args) throws InvocationTargetException, IllegalArgumentException, IllegalAccessException, InstantiationException {
- return getBaseContext().newInstanceSpecial(constructor, subClass, args);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public final void log(@NonNull String message) {
- getBaseContext().log(message);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public final void log(@NonNull String message, @NonNull Throwable throwable) {
- getBaseContext().log(message, throwable);
- }
-
- /**
- * {@inheritDoc}
- */
- @Nullable
- @Override
- public final DexParser parseDex(@NonNull ByteBuffer dexData, boolean includeAnnotations) throws IOException {
- return getBaseContext().parseDex(dexData, includeAnnotations);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- protected final void attachBaseContext(Context base) {
- if (base instanceof XposedContext || base instanceof XposedContextWrapper) {
- super.attachBaseContext(base);
- } else {
- throw new IllegalArgumentException();
- }
- }
-}
diff --git a/api/src/main/java/io/github/libxposed/api/XposedInterface.java b/api/src/main/java/io/github/libxposed/api/XposedInterface.java
index a8fbf55..87939e8 100644
--- a/api/src/main/java/io/github/libxposed/api/XposedInterface.java
+++ b/api/src/main/java/io/github/libxposed/api/XposedInterface.java
@@ -47,7 +47,7 @@ public interface XposedInterface {
int FRAMEWORK_PRIVILEGE_APP = 2;
/**
* Indicates that the framework is embedded in the hooked app,
- * which means {@link #getSharedPreferences} will be null and remote file is unsupported.
+ * which means {@link #getRemotePreferences} will be null and remote file is unsupported.
*/
int FRAMEWORK_PRIVILEGE_EMBEDDED = 3;
@@ -443,42 +443,49 @@ public interface XposedInterface {
@Nullable
DexParser parseDex(@NonNull ByteBuffer dexData, boolean includeAnnotations) throws IOException;
-
- // Methods the same with Context
-
/**
- * Gets remote preferences stored in Xposed framework. Note that those are read-only in hooked apps.
+ * Gets the application info of the module.
*
- * @see Context#getSharedPreferences(String, int)
+ * @see Context#getApplicationInfo()
*/
- SharedPreferences getSharedPreferences(String name, int mode);
-
- /**
- * Open a remote file stored in Xposed framework.
- *
- * @see Context#openFileInput(String)
- */
- FileInputStream openFileInput(String name) throws FileNotFoundException;
-
- /**
- * List all remote files stored in Xposed framework. Note that you can only access files created by
- * your own module app with XposedService.
- *
- * @see Context#fileList()
- */
- String[] fileList();
+ @NonNull
+ ApplicationInfo getApplicationInfo();
/**
* Gets resources of the module.
*
* @see Context#getResources()
*/
+ @NonNull
Resources getResources();
/**
- * Gets the application info of the module.
+ * Gets remote preferences stored in Xposed framework. Note that those are read-only in hooked apps.
*
- * @see Context#getApplicationInfo()
+ * @param group Group name
+ * @return The preferences, null if the group does not exists
+ * @throws UnsupportedOperationException If the framework is embedded
*/
- ApplicationInfo getApplicationInfo();
+ @Nullable
+ SharedPreferences getRemotePreferences(@NonNull String group);
+
+ /**
+ * Open an InputStream to read a file from the module's shared data directory.
+ *
+ * @param name File name, must not contain path separators and . or ..
+ * @return The InputStream
+ * @throws FileNotFoundException If the file does not exist or the path is forbidden
+ * @throws UnsupportedOperationException If the framework is embedded
+ */
+ @NonNull
+ FileInputStream openRemoteFileInput(@NonNull String name) throws FileNotFoundException;
+
+ /**
+ * List all files in the module's shared data directory.
+ *
+ * @return The file list
+ * @throws UnsupportedOperationException If the framework is embedded
+ */
+ @NonNull
+ String[] listRemoteFiles();
}
diff --git a/api/src/main/java/io/github/libxposed/api/XposedInterfaceWrapper.java b/api/src/main/java/io/github/libxposed/api/XposedInterfaceWrapper.java
new file mode 100644
index 0000000..c435f4e
--- /dev/null
+++ b/api/src/main/java/io/github/libxposed/api/XposedInterfaceWrapper.java
@@ -0,0 +1,155 @@
+package io.github.libxposed.api;
+
+import android.content.SharedPreferences;
+import android.content.pm.ApplicationInfo;
+import android.content.res.Resources;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.nio.ByteBuffer;
+
+import io.github.libxposed.api.utils.DexParser;
+
+/**
+ * Wrap of {@link XposedInterface} used by the modules for the purpose of shielding framework implementation details.
+ */
+public class XposedInterfaceWrapper implements XposedInterface {
+
+ private final XposedInterface mBase;
+
+ XposedInterfaceWrapper(@NonNull XposedInterface base) {
+ mBase = base;
+ }
+
+ @NonNull
+ @Override
+ public final String getFrameworkName() {
+ return mBase.getFrameworkName();
+ }
+
+ @NonNull
+ @Override
+ public final String getFrameworkVersion() {
+ return mBase.getFrameworkVersion();
+ }
+
+ @Override
+ public final long getFrameworkVersionCode() {
+ return mBase.getFrameworkVersionCode();
+ }
+
+ @Override
+ public final int getFrameworkPrivilege() {
+ return mBase.getFrameworkPrivilege();
+ }
+
+ @NonNull
+ @Override
+ public final MethodUnhooker hook(@NonNull Method origin, @NonNull Class extends Hooker> hooker) {
+ return mBase.hook(origin, hooker);
+ }
+
+ @NonNull
+ @Override
+ public final MethodUnhooker hook(@NonNull Method origin, int priority, @NonNull Class extends Hooker> hooker) {
+ return mBase.hook(origin, priority, hooker);
+ }
+
+ @NonNull
+ @Override
+ public final MethodUnhooker> hook(@NonNull Constructor origin, @NonNull Class extends Hooker> hooker) {
+ return mBase.hook(origin, hooker);
+ }
+
+ @NonNull
+ @Override
+ public final MethodUnhooker> hook(@NonNull Constructor origin, int priority, @NonNull Class extends Hooker> hooker) {
+ return mBase.hook(origin, priority, hooker);
+ }
+
+ @Override
+ public final boolean deoptimize(@NonNull Method method) {
+ return mBase.deoptimize(method);
+ }
+
+ @Override
+ public final boolean deoptimize(@NonNull Constructor constructor) {
+ return mBase.deoptimize(constructor);
+ }
+
+ @Nullable
+ @Override
+ public final Object invokeOrigin(@NonNull Method method, @Nullable Object thisObject, Object... args) throws InvocationTargetException, IllegalArgumentException, IllegalAccessException {
+ return mBase.invokeOrigin(method, thisObject, args);
+ }
+
+ @Nullable
+ @Override
+ public final Object invokeSpecial(@NonNull Method method, @NonNull Object thisObject, Object... args) throws InvocationTargetException, IllegalArgumentException, IllegalAccessException {
+ return mBase.invokeSpecial(method, thisObject, args);
+ }
+
+ @NonNull
+ @Override
+ public final T newInstanceOrigin(@NonNull Constructor constructor, Object... args) throws InvocationTargetException, IllegalArgumentException, IllegalAccessException, InstantiationException {
+ return mBase.newInstanceOrigin(constructor, args);
+ }
+
+ @NonNull
+ @Override
+ public final U newInstanceSpecial(@NonNull Constructor constructor, @NonNull Class subClass, Object... args) throws InvocationTargetException, IllegalArgumentException, IllegalAccessException, InstantiationException {
+ return mBase.newInstanceSpecial(constructor, subClass, args);
+ }
+
+ @Override
+ public final void log(@NonNull String message) {
+ mBase.log(message);
+ }
+
+ @Override
+ public final void log(@NonNull String message, @NonNull Throwable throwable) {
+ mBase.log(message, throwable);
+ }
+
+ @Nullable
+ @Override
+ public final DexParser parseDex(@NonNull ByteBuffer dexData, boolean includeAnnotations) throws IOException {
+ return mBase.parseDex(dexData, includeAnnotations);
+ }
+
+ @Override
+ public SharedPreferences getRemotePreferences(@NonNull String name) {
+ return mBase.getRemotePreferences(name);
+ }
+
+ @NonNull
+ @Override
+ public ApplicationInfo getApplicationInfo() {
+ return mBase.getApplicationInfo();
+ }
+
+ @NonNull
+ @Override
+ public Resources getResources() {
+ return mBase.getResources();
+ }
+
+ @NonNull
+ @Override
+ public FileInputStream openRemoteFileInput(@NonNull String name) throws FileNotFoundException {
+ return mBase.openRemoteFileInput(name);
+ }
+
+ @NonNull
+ @Override
+ public String[] listRemoteFiles() {
+ return mBase.listRemoteFiles();
+ }
+}
diff --git a/api/src/main/java/io/github/libxposed/api/XposedModule.java b/api/src/main/java/io/github/libxposed/api/XposedModule.java
index 904b462..b2e1a03 100644
--- a/api/src/main/java/io/github/libxposed/api/XposedModule.java
+++ b/api/src/main/java/io/github/libxposed/api/XposedModule.java
@@ -7,15 +7,15 @@ import androidx.annotation.NonNull;
* Entry classes will be instantiated exactly once for each process.
*/
@SuppressWarnings("unused")
-public abstract class XposedModule extends XposedContextWrapper implements XposedModuleInterface {
+public abstract class XposedModule extends XposedInterfaceWrapper implements XposedModuleInterface {
/**
* Instantiates a new Xposed module.
* When the module is loaded into the target process, the constructor will be called.
*
- * @param base The base context provided by the framework, should not be used by the module
+ * @param base The implementation interface provided by the framework, should not be used by the module
* @param param Information about the process in which the module is loaded
*/
- public XposedModule(@NonNull XposedContext base, @NonNull ModuleLoadedParam param) {
+ public XposedModule(@NonNull XposedInterface base, @NonNull ModuleLoadedParam param) {
super(base);
}
}