如何以编程方式从无障碍服务中添加和删除布局? [英] How do I add and remove a layout programmatically from an accessibility service?

查看:60
本文介绍了如何以编程方式从无障碍服务中添加和删除布局?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在关注 this Google 的官方教程,展示了在视图顶部添加布局.但是,它始终添加布局,从激活辅助功能服务的时间开始.

I am following this official tutorial by Google, which shows adding a layout on top of a view. However, it adds the layout always, from the time accessibility service is activated.

我想在某个操作之后以编程方式添加此布局,并在其他一些操作之后再次将其删除.

I want to add this layout programmatically, after a certain action and remove it again, after some other action.

这是我的无障碍服务 XML:

Here is my XML for accessibility service:

<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" />

以下是我的代码,主要是从教程中借来的:

Following is my code, which I have mostly borrowed from the tutorial:

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() {

    }

} 

然而,我的代码中断了,显然是错误的.当它尝试删除布局时失败.(而且,它是否多次添加相同的布局?).还有我应该考虑的性能问题吗?

However, my code breaks and it is obviously wrong. It fails when it tries to remove the layout. (And also, is it adding the same layout multiple times?). And are there any performance issues I should consider?

以下是我尝试删除框架布局时抛出的异常:

Following is the exception which is thrown when I try to remove the frame layout:

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)

推荐答案

我在朋友的帮助下找到了解决方案.我犯的错误是每次都添加框架布局.以下是现在有效的代码:

I figured out the solution with a help of my friend. The mistake I was doing was adding the framelayout everytime. Following is the code which works now:

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() {

    }

} 

这篇关于如何以编程方式从无障碍服务中添加和删除布局?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆