【问题标题】:How do I add and remove a layout programmatically from an accessibility service?如何以编程方式从无障碍服务中添加和删除布局?
【发布时间】:2017-03-09 15:04:27
【问题描述】:

我正在关注 Google 的 this 官方教程,该教程显示了在视图顶部添加布局。但是,它始终添加布局,从激活无障碍服务开始。

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

这是我的无障碍服务 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)

【问题讨论】:

    标签: android android-layout accessibilityservice


    【解决方案1】:

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

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

    【讨论】:

    • 完美的工作,谢谢。我一直在做这个任务,现在我得到了解决方案。
    猜你喜欢
    • 2016-11-26
    • 2012-12-25
    • 2013-06-06
    • 2017-07-16
    • 1970-01-01
    • 2019-06-12
    • 2017-10-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多