dispatchPopulateAccessibilityEvent not triggered

2019-05-31 15:54发布

问题:

I'm trying to implement accessibility feature in my app. I'm confused about how it actually works. I've a simple imageView in different package from where I send events as:

public final void onClick(final android.view.View v) {
            android.util.Log.v(CLASSNAME,"onClick tag:"+v.getTag());
            v.sendAccessibilityEvent(android.view.accessibility.AccessibilityEvent.TYPE_VIEW_CLICKED);

I've implmented Accessibility class as follows:

import android.content.Context;

public final class Accessibility extends android.view.View {
     public Accessibility(Context context) {
        super(context);
        // TODO Auto-generated constructor stub
    }



    public static android.view.accessibility.AccessibilityManager manager = (android.view.accessibility.AccessibilityManager)getSystemService(android.content.Context.ACCESSIBILITY_SERVICE); 
    public static android.view.accessibility.AccessibilityEvent event = android.view.accessibility.AccessibilityEvent.obtain();

    public static Accessibility accessibility;


    public static boolean isEenabled()
    {

    if(manager.isEnabled())
        return true;
    else
        return false;
    }


    @Override
    public boolean dispatchPopulateAccessibilityEvent(android.view.accessibility.AccessibilityEvent event)
    {
        super.dispatchPopulateAccessibilityEvent(event);
        android.util.Log.e(CLASSNAME, "Came here");
                        {

            event.getText().add("Click here!!");
            event.setEnabled(true);
                            return true;
        }

I read the Developer docs and I have to override the method in View class (that's the reason I extended my class to View). I realized this method also exists in Activity class (i.e. extends Activity) which calls this method without even sending any events.

I know I'm doing something silly, but not able to find where exactly.

P.S.: I did set a breakpoint on v.sendAccessibilityEvent - It goes to View.java and somehow it fails at condition "AccessibilityManager.getInstance(mContext)!= null"

回答1:

The reason it is not called is because the system calls dispatchPopulateAccessibilityEvent of your ImageView(because you send the event from there), not the one of your Accessibility object.

To implement custom accessibility behavior you have 3 options:

  1. Implement a custom View that extends ImageView(and override the dispatchPopulateAccessibilityEvent method and other accessibility). This is a more generic approach and lets the developer imitate system widgets accessibility behavior.

    Here's an example class that adds custom text to the event object on TYPE_VIEW_CLICKED event. You need to set its clickable attribute to true so it can receive clicked events. I've overridden onPopulateAccessibilityEvent rather than dispatchPopulateAccessibilityEvent because this class doesn't have children and there's no need to override dispatching algorithm.

    public class CustomImageView  extends ImageView {
    
        private static final String TAG = CustomImageView.class.getSimpleName();
    
        /* Here are constructors from ImageView */
    
        @Override
        public void onPopulateAccessibilityEvent(AccessibilityEvent event) {
            super.onPopulateAccessibilityEvent(event);
    
            if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_CLICKED) {
                Log.v(TAG, "Populating accessibility event");
                event.getText().add("Custom text from onPopulateAccessibilityEvent");
            }
        }
    }
    
  2. Implement AccessibilityDelegate. This is not as generic as the first method, but for simple applications it's easier and allows more complex accessibility behavior.

    Here's an AccessibilityDelegate that does similar thing to the CustomImageView. The main advantage is that you can reuse same AccessibilityDelegate for different objects and classes.

    imageView.setAccessibilityDelegate(new View.AccessibilityDelegate() {
        @Override
        public void onPopulateAccessibilityEvent(View host, AccessibilityEvent event) {
            super.onPopulateAccessibilityEvent(host, event);
    
            if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_CLICKED) {
                Log.v(TAG, "Populating accessibility event");
                event.getText().add("Custom text from AccessibilityDelegate");
            }
        }
    });
    
  3. Combine both methods if you need a very complex accessibility logic.

There are many accessibility methods in View, read documentation carefully which ones you really need to override.