SoloPi安卓自动化测试工具源码研究二:截获用户输入

2019-12-19  本文已影响0人  黑山老雕

截断用户点击事件

截断用户点击事件的代码在AccessbilityServiceImpl.java.

  1. 它注册了一个自定义的Accessibility服务。通过用setServiceInfo,设置info的flag为FLAG_REQUEST_TOUCH_EXPLORATION_MODE来实现对于用户输入事件的截获。

示例代码;


package com.zzp.floating;

import android.accessibilityservice.AccessibilityService;

import android.accessibilityservice.AccessibilityServiceInfo;

import android.util.Log;

import android.view.accessibility.AccessibilityEvent;

public class InterceptService extends AccessibilityService {

    private static final String TAG = "ZZP_Intercept";

    private static InterceptService instance = null;

    public static InterceptService getInstance(){

        return instance;

    }

    @Override

    protected void onServiceConnected() {

        Log.d(TAG, "onServiceConnected: ");

        instance = this;

        super.onServiceConnected();

    }

    @Override

    public void onAccessibilityEvent(AccessibilityEvent event) {

        Log.d(TAG, "onAccessibilityEvent: Got event " + event.toString());

    }

    @Override

    public void onInterrupt() {

    }

    public void setBlock() {

        AccessibilityServiceInfo info = getServiceInfo();

        if (info == null) {

            Log.e(TAG, "ServiceInfo为空");

            return;

        }

        info.flags = AccessibilityServiceInfo.FLAG_REPORT_VIEW_IDS |

                AccessibilityServiceInfo.FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY |

                AccessibilityServiceInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS |

                AccessibilityServiceInfo.FLAG_RETRIEVE_INTERACTIVE_WINDOWS |

                AccessibilityServiceInfo.DEFAULT |

                AccessibilityServiceInfo.FLAG_REQUEST_TOUCH_EXPLORATION_MODE;

        Log.d(TAG, "辅助功能进入触摸监控模式");

        setServiceInfo(info);

    }

    public void setNormal() {

        AccessibilityServiceInfo info = getServiceInfo();

        if (info == null) {

            Log.e(TAG, "ServiceInfo为空");

            return;

        }

        info.flags = AccessibilityServiceInfo.FLAG_REPORT_VIEW_IDS |

                AccessibilityServiceInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS |

                AccessibilityServiceInfo.FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY |

                AccessibilityServiceInfo.FLAG_RETRIEVE_INTERACTIVE_WINDOWS |

                AccessibilityServiceInfo.DEFAULT;

        Log.d(TAG, "辅助功能进入正常模式");

        setServiceInfo(info);

    }

}

注意,这个服务的 onServiceConnected 函数会被系统自动的绑定上。并不需要我们自己去bind 这个service。这是因为我们对这个服务声明特定的intent-filter和permission。

  1. 在manifest中声明一个service,注意提供特定的intent filter, permission 和 meta data。 manifest sample:

        <service android:name=".InterceptService"

            android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">

            <intent-filter>

                <!-- android:name必须是以下这个名字 -->

                <action android:name="android.accessibilityservice.AccessibilityService"></action>

            </intent-filter>

            <meta-data

                android:name="android.accessibilityservice"

                android:resource="@xml/accessibility" />

        </service>

meta data sample:


<?xml version="1.0" encoding="utf-8"?>

<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"

    android:accessibilityEventTypes="typeAllMask"

    android:accessibilityFeedbackType="feedbackAllMask"

    android:notificationTimeout="100"

    android:canRetrieveWindowContent="true"

    android:canRequestFilterKeyEvents="true"

    android:description="@string/accessibility_description"

    android:accessibilityFlags="flagDefault|flagIncludeNotImportantViews|flagReportViewIds|flagRequestEnhancedWebAccessibility|flagRetrieveInteractiveWindows"

    android:canRequestTouchExplorationMode="true"

    android:canRequestEnhancedWebAccessibility="true">

</accessibility-service>

参考:https://developer.android.com/guide/topics/ui/accessibility/service

  1. 基本上,安装app后,需要重启,这个服务才会被注册。切记切记。你可以在onServiceConnected处断点。当服务被bind的时候,断点会命中。

  2. 在服务中找到无障碍,英文的话找accessibility,启用无障碍权限。当你但确定的时候,服务就会被bind,onSerivceConnected会被调用。

调用无障碍权限的settings页面

在Serivce代码中,可以用


                Intent intent1 = new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS);

                intent1.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); //如果是在Serivce中启动,这行是重点

                startActivity(intent1);

启用acessibility service

有些设备上的accessibility service可能被禁用了。查看方法 adb shell dumpsys accessibility。 输出结果类似:


User state[attributes:{id=0, currentUser=true, accessibilityEnabled=false, touchExplorationEnabled=false, displayMagnificationEnabled=false}

          services:{}]

正常的话应该看起来像:


DUMP OF SERVICE accessibility:

ACCESSIBILITY MANAGER (dumpsys accessibility)

User state[attributes:{id=0, currentUser=true, touchExplorationEnabled=false, displayMagnificationEnabled=false, navBarMagnificationEnabled=false, autoclickEnabled=false}

          services:{Service[label=com.zzp.floating.Interce…, feedbackType[FEEDBACK_SPOKEN, FEEDBACK_HAPTIC, FEEDBACK_AUDIBLE, FEEDBACK_VISUAL, FEEDBACK_GENERIC, FEEDBACK_BRAILLE], capabilities=11, eventTypes=TYPES_ALL_MASK, notificationTimeout=100]}]

Window[AccessibilityWindowInfo[title=null, id=116, type=<UNKNOWN>, layer=0, bounds=Rect(0, 0 - 1080, 2160), focused=true, active=true, pictureInPicture=false, hasParent=false, isAnchored=false, hasChildren=false]]--------- 0.047s was the duration of dumpsys accessibility, ending at: 2019-12-18 16:23:15

那么手动启动的方法:


adb shell settings put secure enabled_accessibility_services packagname/servicename

还有人提到还需要做下述, 不过可能没有必要:


adb shell settings put secure accessibility_enabled 1

不过貌似最好还是在Settings页面里面激活

参考: https://stackoverflow.com/questions/10061154/how-to-programmatically-enable-disable-accessibility-service-in-android


转载请注明出处。

image

更多视频教程请在网易云课堂搜索黑山老雕。

上一篇下一篇

猜你喜欢

热点阅读