6.7.0 - Alpha18 - 读取通知权限支持自动重连机制 (requestRebind) 以增强通知监听相关功能的稳定性
This commit is contained in:
@@ -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 的安全性以避免应用崩溃",
|
||||
"浮动按钮 \"更多\" 对话框使用异步加载数据方式提升显示流畅度",
|
||||
"浮动按钮 \"运行脚本\" 对话框增加 \"主页\" 菜单项",
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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() }
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user