diff --git a/daemon/src/main/java/org/lsposed/lspd/service/LSPNotificationManager.java b/daemon/src/main/java/org/lsposed/lspd/service/LSPNotificationManager.java index ab913fa1..878837ee 100644 --- a/daemon/src/main/java/org/lsposed/lspd/service/LSPNotificationManager.java +++ b/daemon/src/main/java/org/lsposed/lspd/service/LSPNotificationManager.java @@ -102,7 +102,7 @@ public class LSPNotificationManager { } else { channel = nm.getNotificationChannelForPackage("android", 1000, channelId, false); } - if(channel != null) { + if (channel != null) { Log.d(TAG, "hasNotificationChannelForSystem: " + channel); } return channel != null; @@ -178,6 +178,7 @@ public class LSPNotificationManager { static void cancelStatusNotification() { try { var nm = getNotificationManager(); + createNotificationChannel(nm); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { nm.cancelNotificationWithTag("android", "android", null, STATUS_NOTIFICATION_ID, 0); } else { @@ -224,89 +225,85 @@ public class LSPNotificationManager { int moduleUserId, boolean enabled, boolean systemModule) { + var context = new FakeContext(); + var userName = UserService.getUserName(moduleUserId); + String title = context.getString(enabled ? systemModule ? + R.string.xposed_module_updated_notification_title_system : + R.string.xposed_module_updated_notification_title : + R.string.module_is_not_activated_yet); + String content = context.getString(enabled ? systemModule ? + R.string.xposed_module_updated_notification_content_system : + R.string.xposed_module_updated_notification_content : + (moduleUserId == 0 ? + R.string.module_is_not_activated_yet_main_user_detailed : + R.string.module_is_not_activated_yet_multi_user_detailed), modulePackageName, userName); + + var style = new Notification.BigTextStyle(); + style.bigText(content); + + var notification = new Notification.Builder(context, UPDATED_CHANNEL_ID) + .setContentTitle(title) + .setContentText(content) + .setSmallIcon(getNotificationIcon()) + .setContentIntent(getModuleIntent(modulePackageName, moduleUserId)) + .setVisibility(Notification.VISIBILITY_SECRET) + .setColor(0xFFF48FB1) + .setAutoCancel(true) + .setStyle(style) + .build(); + notification.extras.putString("android.substName", "LSPosed"); try { - var context = new FakeContext(); - var userInfo = UserService.getUserInfo(moduleUserId); - String userName = userInfo != null ? userInfo.name : String.valueOf(moduleUserId); - String title = context.getString(enabled ? systemModule ? - R.string.xposed_module_updated_notification_title_system : - R.string.xposed_module_updated_notification_title : - R.string.module_is_not_activated_yet); - String content = context.getString(enabled ? systemModule ? - R.string.xposed_module_updated_notification_content_system : - R.string.xposed_module_updated_notification_content : - (moduleUserId == 0 ? - R.string.module_is_not_activated_yet_main_user_detailed : - R.string.module_is_not_activated_yet_multi_user_detailed), modulePackageName, userName); - - var style = new Notification.BigTextStyle(); - style.bigText(content); - - var notification = new Notification.Builder(context, UPDATED_CHANNEL_ID) - .setContentTitle(title) - .setContentText(content) - .setSmallIcon(getNotificationIcon()) - .setContentIntent(getModuleIntent(modulePackageName, moduleUserId)) - .setVisibility(Notification.VISIBILITY_SECRET) - .setColor(0xFFF48FB1) - .setAutoCancel(true) - .setStyle(style) - .build(); - notification.extras.putString("android.substName", "LSPosed"); var nm = getNotificationManager(); - createNotificationChannel(nm); nm.enqueueNotificationWithTag("android", opPkg, modulePackageName, pushAndGetNotificationId(UPDATED_CHANNEL_ID, modulePackageName, moduleUserId), notification, 0); - } catch (Throwable e) { + } catch (RemoteException e) { Log.e(TAG, "notify module updated", e); } } static void requestModuleScope(String modulePackageName, int moduleUserId, String scopePackageName, IXposedScopeCallback callback) { + var context = new FakeContext(); + var userName = UserService.getUserName(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"); 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 (Throwable e) { + } catch (RemoteException e) { try { callback.onScopeRequestFailed(scopePackageName, e.getMessage()); } catch (RemoteException ignored) { diff --git a/daemon/src/main/java/org/lsposed/lspd/service/LSPosedService.java b/daemon/src/main/java/org/lsposed/lspd/service/LSPosedService.java index 2d92a125..5468eaaf 100644 --- a/daemon/src/main/java/org/lsposed/lspd/service/LSPosedService.java +++ b/daemon/src/main/java/org/lsposed/lspd/service/LSPosedService.java @@ -115,6 +115,7 @@ public class LSPosedService extends ILSPosedService.Stub { if (uid == AID_NOBODY || uid <= 0) return; int userId = intent.getIntExtra("android.intent.extra.user_handle", USER_NULL); var intentAction = intent.getAction(); + if (intentAction == null) return; var allUsers = intent.getBooleanExtra(EXTRA_REMOVED_FOR_ALL_USERS, false); if (userId == USER_NULL) userId = uid % PER_USER_RANGE; Uri uri = intent.getData(); @@ -132,26 +133,23 @@ public class LSPosedService extends ILSPosedService.Stub { boolean isXposedModule = applicationInfo != null && ((applicationInfo.metaData != null && applicationInfo.metaData.containsKey("xposedminversion")) || isModernModules(applicationInfo)); switch (intentAction) { - case Intent.ACTION_PACKAGE_FULLY_REMOVED: { + case Intent.ACTION_PACKAGE_FULLY_REMOVED -> { // for module, remove module // because we only care about when the apk is gone - if (moduleName != null && allUsers) - if (ConfigManager.getInstance().removeModule(moduleName)) { + if (moduleName != null) { + if (allUsers && ConfigManager.getInstance().removeModule(moduleName)) { isXposedModule = true; broadcastAndShowNotification(moduleName, userId, intent, true); } - if (moduleName != null) { LSPNotificationManager.cancelNotification(UPDATED_CHANNEL_ID, moduleName, userId); } - break; } - case Intent.ACTION_PACKAGE_REMOVED: + case Intent.ACTION_PACKAGE_REMOVED -> { if (moduleName != null) { LSPNotificationManager.cancelNotification(UPDATED_CHANNEL_ID, moduleName, userId); } - break; - case Intent.ACTION_PACKAGE_ADDED: - case Intent.ACTION_PACKAGE_CHANGED: { + } + case Intent.ACTION_PACKAGE_ADDED, Intent.ACTION_PACKAGE_CHANGED -> { // make sure that the change is for the complete package, not only a // component String[] components = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST); @@ -165,24 +163,22 @@ public class LSPosedService extends ILSPosedService.Stub { // If cache not updated, assume it's not xposed module isXposedModule = ConfigManager.getInstance().updateModuleApkPath(moduleName, ConfigManager.getInstance().getModuleApkPath(applicationInfo), false); } else if (ConfigManager.getInstance().isUidHooked(uid)) { - // it will automatically remove obsolete app from database + // it will auto update obsolete scope from database ConfigManager.getInstance().updateAppCache(); } broadcastAndShowNotification(moduleName, userId, intent, isXposedModule); - break; } - case Intent.ACTION_UID_REMOVED: { + case Intent.ACTION_UID_REMOVED -> { // when a package is removed (rather than hide) for a single user // (apk may still be there because of multi-user) broadcastAndShowNotification(moduleName, userId, intent, isXposedModule); if (isXposedModule) { - // it will automatically remove obsolete scope from database + // it will auto remove obsolete app and scope from database ConfigManager.getInstance().updateCache(); } else if (ConfigManager.getInstance().isUidHooked(uid)) { - // it will automatically remove obsolete app from database + // it will auto remove obsolete scope from database ConfigManager.getInstance().updateAppCache(); } - break; } } boolean removed = Intent.ACTION_PACKAGE_FULLY_REMOVED.equals(intentAction) || Intent.ACTION_UID_REMOVED.equals(intentAction); @@ -230,6 +226,8 @@ public class LSPosedService extends ILSPosedService.Stub { var configManager = ConfigManager.getInstance(); if (configManager.enableStatusNotification()) { LSPNotificationManager.notifyStatusNotification(); + } else { + LSPNotificationManager.cancelStatusNotification(); } } @@ -238,6 +236,8 @@ public class LSPosedService extends ILSPosedService.Stub { var configManager = ConfigManager.getInstance(); if (configManager.enableStatusNotification()) { LSPNotificationManager.notifyStatusNotification(); + } else { + LSPNotificationManager.cancelStatusNotification(); } } @@ -255,7 +255,10 @@ public class LSPosedService extends ILSPosedService.Stub { var extras = intent.getExtras(); if (extras == null || data == null) return; var callback = extras.getBinder("callback"); - var s = data.getEncodedAuthority().split(":", 2); + if (callback == null || !callback.isBinderAlive()) return; + var authority = data.getEncodedAuthority(); + if (authority == null) return; + var s = authority.split(":", 2); if (s.length != 2) return; var packageName = s[0]; int userId; @@ -272,37 +275,29 @@ public class LSPosedService extends ILSPosedService.Stub { var iCallback = IXposedScopeCallback.Stub.asInterface(callback); try { - ApplicationInfo applicationInfo = null; - try { - applicationInfo = PackageService.getApplicationInfo(scopePackageName, 0, userId); - } catch (Throwable ignored) { - } + var applicationInfo = PackageService.getApplicationInfo(scopePackageName, 0, userId); if (applicationInfo == null) { iCallback.onScopeRequestFailed(scopePackageName, "Package not found"); return; } switch (action) { - case "approve": + case "approve" -> { ConfigManager.getInstance().setModuleScope(packageName, scopePackageName, userId); iCallback.onScopeRequestApproved(scopePackageName); - break; - case "deny": - iCallback.onScopeRequestDenied(scopePackageName); - break; - case "delete": - iCallback.onScopeRequestTimeout(scopePackageName); - break; - case "block": + } + case "deny" -> iCallback.onScopeRequestDenied(scopePackageName); + case "delete" -> iCallback.onScopeRequestTimeout(scopePackageName); + case "block" -> { ConfigManager.getInstance().blockScopeRequest(packageName); iCallback.onScopeRequestDenied(scopePackageName); - break; + } } Log.i(TAG, action + " scope " + scopePackageName + " for " + packageName + " in user " + userId); - } catch (Throwable e) { + } catch (RemoteException e) { try { iCallback.onScopeRequestFailed(scopePackageName, e.getMessage()); - } catch (Throwable ignored) { + } catch (RemoteException ignored) { // callback died } } @@ -337,16 +332,9 @@ public class LSPosedService extends ILSPosedService.Stub { } } - private void registerReceiver(List filters, String requiredPermission, int userId, Consumer task) { - registerReceiver(filters, requiredPermission, userId, task, Context.RECEIVER_NOT_EXPORTED); - } - private void registerReceiver(List filters, int userId, Consumer task) { - registerReceiver(filters, null, userId, task, Context.RECEIVER_NOT_EXPORTED); - } - - private void registerReceiver(List filters, int userId, Consumer task, int flag) { - registerReceiver(filters, null, userId, task, flag); + //noinspection InlinedApi + registerReceiver(filters, "android.permission.BRICK", userId, task, Context.RECEIVER_NOT_EXPORTED); } private void registerPackageReceiver() { @@ -380,7 +368,9 @@ public class LSPosedService extends ILSPosedService.Stub { intentFilter.addDataAuthority("5776733", null); intentFilter.addDataScheme("android_secret_code"); - registerReceiver(List.of(intentFilter), 0, this::dispatchSecretCodeReceive, Context.RECEIVER_EXPORTED); + //noinspection InlinedApi + registerReceiver(List.of(intentFilter), "android.permission.CONTROL_INCALL_EXPERIENCE", + 0, this::dispatchSecretCodeReceive, Context.RECEIVER_EXPORTED); Log.d(TAG, "registered secret code receiver"); } @@ -405,7 +395,7 @@ public class LSPosedService extends ILSPosedService.Stub { var moduleFilter = new IntentFilter(intentFilter); moduleFilter.addDataScheme("module"); - registerReceiver(List.of(intentFilter, moduleFilter), "android.permission.BRICK", 0, this::dispatchOpenManager); + registerReceiver(List.of(intentFilter, moduleFilter), 0, this::dispatchOpenManager); Log.d(TAG, "registered open manager receiver"); } @@ -413,7 +403,7 @@ public class LSPosedService extends ILSPosedService.Stub { var intentFilter = new IntentFilter(LSPNotificationManager.moduleScope); intentFilter.addDataScheme("module"); - registerReceiver(List.of(intentFilter), "android.permission.BRICK", 0, this::dispatchModuleScope); + registerReceiver(List.of(intentFilter), 0, this::dispatchModuleScope); Log.d(TAG, "registered module scope receiver"); } diff --git a/daemon/src/main/java/org/lsposed/lspd/service/UserService.java b/daemon/src/main/java/org/lsposed/lspd/service/UserService.java index ee98969e..ce9c40aa 100644 --- a/daemon/src/main/java/org/lsposed/lspd/service/UserService.java +++ b/daemon/src/main/java/org/lsposed/lspd/service/UserService.java @@ -102,6 +102,15 @@ public class UserService { return um.getUserInfo(userId); } + public static String getUserName(int userId) { + try { + var userInfo = getUserInfo(userId); + if (userInfo != null) return userInfo.name; + } catch (RemoteException ignored) { + } + return String.valueOf(userId); + } + public static int getProfileParent(int userId) throws RemoteException { IUserManager um = getUserManager(); if (um == null) return -1;