6.7.0 - Alpha18 - 读取通知权限支持自动重连机制 (requestRebind) 以增强通知监听相关功能的稳定性

This commit is contained in:
SuperMonster003
2026-01-28 18:11:45 +08:00
parent 6e6d288c34
commit 2f223d1d67
5 changed files with 73 additions and 5 deletions

View File

@@ -1,7 +1,7 @@
{
"$data": {
"v6.7.0": {
"released_date": "2026/01/27",
"released_date": "2026/01/28",
"feature": [
"插件中心功能, 支持插件的安装/卸载/更新等操作 (入口: 主页抽屉按钮/主页标签页)",
"Paddle OCR (PP-OCRv5) 插件, 用于光学字符识别",
@@ -138,6 +138,7 @@
"客户端模式连接时支持特殊用途 IPv4 地址 (回环/广播/多播/保留/...) 检测提示",
"客户端模式连接时支持连接状态显示及管理 (修正地址/中止连接)",
"服务端模式连接时支持显示已建立连接的客户端数量",
"读取通知权限支持自动重连机制 ([requestRebind](https://developer.android.com/reference/android/service/notification/NotificationListenerService#requestRebind(android.content.ComponentName))) 以增强通知监听相关功能的稳定性",
"浮动按钮增强后台启动 Activity 的安全性以避免应用崩溃",
"浮动按钮 \"更多\" 对话框使用异步加载数据方式提升显示流畅度",
"浮动按钮 \"运行脚本\" 对话框增加 \"主页\" 菜单项",

View File

@@ -1,13 +1,17 @@
package org.autojs.autojs.core.notification
import android.content.ComponentName
import android.content.Context
import android.provider.Settings
import android.service.notification.StatusBarNotification
import org.autojs.autojs.core.accessibility.NotificationListener
import java.util.concurrent.CopyOnWriteArrayList
import android.service.notification.NotificationListenerService as AndroidNotificationListenerService
/**
* Created by Stardust on Oct 30, 2017.
*/
class NotificationListenerService : android.service.notification.NotificationListenerService() {
class NotificationListenerService : AndroidNotificationListenerService() {
private val mNotificationListeners = CopyOnWriteArrayList<NotificationListener>()
@@ -44,8 +48,31 @@ class NotificationListenerService : android.service.notification.NotificationLis
}
companion object {
@JvmStatic
var instance: NotificationListenerService? = null
private set
@JvmStatic
fun isNotificationListenerEnabled(context: Context): Boolean {
val enabled = Settings.Secure.getString(
context.contentResolver,
"enabled_notification_listeners",
) ?: return false
val cn = ComponentName(context, NotificationListenerService::class.java).flattenToString()
return enabled.contains(cn)
}
@JvmStatic
fun requestRebindIfPossible(context: Context): Boolean {
if (!isNotificationListenerEnabled(context)) return false
return runCatching {
val cn = ComponentName(context, NotificationListenerService::class.java)
requestRebind(cn)
true
}.isSuccess
}
}
}

View File

@@ -40,6 +40,8 @@ import java.util.Set;
/**
* Created by Stardust on Jul 18, 2017.
* Modified by JetBrains AI Assistant (GPT-5.2) as of Jan 28, 2026.
* Modified by SuperMonster003 as of Jan 28, 2026.
*/
public class Events extends EventEmitter implements OnKeyListener, TouchObserver.OnTouchEventListener, NotificationListener, AccessibilityNotificationObserver.ToastListener, AccessibilityService.Companion.GestureListener {
@@ -72,8 +74,14 @@ public class Events extends EventEmitter implements OnKeyListener, TouchObserver
private boolean mListeningKey = false;
private final Loopers mLoopers;
private Handler mHandler;
private boolean mListeningNotification = false;
private boolean mListeningToast = false;
private int mNotificationBindRetryCount = 0;
private static final int NOTIFICATION_BIND_MAX_RETRY = 5;
private static final long NOTIFICATION_BIND_RETRY_DELAY_MS = 400L;
private final ScriptRuntime mScriptRuntime;
private volatile boolean mInterceptsAllKey = false;
private KeyInterceptor mKeyInterceptor;
@@ -237,21 +245,53 @@ public class Events extends EventEmitter implements OnKeyListener, TouchObserver
mListeningNotification = true;
ensureHandler();
mLoopers.waitWhenIdle(true);
if (NotificationListenerService.getInstance() != null) {
NotificationListenerService.getInstance().addListener(this);
return;
}
// Permission enabled but service not bound (common on some ROMs): try to rebind automatically.
// zh-CN: 权限已启用但服务未绑定 (在某些 ROM 上常见): 尝试自动重新绑定.
if (NotificationListenerService.isNotificationListenerEnabled(mContext)) {
mNotificationBindRetryCount = 0;
NotificationListenerService.requestRebindIfPossible(mContext);
retryAttachNotificationListener();
return;
}
// Permission not enabled: guide user to settings page.
// zh-CN: 权限未启用: 引导用户前往设置页面.
Intent intent = new Intent(Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS);
IntentUtils.startSafely(intent, mContext);
throw new ScriptException(mContext.getString(R.string.text_notification_service_disabled));
}
private void retryAttachNotificationListener() {
if (!mListeningNotification) {
return;
}
if (NotificationListenerService.getInstance() != null) {
NotificationListenerService.getInstance().addListener(this);
return;
}
if (mNotificationBindRetryCount++ >= NOTIFICATION_BIND_MAX_RETRY) {
// Still not bound: last resort, open settings page to let user re-toggle.
// zh-CN: 仍未绑定: 最后的手段, 打开设置页面让用户重新切换.
Intent intent = new Intent(Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS);
IntentUtils.startSafely(intent, mContext);
return;
}
mHandler.postDelayed(this::retryAttachNotificationListener, NOTIFICATION_BIND_RETRY_DELAY_MS);
}
public void removeNotificationObserver() {
mAccessibilityBridge.getNotificationObserver().removeNotificationListener(this);
if (NotificationListenerService.getInstance() != null) {
NotificationListenerService.getInstance().removeListener(this);
}
mListeningNotification = false;
mNotificationBindRetryCount = 0;
if (!mListeningToast) {
mLoopers.waitWhenIdle(false);
}

View File

@@ -10,7 +10,7 @@ import org.autojs.autojs.util.IntentUtils.startSafely
class NotificationService(override val context: Context) : ServiceItemHelper {
override val isRunning: Boolean
get() = NotificationListenerService.instance != null
get() = NotificationListenerService.isNotificationListenerEnabled(context)
override fun start(): Boolean = false.also { config() }

View File

@@ -1,5 +1,5 @@
#Wed Jan 28 17:23:27 CST 2026
BUILD_TIME=1769592207672
#Wed Jan 28 18:09:10 CST 2026
BUILD_TIME=1769594950154
COMPILE_SDK_VERSION=36
IMAGE_QUANT_CMAKE_VERSION=3.22.1
IMAGE_QUANT_NDK_VERSION=26.1.10909125