Check notification channels only when necessary (#2635)

This commit is contained in:
南宫雪珊 2023-07-18 14:45:49 +08:00 committed by GitHub
parent 645d7cfadf
commit db8927ac01
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 110 additions and 114 deletions

View File

@ -102,7 +102,7 @@ public class LSPNotificationManager {
} else { } else {
channel = nm.getNotificationChannelForPackage("android", 1000, channelId, false); channel = nm.getNotificationChannelForPackage("android", 1000, channelId, false);
} }
if(channel != null) { if (channel != null) {
Log.d(TAG, "hasNotificationChannelForSystem: " + channel); Log.d(TAG, "hasNotificationChannelForSystem: " + channel);
} }
return channel != null; return channel != null;
@ -178,6 +178,7 @@ public class LSPNotificationManager {
static void cancelStatusNotification() { static void cancelStatusNotification() {
try { try {
var nm = getNotificationManager(); var nm = getNotificationManager();
createNotificationChannel(nm);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
nm.cancelNotificationWithTag("android", "android", null, STATUS_NOTIFICATION_ID, 0); nm.cancelNotificationWithTag("android", "android", null, STATUS_NOTIFICATION_ID, 0);
} else { } else {
@ -224,89 +225,85 @@ public class LSPNotificationManager {
int moduleUserId, int moduleUserId,
boolean enabled, boolean enabled,
boolean systemModule) { 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 { 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(); var nm = getNotificationManager();
createNotificationChannel(nm);
nm.enqueueNotificationWithTag("android", opPkg, modulePackageName, nm.enqueueNotificationWithTag("android", opPkg, modulePackageName,
pushAndGetNotificationId(UPDATED_CHANNEL_ID, modulePackageName, moduleUserId), pushAndGetNotificationId(UPDATED_CHANNEL_ID, modulePackageName, moduleUserId),
notification, 0); notification, 0);
} catch (Throwable e) { } catch (RemoteException e) {
Log.e(TAG, "notify module updated", e); Log.e(TAG, "notify module updated", e);
} }
} }
static void requestModuleScope(String modulePackageName, int moduleUserId, String scopePackageName, IXposedScopeCallback callback) { 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 { 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(); var nm = getNotificationManager();
createNotificationChannel(nm);
nm.enqueueNotificationWithTag("android", opPkg, modulePackageName, nm.enqueueNotificationWithTag("android", opPkg, modulePackageName,
pushAndGetNotificationId(SCOPE_CHANNEL_ID, modulePackageName, moduleUserId), pushAndGetNotificationId(SCOPE_CHANNEL_ID, modulePackageName, moduleUserId),
notification, 0); notification, 0);
} catch (Throwable e) { } catch (RemoteException e) {
try { try {
callback.onScopeRequestFailed(scopePackageName, e.getMessage()); callback.onScopeRequestFailed(scopePackageName, e.getMessage());
} catch (RemoteException ignored) { } catch (RemoteException ignored) {

View File

@ -115,6 +115,7 @@ public class LSPosedService extends ILSPosedService.Stub {
if (uid == AID_NOBODY || uid <= 0) return; if (uid == AID_NOBODY || uid <= 0) return;
int userId = intent.getIntExtra("android.intent.extra.user_handle", USER_NULL); int userId = intent.getIntExtra("android.intent.extra.user_handle", USER_NULL);
var intentAction = intent.getAction(); var intentAction = intent.getAction();
if (intentAction == null) return;
var allUsers = intent.getBooleanExtra(EXTRA_REMOVED_FOR_ALL_USERS, false); var allUsers = intent.getBooleanExtra(EXTRA_REMOVED_FOR_ALL_USERS, false);
if (userId == USER_NULL) userId = uid % PER_USER_RANGE; if (userId == USER_NULL) userId = uid % PER_USER_RANGE;
Uri uri = intent.getData(); 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)); boolean isXposedModule = applicationInfo != null && ((applicationInfo.metaData != null && applicationInfo.metaData.containsKey("xposedminversion")) || isModernModules(applicationInfo));
switch (intentAction) { switch (intentAction) {
case Intent.ACTION_PACKAGE_FULLY_REMOVED: { case Intent.ACTION_PACKAGE_FULLY_REMOVED -> {
// for module, remove module // for module, remove module
// because we only care about when the apk is gone // because we only care about when the apk is gone
if (moduleName != null && allUsers) if (moduleName != null) {
if (ConfigManager.getInstance().removeModule(moduleName)) { if (allUsers && ConfigManager.getInstance().removeModule(moduleName)) {
isXposedModule = true; isXposedModule = true;
broadcastAndShowNotification(moduleName, userId, intent, true); broadcastAndShowNotification(moduleName, userId, intent, true);
} }
if (moduleName != null) {
LSPNotificationManager.cancelNotification(UPDATED_CHANNEL_ID, moduleName, userId); LSPNotificationManager.cancelNotification(UPDATED_CHANNEL_ID, moduleName, userId);
} }
break;
} }
case Intent.ACTION_PACKAGE_REMOVED: case Intent.ACTION_PACKAGE_REMOVED -> {
if (moduleName != null) { if (moduleName != null) {
LSPNotificationManager.cancelNotification(UPDATED_CHANNEL_ID, moduleName, userId); LSPNotificationManager.cancelNotification(UPDATED_CHANNEL_ID, moduleName, userId);
} }
break; }
case Intent.ACTION_PACKAGE_ADDED: case Intent.ACTION_PACKAGE_ADDED, Intent.ACTION_PACKAGE_CHANGED -> {
case Intent.ACTION_PACKAGE_CHANGED: {
// make sure that the change is for the complete package, not only a // make sure that the change is for the complete package, not only a
// component // component
String[] components = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST); 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 // If cache not updated, assume it's not xposed module
isXposedModule = ConfigManager.getInstance().updateModuleApkPath(moduleName, ConfigManager.getInstance().getModuleApkPath(applicationInfo), false); isXposedModule = ConfigManager.getInstance().updateModuleApkPath(moduleName, ConfigManager.getInstance().getModuleApkPath(applicationInfo), false);
} else if (ConfigManager.getInstance().isUidHooked(uid)) { } 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(); ConfigManager.getInstance().updateAppCache();
} }
broadcastAndShowNotification(moduleName, userId, intent, isXposedModule); 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 // when a package is removed (rather than hide) for a single user
// (apk may still be there because of multi-user) // (apk may still be there because of multi-user)
broadcastAndShowNotification(moduleName, userId, intent, isXposedModule); broadcastAndShowNotification(moduleName, userId, intent, isXposedModule);
if (isXposedModule) { if (isXposedModule) {
// it will automatically remove obsolete scope from database // it will auto remove obsolete app and scope from database
ConfigManager.getInstance().updateCache(); ConfigManager.getInstance().updateCache();
} else if (ConfigManager.getInstance().isUidHooked(uid)) { } 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(); ConfigManager.getInstance().updateAppCache();
} }
break;
} }
} }
boolean removed = Intent.ACTION_PACKAGE_FULLY_REMOVED.equals(intentAction) || Intent.ACTION_UID_REMOVED.equals(intentAction); 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(); var configManager = ConfigManager.getInstance();
if (configManager.enableStatusNotification()) { if (configManager.enableStatusNotification()) {
LSPNotificationManager.notifyStatusNotification(); LSPNotificationManager.notifyStatusNotification();
} else {
LSPNotificationManager.cancelStatusNotification();
} }
} }
@ -238,6 +236,8 @@ public class LSPosedService extends ILSPosedService.Stub {
var configManager = ConfigManager.getInstance(); var configManager = ConfigManager.getInstance();
if (configManager.enableStatusNotification()) { if (configManager.enableStatusNotification()) {
LSPNotificationManager.notifyStatusNotification(); LSPNotificationManager.notifyStatusNotification();
} else {
LSPNotificationManager.cancelStatusNotification();
} }
} }
@ -255,7 +255,10 @@ public class LSPosedService extends ILSPosedService.Stub {
var extras = intent.getExtras(); var extras = intent.getExtras();
if (extras == null || data == null) return; if (extras == null || data == null) return;
var callback = extras.getBinder("callback"); 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; if (s.length != 2) return;
var packageName = s[0]; var packageName = s[0];
int userId; int userId;
@ -272,37 +275,29 @@ public class LSPosedService extends ILSPosedService.Stub {
var iCallback = IXposedScopeCallback.Stub.asInterface(callback); var iCallback = IXposedScopeCallback.Stub.asInterface(callback);
try { try {
ApplicationInfo applicationInfo = null; var applicationInfo = PackageService.getApplicationInfo(scopePackageName, 0, userId);
try {
applicationInfo = PackageService.getApplicationInfo(scopePackageName, 0, userId);
} catch (Throwable ignored) {
}
if (applicationInfo == null) { if (applicationInfo == null) {
iCallback.onScopeRequestFailed(scopePackageName, "Package not found"); iCallback.onScopeRequestFailed(scopePackageName, "Package not found");
return; return;
} }
switch (action) { switch (action) {
case "approve": case "approve" -> {
ConfigManager.getInstance().setModuleScope(packageName, scopePackageName, userId); ConfigManager.getInstance().setModuleScope(packageName, scopePackageName, userId);
iCallback.onScopeRequestApproved(scopePackageName); iCallback.onScopeRequestApproved(scopePackageName);
break; }
case "deny": case "deny" -> iCallback.onScopeRequestDenied(scopePackageName);
iCallback.onScopeRequestDenied(scopePackageName); case "delete" -> iCallback.onScopeRequestTimeout(scopePackageName);
break; case "block" -> {
case "delete":
iCallback.onScopeRequestTimeout(scopePackageName);
break;
case "block":
ConfigManager.getInstance().blockScopeRequest(packageName); ConfigManager.getInstance().blockScopeRequest(packageName);
iCallback.onScopeRequestDenied(scopePackageName); iCallback.onScopeRequestDenied(scopePackageName);
break; }
} }
Log.i(TAG, action + " scope " + scopePackageName + " for " + packageName + " in user " + userId); Log.i(TAG, action + " scope " + scopePackageName + " for " + packageName + " in user " + userId);
} catch (Throwable e) { } catch (RemoteException e) {
try { try {
iCallback.onScopeRequestFailed(scopePackageName, e.getMessage()); iCallback.onScopeRequestFailed(scopePackageName, e.getMessage());
} catch (Throwable ignored) { } catch (RemoteException ignored) {
// callback died // callback died
} }
} }
@ -337,16 +332,9 @@ public class LSPosedService extends ILSPosedService.Stub {
} }
} }
private void registerReceiver(List<IntentFilter> filters, String requiredPermission, int userId, Consumer<Intent> task) {
registerReceiver(filters, requiredPermission, userId, task, Context.RECEIVER_NOT_EXPORTED);
}
private void registerReceiver(List<IntentFilter> filters, int userId, Consumer<Intent> task) { private void registerReceiver(List<IntentFilter> filters, int userId, Consumer<Intent> task) {
registerReceiver(filters, null, userId, task, Context.RECEIVER_NOT_EXPORTED); //noinspection InlinedApi
} registerReceiver(filters, "android.permission.BRICK", userId, task, Context.RECEIVER_NOT_EXPORTED);
private void registerReceiver(List<IntentFilter> filters, int userId, Consumer<Intent> task, int flag) {
registerReceiver(filters, null, userId, task, flag);
} }
private void registerPackageReceiver() { private void registerPackageReceiver() {
@ -380,7 +368,9 @@ public class LSPosedService extends ILSPosedService.Stub {
intentFilter.addDataAuthority("5776733", null); intentFilter.addDataAuthority("5776733", null);
intentFilter.addDataScheme("android_secret_code"); 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"); Log.d(TAG, "registered secret code receiver");
} }
@ -405,7 +395,7 @@ public class LSPosedService extends ILSPosedService.Stub {
var moduleFilter = new IntentFilter(intentFilter); var moduleFilter = new IntentFilter(intentFilter);
moduleFilter.addDataScheme("module"); 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"); Log.d(TAG, "registered open manager receiver");
} }
@ -413,7 +403,7 @@ public class LSPosedService extends ILSPosedService.Stub {
var intentFilter = new IntentFilter(LSPNotificationManager.moduleScope); var intentFilter = new IntentFilter(LSPNotificationManager.moduleScope);
intentFilter.addDataScheme("module"); 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"); Log.d(TAG, "registered module scope receiver");
} }

View File

@ -102,6 +102,15 @@ public class UserService {
return um.getUserInfo(userId); 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 { public static int getProfileParent(int userId) throws RemoteException {
IUserManager um = getUserManager(); IUserManager um = getUserManager();
if (um == null) return -1; if (um == null) return -1;