android - 如何以编程方式从辅助服务中添加和删除布局?

标签 android android-layout accessibilityservice

我正在关注this Google 的官方教程,展示了在 View 顶部添加布局。但是,从激活辅助服务时起,它总是添加布局。

我想在执行某个操作后以编程方式添加此布局,并在执行其他操作后再次删除它。

这是我的无障碍服务 XML:

<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
    android:accessibilityEventTypes="typeViewClicked|typeViewFocused"
    android:packageNames="com.whatsapp"
    android:accessibilityFeedbackType="feedbackSpoken"
    android:notificationTimeout="100"
    android:settingsActivity="com.example.android.apis.accessibility.TestBackActivity"
    android:canRetrieveWindowContent="true" />

以下是我的代码,大部分是从教程中借来的:

public class GlobalActionBarService extends AccessibilityService {

    private static final String TAG = "AccessibilityService";
    private WindowManager mWindowManager;
    FrameLayout mLayout;

    @Override
    public void onAccessibilityEvent(AccessibilityEvent event) {
        final int eventType = event.getEventType();
        String eventText = null;
        switch(eventType) {
            case AccessibilityEvent.TYPE_VIEW_CLICKED:
                eventText = "Clicked: ";
                break;
            case AccessibilityEvent.TYPE_VIEW_FOCUSED:
                eventText = "Focused: ";
                break;
        }

        eventText = eventText + event.getContentDescription();

        mLayout = new FrameLayout(this);
        mWindowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
        WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
        lp.type = WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY;
        lp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN;
        lp.format = PixelFormat.TRANSLUCENT;
        lp.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
        lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
        lp.gravity = Gravity.TOP;
        LayoutInflater inflater = LayoutInflater.from(this);
        inflater.inflate(R.layout.action_bar, mLayout);

        if (eventText.toLowerCase().contains("test")) {
            Log.d(TAG, "Oh! Displaying the layout");
            mWindowManager.addView(mLayout, lp);
        }

        if (eventText.toLowerCase().contains("navigate")) {
            Log.d(TAG, "Removing the layout");
            if (mLayout != null && mLayout.getRootView() != null) {
                mWindowManager.removeView(mLayout.getRootView());
            }
        }
    }

    @Override
    public void onInterrupt() {

    }

} 

但是,我的代码损坏了,而且显然是错误的。当它尝试删除布局时会失败。 (而且,它是否多次添加相同的布局?)。我应该考虑哪些性能问题吗?

以下是当我尝试删除框架布局时引发的异常:

03-08 22:28:10.375 24266-24266/im.avi.todolist E/AndroidRuntime: 
FATAL EXCEPTION: main
Process: im.avi.todolist, PID: 24266
java.lang.IllegalArgumentException: View=android.widget.FrameLayout{3695c2 V.E...... ......I. 0,0-0,0} not attached to window manager
 at android.view.WindowManagerGlobal.findViewLocked(WindowManagerGlobal.java:473)
 at android.view.WindowManagerGlobal.removeView(WindowManagerGlobal.java:382)
 at android.view.WindowManagerImpl.removeView(WindowManagerImpl.java:119)
 at im.avi.todolist.GlobalActionBarService.onAccessibilityEvent(GlobalActionBarService.java:77)
 at android.accessibilityservice.AccessibilityService$2.onAccessibilityEvent(AccessibilityService.java:1449)
 at android.accessibilityservice.AccessibilityService$IAccessibilityServiceClientWrapper.executeMessage(AccessibilityService.java:1585)
 at com.android.internal.os.HandlerCaller$MyHandler.handleMessage(HandlerCaller.java:37)
 at android.os.Handler.dispatchMessage(Handler.java:102)
 at android.os.Looper.loop(Looper.java:154)
 at android.app.ActivityThread.main(ActivityThread.java:6119)
 at java.lang.reflect.Method.invoke(Native Method)
 at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
 at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)

最佳答案

在 friend 的帮助下我找到了解决方案。我犯的错误是每次都添加框架布局。以下是现在可以运行的代码:

public class GlobalActionBarService extends AccessibilityService {

    private static final String TAG = "AccessibilityService";
    private WindowManager mWindowManager;
    FrameLayout mLayout;

    @Override
    public void onAccessibilityEvent(AccessibilityEvent event) {
        final int eventType = event.getEventType();
        String eventText = null;
        switch(eventType) {
            case AccessibilityEvent.TYPE_VIEW_CLICKED:
                eventText = "Clicked: ";
                break;
            case AccessibilityEvent.TYPE_VIEW_FOCUSED:
                eventText = "Focused: ";
                break;
        }

        eventText = eventText + event.getContentDescription();

        if (eventText.toLowerCase().contains("test")) {
            Log.d(TAG, "Oh! Displaying the layout");
            if (mLayout == null) {
                mLayout = new FrameLayout(this);
                mWindowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
                WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
                lp.type = WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY;
                lp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN;
                lp.format = PixelFormat.TRANSLUCENT;
                lp.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
                lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
                lp.gravity = Gravity.TOP;
                LayoutInflater inflater = LayoutInflater.from(this);
                inflater.inflate(R.layout.action_bar, mLayout);
                mWindowManager.addView(mLayout, lp);
            }
        }

        if (eventText.toLowerCase().contains("navigate")) {
            Log.d(TAG, "Removing the layout");
            if (mLayout != null && mLayout.getRootView() != null) {
                mWindowManager.removeView(mLayout);
                mLayout = null;
            }
        }
    }

    @Override
    public void onInterrupt() {

    }

} 

关于android - 如何以编程方式从辅助服务中添加和删除布局?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42675668/

相关文章:

android - 将 Android SDK 工具更新到修订版 14 后的 Ant 问题

java - 如何从 GooglePlayGames 邀请启动特定 Activity

android - 复选框未出现在自定义 ListView 中

android - 相对布局中的ImageView和listview

android - 共享首选项上的辅助功能设置更改值

android - “通用图像加载器”丢失了我的 ImageView 的参数(大小和位置)

android - Google Mobile Vision的商业用途

android - 在 android 中使用 drawable 设置按钮的边距

android - AccessibilityNodeInfo nodeInfo = event.getSource() 总是返回 null

Android:以编程方式截取通知栏的屏幕截图