一种Android服务,它在后台运行,并在触发可访问性事件时由系统接收回调。
我有一个 jetpack 撰写概览小部件,它在启动时显示一条短信。 如果用户为应用程序启用了辅助功能服务,则扫视小部件应更改为按钮。但这不是...
如何使用 TYPE_WINDOW_STATE_CHANGED 的辅助服务
我尝试使用辅助功能服务来处理打开新活动或窗口时的事件。但这不起作用。 **首先,我实现一个辅助服务类,如下所示: 公开课
我尝试过命令 adb shell settings put secureenabled_accessibility_services com.android.talkback/com.google.android.marvin.talkback.TalkBackService 从 adb shell 启用对讲。是
有没有办法在打开系统对话框(在本例中为关闭弹出窗口)和通知面板时关闭它们? 使用辅助功能服务,我收到执行这些操作的事件...
当应用程序最小化时(在 android 14 中),我没有收到任何辅助功能事件,但它在 android 10 中工作正常 显现: 当应用程序最小化(在 android 14 中)时,我没有收到任何辅助功能事件,但它在 android 10 中工作正常 清单: <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"> <uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" tools:ignore="ProtectedPermissions" /> <uses-permission android:name="android.permission.GET_TASKS" /> <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" /> <uses-permission android:name="android.permission.BIND_ACCESSIBILITY_SERVICE" /> <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/> <uses-permission android:name="android.permission.POST_NOTIFICATIONS"/> <queries> <intent> <action android:name="android.intent.action.MAIN" /> </intent> </queries> <application android:name="MyApplication" android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:roundIcon="@mipmap/ic_launcher" android:label="@string/app_name" android:supportsRtl="true" android:theme="@style/AppTheme"> <activity android:name="MainActivity" android:exported="true"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name="CrashActivity" /> <service android:name="ScreenshotService" android:foregroundServiceType="mediaProjection" android:permission="android.permission.FOREGROUND_SERVICE" /> <service android:name="MyAccessibilityService" android:exported="true" android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"> <intent-filter> <action android:name="android.accessibilityservice.AccessibilityService" /> </intent-filter> <meta-data android:name="android.accessibilityservice" android:resource="@xml/accessibility_service_config" /> </service> </application> </manifest> 无障碍服务: package aman.astau; import android.accessibilityservice.AccessibilityService; import android.app.NotificationManager; import android.content.Context; import android.app.NotificationChannel; import android.app.Notification; import android.os.Build; import android.view.accessibility.AccessibilityEvent; import android.widget.Toast; import androidx.core.app.NotificationCompat; public class MyAccessibilityService extends AccessibilityService { private static final String CHANNEL_ID = "accessibility_service_channel"; private static final int NOTIFICATION_ID = 1; @Override public void onCreate() { super.onCreate(); // Create the notification channel createNotificationChannel(); // Create a persistent notification Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID) .setContentTitle("Accessibility Service") .setContentText("The service is running in the background") .setSmallIcon(android.R.drawable.ic_dialog_info) .build(); // Start the service in the foreground startForeground(NOTIFICATION_ID, notification); } @Override public void onAccessibilityEvent(AccessibilityEvent event) { Toast.makeText(getApplicationContext(), "something happened", Toast.LENGTH_SHORT).show(); } @Override public void onInterrupt() { // Handle interruptions (e.g., if the service is turned off) Toast.makeText(getApplicationContext() , "interrupted" , 0).show(); } private void createNotificationChannel() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { CharSequence name = "Accessibility Service Channel"; String description = "Channel for accessibility service"; int importance = NotificationManager.IMPORTANCE_DEFAULT; NotificationChannel channel = new NotificationChannel(CHANNEL_ID, name, importance); channel.setDescription(description); // Register the channel with the system NotificationManager notificationManager = getSystemService(NotificationManager.class); if (notificationManager != null) { notificationManager.createNotificationChannel(channel); } } } } 配置 <accessibility-service xmlns:android="http://schemas.android.com/apk/res/android" android:accessibilityEventTypes="typeAllMask" android:accessibilityFeedbackType="feedbackGeneric" android:notificationTimeout="1000" android:canRetrieveWindowContent="true" android:canRequestFilterKeyEvents="true" android:accessibilityFlags="flagDefault|flagReportViewIds|flagIncludeNotImportantViews" android:description="@string/accessibility_service_description" /> 我希望它能像在 Android 10 中一样工作 需要注意的一件事 - “Mt manager”或“current Activity”等应用程序能够显示应用程序的整个类名称 这是我自己的问题,所以问题是代码工作正常,但当时我依靠 toast 消息来记录它在 android 10 中工作,但在 android 14 中,我猜 toast 消息不会显示当应用程序最小化后,我使用Log进行检查,发现它已经工作正常了。 TL;DR - 使用 Log 而不是 Toast
使用 AccessibilityService 检测屏幕任何区域的长按
我正在尝试使用 Accessiblity Service 检测屏幕任何区域的长按,我已经设置了代码,但它不起作用..任何帮助将不胜感激 ** 无障碍服务 班级
如何使用 Android 中的辅助功能服务访问弹出窗口中的元素
我一直在开发一个辅助服务来访问应用程序的元素数据,例如文本、描述、资源 ID 等,使用以下辅助功能配置: 我一直在开发辅助功能服务,以使用以下辅助功能配置来访问应用程序的元素数据,例如文本、描述、资源 ID 等: <accessibility-service android:accessibilityEventTypes="typeViewClicked|typeViewLongClicked|typeViewScrolled" android:accessibilityFeedbackType="feedbackGeneric" android:accessibilityFlags="flagIncludeNotImportantViews|flagRetrieveInteractiveWindows|flagReportViewIds" android:canRetrieveWindowContent="true" xmlns:android="http://schemas.android.com/apk/res/android"/> 通过此设置,我可以在与应用程序中的元素交互时捕获事件。但是,当弹出窗口打开并且我尝试与弹出窗口中的按钮(例如搜索按钮、星号消息、回复按钮)进行交互时, onAccessibilityEvent() 函数中不会触发任何事件。 (弹出窗口如所附屏幕截图所示)。 我还尝试通过将 android:accessibilityFlags 更改为来修改配置: android:accessibilityFlags="flagRequestTouchExplorationMode|flagIncludeNotImportantViews|flagRetrieveInteractiveWindows|flagReportViewIds" 但是,我仍然只收到屏幕的根元素。我知道此功能是可能的,因为像 TalkBack 这样的服务可以轻松处理此类交互。为了实现所需的功能我可能会缺少什么? bottomSheet 代码: <?xml version="1.0" encoding="utf-8"?> <androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content"> <RelativeLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="2dp"> <!--image view for displaying course image--> <ImageView android:id="@+id/idIVCourse" android:layout_width="100dp" android:layout_height="100dp" android:layout_margin="10dp" /> <!--text view for displaying course name--> <TextView android:id="@+id/idTVCourseName" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="10dp" android:layout_toEndOf="@id/idIVCourse" android:layout_toRightOf="@id/idIVCourse" android:text="DSA Self Paced Course" android:textColor="@color/black" android:textSize="18sp" android:textStyle="bold" /> <!--text view for displaying course tracks--> <TextView android:id="@+id/idTVCourseTracks" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@id/idTVCourseName" android:layout_marginTop="10dp" android:layout_toEndOf="@id/idIVCourse" android:layout_toRightOf="@id/idIVCourse" android:text="Course Tracks : 30" android:textColor="@color/black" android:textSize="15sp" /> <!--text view for displaying course duration--> <TextView android:id="@+id/idTVCourseDuration" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@id/idTVCourseTracks" android:layout_marginTop="10dp" android:layout_toEndOf="@id/idIVCourse" android:layout_toRightOf="@id/idIVCourse" android:text="Course Duration : 4 Months" android:textColor="@color/black" android:textSize="15sp" /> <!--button for dismissing our dialog--> <Button android:id="@+id/idBtnDismiss" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@id/idIVCourse" android:layout_margin="10dp" android:text="Dismiss dialog" android:textAllCaps="false" /> </RelativeLayout> </androidx.cardview.widget.CardView> 从活动中打开底页的代码: val openBottomSheetButton: Button = findViewById(R.id.open_bottom_sheet_button) openBottomSheetButton.setOnClickListener { val dialog = BottomSheetDialog(this) val view = layoutInflater.inflate(R.layout.bottomsheet, null) val btnClose = view.findViewById<Button>(R.id.idBtnDismiss) btnClose.setOnClickListener { dialog.dismiss() } dialog.setCancelable(false) dialog.setContentView(view) dialog.show() } 编辑 然后我回去回顾了这个问题,最重要的部分: 我尝试与弹出窗口中的按钮(例如搜索按钮、星标消息、回复按钮)进行交互... onAccessibilityEvent() 函数中没有触发任何事件 我的答案表明我们绝对可以与弹出按钮进行交互,但是一旦打开弹出窗口,它就不会处理事件注册表,例如TYPE_VIEW_CLICKED 我确实检查过,我们能够检索 WINDOW_STATE_CHANGE 上的所有内容: private fun AccessibilityNodeInfo.forAllChildren(depth:Int = 0, fn:(AccessibilityNodeInfo, Int) -> Unit) { for (index in 0..<this.childCount){ this.getChild(index)?.let { fn(it, depth) it.forAllChildren(depth+1, fn) } } } // inside onAccessibilityEvent if (event?.eventType == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) { rootInActiveWindow.forAllChildren { node, depth -> Log("${" ".repeat(depth * 2)} ${node.viewIdResourceName} ${node.text}") } } 但是一旦点击视图我们就看不到了: // inside onAccessibilityEvent if (event?.eventType == AccessibilityEvent.TYPE_VIEW_CLICKED) { Log("onAccessibilityEvent CLICKED ${event.className ?: " "}") } 我稍后会花更多时间来解决这个问题,但这是一个问题,我们可能需要在问题跟踪器上提出错误 原答案 我花了一些时间对此进行了更多研究,说实话我仍然有点困惑,但我已经成功创建了一个小型演示。请理解,我仍然不知道我们为什么要这样做的实际意义。我希望至少进行一次讨论,这样我们才能找到答案。这里的评论根本不够。 我目前与此问题相关的问题: 这对残疾人有何帮助? 这是否与辅助技术(例如对讲、语音访问等)结合使用? 但我不想继续提问,而是想根据我所掌握的信息尝试一下。现在这就是我所做的: 使用尽可能多的代码编写一个打开底部工作表的自定义视图应用程序 编写跟踪用户移动的自定义辅助功能服务,如果显示底部工作表,看看是否可以找到关闭按钮并单击它 accessibility_service_config.xml <accessibility-service xmlns:android="http://schemas.android.com/apk/res/android" android:description="@string/accessibility_service_description" android:accessibilityEventTypes="typeAllMask" android:accessibilityFlags="flagIncludeNotImportantViews|flagRetrieveInteractiveWindows|flagReportViewIds" android:accessibilityFeedbackType="feedbackGeneric" android:notificationTimeout="100" android:canRetrieveWindowContent="true" /> SampleAccessibilityService.kt class SampleAccessibilityService: AccessibilityService() { override fun onInterrupt() { Log("onInterrupt") } override fun onAccessibilityEvent(event: AccessibilityEvent?) { Log("---------------------------------------------------------") Log("onAccessibilityEvent CLASS ${event?.className ?: " "} -- ${BottomSheetDialog::class.java.name}") Log("onAccessibilityEvent EVENT ${event?.eventType ?: " "}") Log("onAccessibilityEvent TEXT ${event?.text ?: " "}") if (event?.eventType == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED && event.className == BottomSheetDialog::class.java.name) { rootInActiveWindow.findAccessibilityNodeInfosByText("Dismiss dialog").forEach { node -> Log(" onAccessibilityEvent CLICKING A NODE") node.performAction(AccessibilityNodeInfo.ACTION_CLICK) } } } override fun onServiceConnected() { Log("onServiceConnected") serviceInfo.apply { // I have found you have to do this in the config and onServiceConnected. Mine are actually mismatched but the service worked fine. ¯\_(ツ)_/¯ eventTypes = AccessibilityEvent.TYPE_VIEW_CLICKED or AccessibilityEvent.TYPE_VIEW_FOCUSED notificationTimeout = 100 } } } object Log { operator fun invoke(text: String) { android.util.Log.d("SAMPLEALLYSERVICE","SAMPLEALLYSERVICE: $text") } } 当我从“设置”菜单启用此服务时: Settings -> Accessibility -> Sample Accessibility Service -> Use Sample Accessibility Service 打开我的测试应用程序 打开底页 我可以看到它立即关闭了。 我真的希望这能为您带来一些启发 - 您必须在辅助功能服务中使用事件触发器才能知道某些方面发生了变化,例如 TYPE_WINDOW_STATE_CHANGED - 然后我通过文本而不是 ID 查找节点,因为 ID 是将会变得不那么流行(Jetpack Compose),我可以通过可访问性节点发送交互命令: node.performAction(AccessibilityNodeInfo.ACTION_CLICK)
对于 Android 14 上 filterTouchesWhenObscured 标志为 true 的应用,不会报告辅助功能服务信息
我的应用程序依赖于辅助功能事件(例如,AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED 或 AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED)以及 AccessibiltyNodeInfo 中的信息
我一直在开发一个辅助服务来访问应用程序的元素数据,例如文本、描述、资源 ID 等,使用以下辅助功能配置: 我一直在开发辅助功能服务,以使用以下辅助功能配置来访问应用程序的元素数据,例如文本、描述、资源 ID 等: <accessibility-service android:accessibilityEventTypes="typeViewClicked|typeViewLongClicked|typeViewScrolled" android:accessibilityFeedbackType="feedbackGeneric" android:accessibilityFlags="flagIncludeNotImportantViews|flagRetrieveInteractiveWindows|flagReportViewIds" android:canRetrieveWindowContent="true" xmlns:android="http://schemas.android.com/apk/res/android"/> 通过此设置,我可以在与应用程序中的元素交互时捕获事件。但是,当弹出窗口打开并且我尝试与弹出窗口中的按钮(例如搜索按钮、星号消息、回复按钮)进行交互时, onAccessibilityEvent() 函数中不会触发任何事件。 (弹出窗口如所附屏幕截图所示)。 我还尝试通过将 android:accessibilityFlags 更改为来修改配置: android:accessibilityFlags="flagRequestTouchExplorationMode|flagIncludeNotImportantViews|flagRetrieveInteractiveWindows|flagReportViewIds" 但是,我仍然只收到屏幕的根元素。我知道此功能是可能的,因为像 TalkBack 这样的服务可以轻松处理此类交互。您能否指导我实现所需功能时可能缺少的内容? bottomSheet 代码: <?xml version="1.0" encoding="utf-8"?> <androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content"> <RelativeLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="2dp"> <!--image view for displaying course image--> <ImageView android:id="@+id/idIVCourse" android:layout_width="100dp" android:layout_height="100dp" android:layout_margin="10dp" /> <!--text view for displaying course name--> <TextView android:id="@+id/idTVCourseName" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="10dp" android:layout_toEndOf="@id/idIVCourse" android:layout_toRightOf="@id/idIVCourse" android:text="DSA Self Paced Course" android:textColor="@color/black" android:textSize="18sp" android:textStyle="bold" /> <!--text view for displaying course tracks--> <TextView android:id="@+id/idTVCourseTracks" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@id/idTVCourseName" android:layout_marginTop="10dp" android:layout_toEndOf="@id/idIVCourse" android:layout_toRightOf="@id/idIVCourse" android:text="Course Tracks : 30" android:textColor="@color/black" android:textSize="15sp" /> <!--text view for displaying course duration--> <TextView android:id="@+id/idTVCourseDuration" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@id/idTVCourseTracks" android:layout_marginTop="10dp" android:layout_toEndOf="@id/idIVCourse" android:layout_toRightOf="@id/idIVCourse" android:text="Course Duration : 4 Months" android:textColor="@color/black" android:textSize="15sp" /> <!--button for dismissing our dialog--> <Button android:id="@+id/idBtnDismiss" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@id/idIVCourse" android:layout_margin="10dp" android:text="Dismiss dialog" android:textAllCaps="false" /> </RelativeLayout> </androidx.cardview.widget.CardView> 从活动中打开底页的代码: val openBottomSheetButton: Button = findViewById(R.id.open_bottom_sheet_button) openBottomSheetButton.setOnClickListener { val dialog = BottomSheetDialog(this) val view = layoutInflater.inflate(R.layout.bottomsheet, null) val btnClose = view.findViewById<Button>(R.id.idBtnDismiss) btnClose.setOnClickListener { dialog.dismiss() } dialog.setCancelable(false) dialog.setContentView(view) dialog.show() } 我花了一些时间对此进行了更多研究,说实话我仍然有点困惑,但我已经成功创建了一个小型演示。请理解,我仍然不知道我们为什么要这样做的实际意义。我希望至少进行一次讨论,这样我们才能找到答案。这里的评论根本不够。 我目前与此问题相关的问题: 这对残疾人有何帮助? 这是否与辅助技术(例如对讲、语音访问等)结合使用? 但我不想继续提问,而是想根据我所掌握的信息尝试一下。现在这就是我所做的: 使用尽可能多的代码编写一个打开底部工作表的自定义视图应用程序 编写跟踪用户移动的自定义辅助功能服务,如果显示底部工作表,看看是否可以找到关闭按钮并单击它 accessibility_service_config.xml <accessibility-service xmlns:android="http://schemas.android.com/apk/res/android" android:description="@string/accessibility_service_description" android:accessibilityEventTypes="typeAllMask" android:accessibilityFlags="flagIncludeNotImportantViews|flagRetrieveInteractiveWindows|flagReportViewIds" android:accessibilityFeedbackType="feedbackGeneric" android:notificationTimeout="100" android:canRetrieveWindowContent="true" /> SampleAccessibilityService.kt class SampleAccessibilityService: AccessibilityService() { override fun onInterrupt() { Log("onInterrupt") } override fun onAccessibilityEvent(event: AccessibilityEvent?) { Log("---------------------------------------------------------") Log("onAccessibilityEvent CLASS ${event?.className ?: " "} -- ${BottomSheetDialog::class.java.name}") Log("onAccessibilityEvent EVENT ${event?.eventType ?: " "}") Log("onAccessibilityEvent TEXT ${event?.text ?: " "}") if (event?.eventType == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED && event.className == BottomSheetDialog::class.java.name) { rootInActiveWindow.findAccessibilityNodeInfosByText("Dismiss dialog").forEach { node -> Log(" onAccessibilityEvent CLICKING A NODE") node.performAction(AccessibilityNodeInfo.ACTION_CLICK) } } } override fun onServiceConnected() { Log("onServiceConnected") serviceInfo.apply { // I have found you have to do this in the config and onServiceConnected. Mine are actually mismatched but the service worked fine. ¯\_(ツ)_/¯ eventTypes = AccessibilityEvent.TYPE_VIEW_CLICKED or AccessibilityEvent.TYPE_VIEW_FOCUSED notificationTimeout = 100 } } } object Log { operator fun invoke(text: String) { android.util.Log.d("SAMPLEALLYSERVICE","SAMPLEALLYSERVICE: $text") } } 当我从“设置”菜单启用此服务时: Settings -> Accessibility -> Sample Accessibility Service -> Use Sample Accessibility Service 打开我的测试应用程序 打开底页 我可以看到它立即关闭了。 我真的希望这能为您带来一些启发 - 您必须在辅助功能服务中使用事件触发器才能知道某些方面发生了变化,例如 TYPE_WINDOW_STATE_CHANGED - 然后我通过文本而不是 ID 查找节点,因为 ID 是将会变得不那么流行(Jetpack Compose),我可以通过可访问性节点发送交互命令: node.performAction(AccessibilityNodeInfo.ACTION_CLICK)
我使用以下代码以编程方式单击屏幕。但它就是行不通。我在 Android 13 和 Android 14 调试版和发布版上进行了测试 ClickAccessibilityService 类:
辅助功能服务 - PerformGlobalAction() 不起作用?
我正在创建一个调用performGlobalAction()的Android辅助服务 导入 android.accessibilityservice.AccessibilityService; 导入 android.content.Intent; 导入 android.view.accessi...
自 Android studio 3.5 起,辅助服务在每次运行时都会自动关闭
自从我将 Android Studio 更新到 3.5 以来,当我启动 Run 来构建和部署我的应用程序时,我的自定义辅助功能服务会自动关闭(不是崩溃,只是在设置中关闭)。 钙...
当尝试通过向我的博览会应用程序添加自定义模块来创建 Android 辅助服务时,我在构建我的开发版本时遇到错误 我几周前才开始使用 expo,因为我想......
Android 电视应用程序中的辅助功能服务自动禁用(在详细视图的右侧显示已启用,在应用程序名称的左侧显示已启用)
我通过使用自定义辅助功能服务创建了 android 电视应用程序。我用它来监听“HOME”按钮按键事件来启动我的应用程序(当用户按下方向键上的“HOME”按钮时)。
Android多屏设置中如何访问AccessibilityNode并点击副屏?
我正在构建一个支持两个显示器的 Android AccessibilityService。 想法是在第一个显示器上有一个可拖动的触摸区域(类似于触摸栏),用户可以用它拖动到我的...
在android中按后退或主页按钮时可以使用WindowManager删除覆盖吗?
我试图在网站上找到我的问题的一些答案,但我没有找到任何东西,而且我不确定当按后退或主页按钮时是否可以使用 windowManager 删除或隐藏覆盖层。 ...
AccessibilityNodeInfo 的生命周期是怎样的?
我正在开发一款 Android 应用程序,其中包含辅助功能服务,允许用户创建“宏”,可以快速、自动地执行他们经常使用第三方应用程序执行的任务
Android OS 13 - 使用辅助功能服务授予 MediaProjection 权限
我正在开发一个应用程序,它是一个私人应用程序,即它不会在 Google Play 商店上发布。 我使用的是 Android OS 13 设备。我的应用程序有屏幕投射功能。要使用此功能...
如何使用 AccessibilityService 从活动窗口获取所有内容
更新窗口时如何获取屏幕上的所有内容?这可能吗? 意味着当我打开和关闭任何应用程序以及设备的主屏幕时,我想从活动窗口获取所有文本。 <...
我一直致力于创建一个 Android 应用程序,该应用程序可以每 5 秒在屏幕上执行一次向上滑动手势。这个想法是让它滚动任何打开的应用程序,例如 Instagram 或 Facebook 上的 reels