Implement scope interfaces
This commit is contained in:
parent
9abf3f2b16
commit
89d255d18a
|
|
@ -45,7 +45,6 @@ import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.lang.reflect.Constructor;
|
import java.lang.reflect.Constructor;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
|
|
@ -63,7 +62,6 @@ import io.github.libxposed.XposedUtils;
|
||||||
public class LSPosedContext extends XposedContext {
|
public class LSPosedContext extends XposedContext {
|
||||||
|
|
||||||
private static final String TAG = "LSPosedContext";
|
private static final String TAG = "LSPosedContext";
|
||||||
private static final int PER_USER_RANGE = 100000;
|
|
||||||
public static boolean isSystemServer;
|
public static boolean isSystemServer;
|
||||||
public static String appDir;
|
public static String appDir;
|
||||||
public static String processName;
|
public static String processName;
|
||||||
|
|
|
||||||
|
|
@ -458,24 +458,22 @@ public class ConfigManager {
|
||||||
config.compute(group, (g, prefs) -> {
|
config.compute(group, (g, prefs) -> {
|
||||||
HashMap<String, Object> newPrefs = prefs == null ? new HashMap<>() : new HashMap<>(prefs);
|
HashMap<String, Object> newPrefs = prefs == null ? new HashMap<>() : new HashMap<>(prefs);
|
||||||
executeInTransaction(() -> {
|
executeInTransaction(() -> {
|
||||||
var contents = new ContentValues();
|
|
||||||
for (var entry : values.entrySet()) {
|
for (var entry : values.entrySet()) {
|
||||||
var key = entry.getKey();
|
var key = entry.getKey();
|
||||||
var value = entry.getValue();
|
var value = entry.getValue();
|
||||||
if (value instanceof Serializable) {
|
if (value instanceof Serializable) {
|
||||||
newPrefs.put(key, value);
|
newPrefs.put(key, value);
|
||||||
|
var contents = new ContentValues();
|
||||||
contents.put("`group`", group);
|
contents.put("`group`", group);
|
||||||
contents.put("`key`", key);
|
contents.put("`key`", key);
|
||||||
contents.put("data", SerializationUtils.serialize((Serializable) value));
|
contents.put("data", SerializationUtils.serialize((Serializable) value));
|
||||||
contents.put("module_pkg_name", moduleName);
|
contents.put("module_pkg_name", moduleName);
|
||||||
contents.put("user_id", String.valueOf(userId));
|
contents.put("user_id", String.valueOf(userId));
|
||||||
|
db.insertWithOnConflict("configs", null, contents, SQLiteDatabase.CONFLICT_REPLACE);
|
||||||
} else {
|
} else {
|
||||||
newPrefs.remove(key);
|
newPrefs.remove(key);
|
||||||
db.delete("configs", "module_pkg_name=? and user_id=? and `group`=? and `key`=?", new String[]{moduleName, String.valueOf(userId), group, key});
|
db.delete("configs", "module_pkg_name=? and user_id=? and `group`=? and `key`=?", new String[]{moduleName, String.valueOf(userId), group, key});
|
||||||
}
|
}
|
||||||
if (contents.size() > 0) {
|
|
||||||
db.insertWithOnConflict("configs", null, contents, SQLiteDatabase.CONFLICT_REPLACE);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
var bundle = new Bundle();
|
var bundle = new Bundle();
|
||||||
bundle.putSerializable("config", (Serializable) config);
|
bundle.putSerializable("config", (Serializable) config);
|
||||||
|
|
@ -841,6 +839,37 @@ public class ConfigManager {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean setModuleScope(String packageName, String scopePackageName, int userId) {
|
||||||
|
if (scopePackageName == null) return false;
|
||||||
|
int mid = getModuleId(packageName);
|
||||||
|
if (mid == -1) return false;
|
||||||
|
if (scopePackageName.equals("android") && userId != 0) return false;
|
||||||
|
executeInTransaction(() -> {
|
||||||
|
ContentValues values = new ContentValues();
|
||||||
|
values.put("mid", mid);
|
||||||
|
values.put("app_pkg_name", scopePackageName);
|
||||||
|
values.put("user_id", userId);
|
||||||
|
db.insertWithOnConflict("scope", null, values, SQLiteDatabase.CONFLICT_IGNORE);
|
||||||
|
});
|
||||||
|
// Called by xposed service, should be async
|
||||||
|
updateCaches(false);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean removeModuleScope(String packageName, String scopePackageName, int userId) {
|
||||||
|
if (scopePackageName == null) return false;
|
||||||
|
int mid = getModuleId(packageName);
|
||||||
|
if (mid == -1) return false;
|
||||||
|
if (scopePackageName.equals("android") && userId != 0) return false;
|
||||||
|
executeInTransaction(() -> {
|
||||||
|
db.delete("scope", "mid = ? AND app_pkg_name = ? AND user_id = ?", new String[]{String.valueOf(mid), scopePackageName, String.valueOf(userId)});
|
||||||
|
});
|
||||||
|
// Called by xposed service, should be async
|
||||||
|
updateCaches(false);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public String[] enabledModules() {
|
public String[] enabledModules() {
|
||||||
try (Cursor cursor = db.query("modules", new String[]{"module_pkg_name"}, "enabled = 1", null, null, null, null)) {
|
try (Cursor cursor = db.query("modules", new String[]{"module_pkg_name"}, "enabled = 1", null, null, null, null)) {
|
||||||
if (cursor == null) {
|
if (cursor == null) {
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,7 @@ import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
import io.github.libxposed.service.IXposedScopeCallback;
|
||||||
import io.github.libxposed.service.IXposedService;
|
import io.github.libxposed.service.IXposedService;
|
||||||
|
|
||||||
public class LSPModuleService extends IXposedService.Stub {
|
public class LSPModuleService extends IXposedService.Stub {
|
||||||
|
|
@ -147,9 +148,23 @@ public class LSPModuleService extends IXposedService.Stub {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void requestScope(String packageName) throws RemoteException {
|
public void requestScope(String packageName, IXposedScopeCallback callback) throws RemoteException {
|
||||||
ensureModule();
|
var userId = ensureModule();
|
||||||
// TODO
|
LSPNotificationManager.requestModuleScope(loadedModule.packageName, userId, packageName, callback);
|
||||||
|
callback.onScopeRequestPrompted(packageName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String removeScope(String packageName) throws RemoteException {
|
||||||
|
var userId = ensureModule();
|
||||||
|
try {
|
||||||
|
if (!ConfigManager.getInstance().removeModuleScope(loadedModule.packageName, packageName, userId)) {
|
||||||
|
return "Invalid request";
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
} catch (Throwable e) {
|
||||||
|
return e.getMessage();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ import android.graphics.drawable.Icon;
|
||||||
import android.graphics.drawable.LayerDrawable;
|
import android.graphics.drawable.LayerDrawable;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
|
import android.os.Bundle;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
@ -27,20 +28,25 @@ import org.lsposed.daemon.R;
|
||||||
import org.lsposed.lspd.util.FakeContext;
|
import org.lsposed.lspd.util.FakeContext;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.Map;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
import io.github.libxposed.service.IXposedScopeCallback;
|
||||||
|
|
||||||
public class LSPNotificationManager {
|
public class LSPNotificationManager {
|
||||||
private static final String UPDATED_CHANNEL_ID = "lsposed_module_updated";
|
private static final String UPDATED_CHANNEL_ID = "lsposed_module_updated";
|
||||||
|
private static final String SCOPE_CHANNEL_ID = "lsposed_module_scope";
|
||||||
private static final String STATUS_CHANNEL_ID = "lsposed_status";
|
private static final String STATUS_CHANNEL_ID = "lsposed_status";
|
||||||
private static final int STATUS_NOTIFICATION_ID = 2000;
|
private static final int STATUS_NOTIFICATION_ID = 2000;
|
||||||
private static final String opPkg = Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q ?
|
private static final String opPkg = Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q ?
|
||||||
"android" : "com.android.settings";
|
"android" : "com.android.settings";
|
||||||
|
|
||||||
private static final HashMap<String, Integer> notificationIds = new HashMap<>();
|
private static final Map<String, Integer> notificationIds = new ConcurrentHashMap<>();
|
||||||
private static int previousNotificationId = STATUS_NOTIFICATION_ID;
|
private static int previousNotificationId = STATUS_NOTIFICATION_ID;
|
||||||
|
|
||||||
static final String openManagerAction = UUID.randomUUID().toString();
|
static final String openManagerAction = UUID.randomUUID().toString();
|
||||||
|
static final String moduleScope = UUID.randomUUID().toString();
|
||||||
|
|
||||||
private static INotificationManager notificationManager = null;
|
private static INotificationManager notificationManager = null;
|
||||||
private static IBinder binder = null;
|
private static IBinder binder = null;
|
||||||
|
|
@ -121,6 +127,16 @@ public class LSPNotificationManager {
|
||||||
list.add(status);
|
list.add(status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var scope = new NotificationChannel(SCOPE_CHANNEL_ID,
|
||||||
|
context.getString(R.string.scope_channel_name),
|
||||||
|
NotificationManager.IMPORTANCE_HIGH);
|
||||||
|
scope.setShowBadge(false);
|
||||||
|
if (hasNotificationChannelForSystem(nm, SCOPE_CHANNEL_ID)) {
|
||||||
|
nm.updateNotificationChannelForPackage("android", 1000, scope);
|
||||||
|
} else {
|
||||||
|
list.add(scope);
|
||||||
|
}
|
||||||
|
|
||||||
nm.createNotificationChannelsForPackage("android", 1000, new ParceledListSlice<>(list));
|
nm.createNotificationChannelsForPackage("android", 1000, new ParceledListSlice<>(list));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -169,12 +185,22 @@ public class LSPNotificationManager {
|
||||||
return PendingIntent.getBroadcast(new FakeContext(), 3, intent, flags);
|
return PendingIntent.getBroadcast(new FakeContext(), 3, intent, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String getNotificationIdKey(String modulePackageName, int moduleUserId) {
|
private static PendingIntent getModuleScopeIntent(String modulePackageName, int moduleUserId, String scopePackageName, String action, IXposedScopeCallback callback) {
|
||||||
return modulePackageName + ":" + moduleUserId;
|
var intent = new Intent(moduleScope);
|
||||||
|
intent.setData(new Uri.Builder().scheme("module").encodedAuthority(modulePackageName + ":" + moduleUserId).encodedPath(scopePackageName).appendQueryParameter("action", action).build());
|
||||||
|
var extras = new Bundle();
|
||||||
|
extras.putBinder("callback", callback.asBinder());
|
||||||
|
intent.putExtras(extras);
|
||||||
|
int flags = PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE;
|
||||||
|
return PendingIntent.getBroadcast(new FakeContext(), 4, intent, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int pushAndGetNotificationId(String modulePackageName, int moduleUserId) {
|
private static String getNotificationIdKey(String channel, String modulePackageName, int moduleUserId) {
|
||||||
var idKey = getNotificationIdKey(modulePackageName, moduleUserId);
|
return channel + "/" + modulePackageName + ":" + moduleUserId;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int pushAndGetNotificationId(String channel, String modulePackageName, int moduleUserId) {
|
||||||
|
var idKey = getNotificationIdKey(channel, modulePackageName, moduleUserId);
|
||||||
// previousNotificationId start with 2001
|
// previousNotificationId start with 2001
|
||||||
// https://android.googlesource.com/platform/frameworks/base/+/master/proto/src/system_messages.proto
|
// https://android.googlesource.com/platform/frameworks/base/+/master/proto/src/system_messages.proto
|
||||||
// https://android.googlesource.com/platform/system/core/+/master/libcutils/include/private/android_filesystem_config.h
|
// https://android.googlesource.com/platform/system/core/+/master/libcutils/include/private/android_filesystem_config.h
|
||||||
|
|
@ -218,7 +244,7 @@ public class LSPNotificationManager {
|
||||||
var nm = getNotificationManager();
|
var nm = getNotificationManager();
|
||||||
createNotificationChannel(nm);
|
createNotificationChannel(nm);
|
||||||
nm.enqueueNotificationWithTag("android", opPkg, modulePackageName,
|
nm.enqueueNotificationWithTag("android", opPkg, modulePackageName,
|
||||||
pushAndGetNotificationId(modulePackageName, moduleUserId),
|
pushAndGetNotificationId(UPDATED_CHANNEL_ID, modulePackageName, moduleUserId),
|
||||||
notification, 0);
|
notification, 0);
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
Log.e(TAG, "notify module updated", e);
|
Log.e(TAG, "notify module updated", e);
|
||||||
|
|
@ -227,7 +253,7 @@ public class LSPNotificationManager {
|
||||||
|
|
||||||
static void cancelUpdatedNotification(String modulePackageName, int moduleUserId) {
|
static void cancelUpdatedNotification(String modulePackageName, int moduleUserId) {
|
||||||
try {
|
try {
|
||||||
var idKey = getNotificationIdKey(modulePackageName, moduleUserId);
|
var idKey = getNotificationIdKey(UPDATED_CHANNEL_ID, modulePackageName, moduleUserId);
|
||||||
var idValue = notificationIds.get(idKey);
|
var idValue = notificationIds.get(idKey);
|
||||||
if (idValue == null) return;
|
if (idValue == null) return;
|
||||||
var nm = getNotificationManager();
|
var nm = getNotificationManager();
|
||||||
|
|
@ -241,4 +267,52 @@ public class LSPNotificationManager {
|
||||||
Log.e(TAG, "cancel notification", e);
|
Log.e(TAG, "cancel notification", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void requestModuleScope(String modulePackageName, int moduleUserId, String scopePackageName, IXposedScopeCallback callback) {
|
||||||
|
try {
|
||||||
|
var context = new FakeContext();
|
||||||
|
var userInfo = UserService.getUserInfo(moduleUserId);
|
||||||
|
String userName = userInfo != null ? userInfo.name : String.valueOf(moduleUserId);
|
||||||
|
String title = context.getString(R.string.xposed_module_request_scope_title);
|
||||||
|
String content = context.getString(R.string.xposed_module_request_scope_content, modulePackageName, userName, scopePackageName);
|
||||||
|
|
||||||
|
var style = new Notification.BigTextStyle();
|
||||||
|
style.bigText(content);
|
||||||
|
|
||||||
|
var notification = new Notification.Builder(context, SCOPE_CHANNEL_ID)
|
||||||
|
.setContentTitle(title)
|
||||||
|
.setContentText(content)
|
||||||
|
.setSmallIcon(getNotificationIcon())
|
||||||
|
.setVisibility(Notification.VISIBILITY_SECRET)
|
||||||
|
.setColor(0xFFF48FB1)
|
||||||
|
.setAutoCancel(true)
|
||||||
|
.setTimeoutAfter(1000 * 60 * 60)
|
||||||
|
.setStyle(style)
|
||||||
|
.setDeleteIntent(getModuleScopeIntent(modulePackageName, moduleUserId, scopePackageName, "delete", callback))
|
||||||
|
.setActions(new Notification.Action.Builder(
|
||||||
|
Icon.createWithResource(context, R.drawable.ic_baseline_check_24),
|
||||||
|
context.getString(R.string.scope_approve),
|
||||||
|
getModuleScopeIntent(modulePackageName, moduleUserId, scopePackageName, "approve", callback))
|
||||||
|
.build(),
|
||||||
|
new Notification.Action.Builder(
|
||||||
|
Icon.createWithResource(context, R.drawable.ic_baseline_close_24),
|
||||||
|
context.getString(R.string.scope_deny),
|
||||||
|
getModuleScopeIntent(modulePackageName, moduleUserId, scopePackageName, "deny", callback))
|
||||||
|
.build(),
|
||||||
|
new Notification.Action.Builder(
|
||||||
|
Icon.createWithResource(context, R.drawable.ic_baseline_block_24),
|
||||||
|
context.getString(R.string.nerver_ask_again),
|
||||||
|
getModuleScopeIntent(modulePackageName, moduleUserId, scopePackageName, "block", callback))
|
||||||
|
.build()
|
||||||
|
).build();
|
||||||
|
notification.extras.putString("android.substName", "LSPosed");
|
||||||
|
var nm = getNotificationManager();
|
||||||
|
createNotificationChannel(nm);
|
||||||
|
nm.enqueueNotificationWithTag("android", opPkg, modulePackageName,
|
||||||
|
pushAndGetNotificationId(SCOPE_CHANNEL_ID, modulePackageName, moduleUserId),
|
||||||
|
notification, 0);
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
Log.e(TAG, "request module scope", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ import static org.lsposed.lspd.service.ServiceManager.getExecutorService;
|
||||||
|
|
||||||
import android.app.IApplicationThread;
|
import android.app.IApplicationThread;
|
||||||
import android.app.IUidObserver;
|
import android.app.IUidObserver;
|
||||||
|
import android.content.ContentValues;
|
||||||
import android.content.IIntentReceiver;
|
import android.content.IIntentReceiver;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.IntentFilter;
|
import android.content.IntentFilter;
|
||||||
|
|
@ -48,6 +49,7 @@ import java.util.List;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
import hidden.HiddenApiBridge;
|
import hidden.HiddenApiBridge;
|
||||||
|
import io.github.libxposed.service.IXposedScopeCallback;
|
||||||
|
|
||||||
public class LSPosedService extends ILSPosedService.Stub {
|
public class LSPosedService extends ILSPosedService.Stub {
|
||||||
private static final int AID_NOBODY = 9999;
|
private static final int AID_NOBODY = 9999;
|
||||||
|
|
@ -225,6 +227,50 @@ public class LSPosedService extends ILSPosedService.Stub {
|
||||||
LSPManagerService.openManager(intent.getData());
|
LSPManagerService.openManager(intent.getData());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void dispatchModuleScope(Intent intent) {
|
||||||
|
Log.d(TAG, "dispatchModuleScope: " + intent);
|
||||||
|
var data = intent.getData();
|
||||||
|
var extras = intent.getExtras();
|
||||||
|
if (extras == null || data == null) return;
|
||||||
|
var callback = extras.getBinder("callback");
|
||||||
|
var s = data.getEncodedAuthority().split(":", 2);
|
||||||
|
if (s.length != 2) return;
|
||||||
|
var packageName = s[0];
|
||||||
|
int userId;
|
||||||
|
try {
|
||||||
|
userId = Integer.parseInt(s[1]);
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var scopePackageName = data.getPath();
|
||||||
|
var action = data.getQueryParameter("action");
|
||||||
|
if (scopePackageName == null || action == null) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
switch (action) {
|
||||||
|
case "allow":
|
||||||
|
ConfigManager.getInstance().setModuleScope(packageName, scopePackageName, userId);
|
||||||
|
IXposedScopeCallback.Stub.asInterface(callback).onScopeRequestApproved(scopePackageName);
|
||||||
|
break;
|
||||||
|
case "deny":
|
||||||
|
IXposedScopeCallback.Stub.asInterface(callback).onScopeRequestDenied(scopePackageName);
|
||||||
|
break;
|
||||||
|
case "delete":
|
||||||
|
IXposedScopeCallback.Stub.asInterface(callback).onScopeRequestTimeout(scopePackageName);
|
||||||
|
break;
|
||||||
|
case "block":
|
||||||
|
// TODO
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} catch (Throwable e) {
|
||||||
|
try {
|
||||||
|
IXposedScopeCallback.Stub.asInterface(callback).onScopeRequestFailed(scopePackageName, e.getMessage());
|
||||||
|
} catch (Throwable ignored) {
|
||||||
|
// callback died
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void registerReceiver(List<IntentFilter> filters, String requiredPermission, int userId, Consumer<Intent> task) {
|
private void registerReceiver(List<IntentFilter> filters, String requiredPermission, int userId, Consumer<Intent> task) {
|
||||||
var receiver = new IIntentReceiver.Stub() {
|
var receiver = new IIntentReceiver.Stub() {
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -317,6 +363,15 @@ public class LSPosedService extends ILSPosedService.Stub {
|
||||||
Log.d(TAG, "registered open manager receiver");
|
Log.d(TAG, "registered open manager receiver");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void registerModuleScopeReceiver() {
|
||||||
|
var intentFilter = new IntentFilter(LSPNotificationManager.moduleScope);
|
||||||
|
var moduleFilter = new IntentFilter(intentFilter);
|
||||||
|
moduleFilter.addDataScheme("module");
|
||||||
|
|
||||||
|
registerReceiver(List.of(intentFilter, moduleFilter), "android.permission.BRICK", 0, this::dispatchModuleScope);
|
||||||
|
Log.d(TAG, "registered module scope receiver");
|
||||||
|
}
|
||||||
|
|
||||||
private void registerUidObserver() {
|
private void registerUidObserver() {
|
||||||
try {
|
try {
|
||||||
ActivityManagerService.registerUidObserver(new IUidObserver.Stub() {
|
ActivityManagerService.registerUidObserver(new IUidObserver.Stub() {
|
||||||
|
|
@ -356,6 +411,7 @@ public class LSPosedService extends ILSPosedService.Stub {
|
||||||
registerBootCompleteReceiver();
|
registerBootCompleteReceiver();
|
||||||
registerUserChangeReceiver();
|
registerUserChangeReceiver();
|
||||||
registerOpenManagerReceiver();
|
registerOpenManagerReceiver();
|
||||||
|
registerModuleScopeReceiver();
|
||||||
registerUidObserver();
|
registerUidObserver();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
<vector android:height="24dp" android:tint="#000000"
|
||||||
|
android:viewportHeight="24" android:viewportWidth="24"
|
||||||
|
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="@android:color/white" android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM4,12c0,-4.42 3.58,-8 8,-8 1.85,0 3.55,0.63 4.9,1.69L5.69,16.9C4.63,15.55 4,13.85 4,12zM12,20c-1.85,0 -3.55,-0.63 -4.9,-1.69L18.31,7.1C19.37,8.45 20,10.15 20,12c0,4.42 -3.58,8 -8,8z"/>
|
||||||
|
</vector>
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
<vector android:height="24dp" android:tint="#000000"
|
||||||
|
android:viewportHeight="24" android:viewportWidth="24"
|
||||||
|
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="@android:color/white" android:pathData="M9,16.17L4.83,12l-1.42,1.41L9,19 21,7l-1.41,-1.41z"/>
|
||||||
|
</vector>
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
<vector android:height="24dp" android:tint="#000000"
|
||||||
|
android:viewportHeight="24" android:viewportWidth="24"
|
||||||
|
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="@android:color/white" android:pathData="M19,6.41L17.59,5 12,10.59 6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 12,13.41 17.59,19 19,17.59 13.41,12z"/>
|
||||||
|
</vector>
|
||||||
|
|
@ -11,4 +11,10 @@
|
||||||
<string name="status_channel_name">LSPosed status</string>
|
<string name="status_channel_name">LSPosed status</string>
|
||||||
<string name="lsposed_running_notification_title">LSPosed loaded</string>
|
<string name="lsposed_running_notification_title">LSPosed loaded</string>
|
||||||
<string name="lsposed_running_notification_content">Tap the notification to open manager</string>
|
<string name="lsposed_running_notification_content">Tap the notification to open manager</string>
|
||||||
|
<string name="xposed_module_request_scope_title">Scope Request</string>
|
||||||
|
<string name="xposed_module_request_scope_content">%1$s on user %2$s requests to add %3$s to its scope.</string>
|
||||||
|
<string name="scope_channel_name">Scope request</string>
|
||||||
|
<string name="scope_approve">Approve</string>
|
||||||
|
<string name="scope_deny">Deny</string>
|
||||||
|
<string name="nerver_ask_again">Never Ask Again</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
package io.github.libxposed.service;
|
||||||
|
|
||||||
|
interface IXposedScopeCallback {
|
||||||
|
oneway void onScopeRequestPrompted(String packageName) = 1;
|
||||||
|
oneway void onScopeRequestApproved(String packageName) = 2;
|
||||||
|
oneway void onScopeRequestDenied(String packageName) = 3;
|
||||||
|
oneway void onScopeRequestTimeout(String packageName) = 4;
|
||||||
|
oneway void onScopeRequestFailed(String packageName, String message) = 5;
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
package io.github.libxposed.service;
|
package io.github.libxposed.service;
|
||||||
|
import io.github.libxposed.service.IXposedScopeCallback;
|
||||||
|
|
||||||
interface IXposedService {
|
interface IXposedService {
|
||||||
const int API = 100;
|
const int API = 100;
|
||||||
|
|
@ -13,7 +14,8 @@ interface IXposedService {
|
||||||
|
|
||||||
// scope utilities
|
// scope utilities
|
||||||
List<String> getScope() = 10;
|
List<String> getScope() = 10;
|
||||||
oneway void requestScope(String packageName) = 11;
|
oneway void requestScope(String packageName, IXposedScopeCallback callback) = 11;
|
||||||
|
String removeScope(String packageName) = 12;
|
||||||
|
|
||||||
// remote preference utilities
|
// remote preference utilities
|
||||||
Bundle requestRemotePreferences(String group) = 20;
|
Bundle requestRemotePreferences(String group) = 20;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue