FileDocCategorySizeDatePackage
AccessibilityInputFilter.javaAPI DocAndroid 5.1 API13300Thu Mar 12 22:22:42 GMT 2015com.android.server.accessibility

AccessibilityInputFilter

public class AccessibilityInputFilter extends android.view.InputFilter implements EventStreamTransformation
This class is an input filter for implementing accessibility features such as display magnification and explore by touch. NOTE: This class has to be created and poked only from the main thread.

Fields Summary
private static final String
TAG
private static final boolean
DEBUG
static final int
FLAG_FEATURE_SCREEN_MAGNIFIER
Flag for enabling the screen magnification feature.
static final int
FLAG_FEATURE_TOUCH_EXPLORATION
Flag for enabling the touch exploration feature.
static final int
FLAG_FEATURE_FILTER_KEY_EVENTS
Flag for enabling the filtering key events feature.
private final Runnable
mProcessBatchedEventsRunnable
private final android.content.Context
mContext
private final android.os.PowerManager
mPm
private final AccessibilityManagerService
mAms
private final android.view.Choreographer
mChoreographer
private int
mCurrentTouchDeviceId
private boolean
mInstalled
private int
mEnabledFeatures
private TouchExplorer
mTouchExplorer
private ScreenMagnifier
mScreenMagnifier
private EventStreamTransformation
mEventHandler
private MotionEventHolder
mEventQueue
private boolean
mMotionEventSequenceStarted
private boolean
mHoverEventSequenceStarted
private boolean
mKeyEventSequenceStarted
private boolean
mFilterKeyEvents
Constructors Summary
AccessibilityInputFilter(android.content.Context context, AccessibilityManagerService service)


        
        super(context.getMainLooper());
        mContext = context;
        mAms = service;
        mPm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
        mChoreographer = Choreographer.getInstance();
    
Methods Summary
private voidbatchMotionEvent(android.view.MotionEvent event, int policyFlags)

        if (DEBUG) {
            Slog.i(TAG, "Batching event: " + event + ", policyFlags: " + policyFlags);
        }
        if (mEventQueue == null) {
            mEventQueue = MotionEventHolder.obtain(event, policyFlags);
            scheduleProcessBatchedEvents();
            return;
        }
        if (mEventQueue.event.addBatch(event)) {
            return;
        }
        MotionEventHolder holder = MotionEventHolder.obtain(event, policyFlags);
        holder.next = mEventQueue;
        mEventQueue.previous = holder;
        mEventQueue = holder;
    
public voidclear()

        /* do nothing */
    
voiddisableFeatures()

        if (mTouchExplorer != null) {
            mTouchExplorer.clear();
            mTouchExplorer.onDestroy();
            mTouchExplorer = null;
        }
        if (mScreenMagnifier != null) {
            mScreenMagnifier.clear();
            mScreenMagnifier.onDestroy();
            mScreenMagnifier = null;
        }
        mEventHandler = null;
        mKeyEventSequenceStarted = false;
        mMotionEventSequenceStarted = false;
        mHoverEventSequenceStarted = false;
        mFilterKeyEvents = false;
    
private voidenableFeatures()

        mMotionEventSequenceStarted = false;
        mHoverEventSequenceStarted = false;
        if ((mEnabledFeatures & FLAG_FEATURE_SCREEN_MAGNIFIER) != 0) {
            mEventHandler = mScreenMagnifier = new ScreenMagnifier(mContext,
                    Display.DEFAULT_DISPLAY, mAms);
            mEventHandler.setNext(this);
        }
        if ((mEnabledFeatures & FLAG_FEATURE_TOUCH_EXPLORATION) != 0) {
            mTouchExplorer = new TouchExplorer(mContext, mAms);
            mTouchExplorer.setNext(this);
            if (mEventHandler != null) {
                mEventHandler.setNext(mTouchExplorer);
            } else {
                mEventHandler = mTouchExplorer;
            }
        }
        if ((mEnabledFeatures & FLAG_FEATURE_FILTER_KEY_EVENTS) != 0) {
            mFilterKeyEvents = true;
        }
    
private voidhandleMotionEvent(android.view.MotionEvent event, int policyFlags)

        if (DEBUG) {
            Slog.i(TAG, "Handling batched event: " + event + ", policyFlags: " + policyFlags);
        }
        // Since we do batch processing it is possible that by the time the
        // next batch is processed the event handle had been set to null.
        if (mEventHandler != null) {
            mPm.userActivity(event.getEventTime(), false);
            MotionEvent transformedEvent = MotionEvent.obtain(event);
            mEventHandler.onMotionEvent(transformedEvent, event, policyFlags);
            transformedEvent.recycle();
        }
    
voidnotifyAccessibilityEvent(android.view.accessibility.AccessibilityEvent event)

        if (mEventHandler != null) {
            mEventHandler.onAccessibilityEvent(event);
        }
    
public voidonAccessibilityEvent(android.view.accessibility.AccessibilityEvent event)

        // TODO Implement this to inject the accessibility event
        //      into the accessibility manager service similarly
        //      to how this is done for input events.
    
public voidonDestroy()

        /* ignore */
    
public voidonInputEvent(android.view.InputEvent event, int policyFlags)

        if (DEBUG) {
            Slog.d(TAG, "Received event: " + event + ", policyFlags=0x" 
                    + Integer.toHexString(policyFlags));
        }
        if (event instanceof MotionEvent
                && event.isFromSource(InputDevice.SOURCE_TOUCHSCREEN)) {
            MotionEvent motionEvent = (MotionEvent) event;
            onMotionEvent(motionEvent, policyFlags);
        } else if (event instanceof KeyEvent
                && event.isFromSource(InputDevice.SOURCE_KEYBOARD)) {
            KeyEvent keyEvent = (KeyEvent) event;
            onKeyEvent(keyEvent, policyFlags);
        } else {
            super.onInputEvent(event, policyFlags);
        }
    
public voidonInstalled()

        if (DEBUG) {
            Slog.d(TAG, "Accessibility input filter installed.");
        }
        mInstalled = true;
        disableFeatures();
        enableFeatures();
        super.onInstalled();
    
private voidonKeyEvent(android.view.KeyEvent event, int policyFlags)

        if (!mFilterKeyEvents) {
            super.onInputEvent(event, policyFlags);
            return;
        }
        if ((policyFlags & WindowManagerPolicy.FLAG_PASS_TO_USER) == 0) {
            mKeyEventSequenceStarted = false;
            super.onInputEvent(event, policyFlags);
            return;
        }
        // Wait for a down key event to start processing.
        if (!mKeyEventSequenceStarted) {
            if (event.getAction() != KeyEvent.ACTION_DOWN) {
                super.onInputEvent(event, policyFlags);
                return;
            }
            mKeyEventSequenceStarted = true;
        }
        mAms.notifyKeyEvent(event, policyFlags);
    
public voidonMotionEvent(android.view.MotionEvent transformedEvent, android.view.MotionEvent rawEvent, int policyFlags)

        sendInputEvent(transformedEvent, policyFlags);
    
private voidonMotionEvent(android.view.MotionEvent event, int policyFlags)

        if (mEventHandler == null) {
            super.onInputEvent(event, policyFlags);
            return;
        }
        if ((policyFlags & WindowManagerPolicy.FLAG_PASS_TO_USER) == 0) {
            mMotionEventSequenceStarted = false;
            mHoverEventSequenceStarted = false;
            mEventHandler.clear();
            super.onInputEvent(event, policyFlags);
            return;
        }
        final int deviceId = event.getDeviceId();
        if (mCurrentTouchDeviceId != deviceId) {
            mCurrentTouchDeviceId = deviceId;
            mMotionEventSequenceStarted = false;
            mHoverEventSequenceStarted = false;
            mEventHandler.clear();
        }
        if (mCurrentTouchDeviceId < 0) {
            super.onInputEvent(event, policyFlags);
            return;
        }
        // We do not handle scroll events.
        if (event.getActionMasked() == MotionEvent.ACTION_SCROLL) {
            super.onInputEvent(event, policyFlags);
            return;
        }
        // Wait for a down touch event to start processing.
        if (event.isTouchEvent()) {
            if (!mMotionEventSequenceStarted) {
                if (event.getActionMasked() != MotionEvent.ACTION_DOWN) {
                    return;
                }
                mMotionEventSequenceStarted = true;
            }
        } else {
            // Wait for an enter hover event to start processing.
            if (!mHoverEventSequenceStarted) {
                if (event.getActionMasked() != MotionEvent.ACTION_HOVER_ENTER) {
                    return;
                }
                mHoverEventSequenceStarted = true;
            }
        }
        batchMotionEvent((MotionEvent) event, policyFlags);
    
public voidonUninstalled()

        if (DEBUG) {
            Slog.d(TAG, "Accessibility input filter uninstalled.");
        }
        mInstalled = false;
        disableFeatures();
        super.onUninstalled();
    
private voidprocessBatchedEvents(long frameNanos)

        MotionEventHolder current = mEventQueue;
        while (current.next != null) {
            current = current.next;
        }
        while (true) {
            if (current == null) {
                mEventQueue = null;
                break;
            }
            if (current.event.getEventTimeNano() >= frameNanos) {
                // Finished with this choreographer frame. Do the rest on the next one.
                current.next = null;
                break;
            }
            handleMotionEvent(current.event, current.policyFlags);
            MotionEventHolder prior = current;
            current = current.previous;
            prior.recycle();
        }
    
private voidscheduleProcessBatchedEvents()

        mChoreographer.postCallback(Choreographer.CALLBACK_INPUT,
                mProcessBatchedEventsRunnable, null);
    
voidsetEnabledFeatures(int enabledFeatures)

        if (mEnabledFeatures == enabledFeatures) {
            return;
        }
        if (mInstalled) {
            disableFeatures();
        }
        mEnabledFeatures = enabledFeatures;
        if (mInstalled) {
            enableFeatures();
        }
    
public voidsetNext(EventStreamTransformation sink)

        /* do nothing */