Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0d67c890 authored by Svetoslav Ganov's avatar Svetoslav Ganov
Browse files

Adding accessibility support to the PIN lock screen.

1. The password lock screen is accessible and with this
   change the PIN lock screen is accessibile as well.
   This is enough to cover the enterprise use case of
   imposed lock of the deivce. we will hide the options
   for pattern since it is hard for use by a blind person.
   We may reconsider this for subsequent releases.

bug:4978246

Change-Id: I67ef783b799ffd64ebff6cdb614c03025fc911e6
parent 3e4e4af4
Loading
Loading
Loading
Loading
+79 −10
Original line number Diff line number Diff line
@@ -21,13 +21,14 @@ import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Paint.Align;
import android.graphics.PorterDuff;
import android.graphics.Rect;
import android.graphics.Typeface;
import android.graphics.Paint.Align;
import android.graphics.Region.Op;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.inputmethodservice.Keyboard.Key;
import android.media.AudioManager;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
@@ -39,6 +40,8 @@ import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup.LayoutParams;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
import android.widget.PopupWindow;
import android.widget.TextView;

@@ -175,7 +178,6 @@ public class KeyboardView extends View implements View.OnClickListener {
    private boolean mShowTouchPoints = true;
    private int mPopupPreviewX;
    private int mPopupPreviewY;
    private int mWindowY;

    private int mLastX;
    private int mLastY;
@@ -242,6 +244,10 @@ public class KeyboardView extends View implements View.OnClickListener {
    private boolean mKeyboardChanged;
    /** The canvas for the above mutable keyboard bitmap */
    private Canvas mCanvas;
    /** The accessibility manager for accessibility support */
    private AccessibilityManager mAccessibilityManager;
    /** The audio manager for accessibility support */
    private AudioManager mAudioManager;

    Handler mHandler = new Handler() {
        @Override
@@ -362,6 +368,10 @@ public class KeyboardView extends View implements View.OnClickListener {
        mSwipeThreshold = (int) (500 * getResources().getDisplayMetrics().density);
        mDisambiguateSwipe = getResources().getBoolean(
                com.android.internal.R.bool.config_swipeDisambiguation);

        mAccessibilityManager = AccessibilityManager.getInstance(context);
        mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);

        resetMultiTap();
        initGestureDetector();
    }
@@ -806,6 +816,7 @@ public class KeyboardView extends View implements View.OnClickListener {
                }
                mKeyboardActionListener.onKey(code, codes);
                mKeyboardActionListener.onRelease(code);
                sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED, (char) code);
            }
            mLastSentIndex = index;
            mLastTapTime = eventTime;
@@ -835,12 +846,18 @@ public class KeyboardView extends View implements View.OnClickListener {
        final Key[] keys = mKeys;
        if (oldKeyIndex != mCurrentKeyIndex) {
            if (oldKeyIndex != NOT_A_KEY && keys.length > oldKeyIndex) {
                keys[oldKeyIndex].onReleased(mCurrentKeyIndex == NOT_A_KEY);
                Key oldKey = keys[oldKeyIndex];
                oldKey.onReleased(mCurrentKeyIndex == NOT_A_KEY);
                invalidateKey(oldKeyIndex);
                final char character = (char) oldKey.codes[0];
                sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_HOVER_EXIT, character);
            }
            if (mCurrentKeyIndex != NOT_A_KEY && keys.length > mCurrentKeyIndex) {
                keys[mCurrentKeyIndex].onPressed();
                Key newKey = keys[mCurrentKeyIndex];
                newKey.onPressed();
                invalidateKey(mCurrentKeyIndex);
                final char character = (char) newKey.codes[0];
                sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_HOVER_ENTER, character);
            }
        }
        // If key changed and preview is on ...
@@ -940,6 +957,21 @@ public class KeyboardView extends View implements View.OnClickListener {
        mPreviewText.setVisibility(VISIBLE);
    }

    private void sendAccessibilityEvent(int eventType, char character) {
        if (mAccessibilityManager.isEnabled()) {
            AccessibilityEvent event = AccessibilityEvent.obtain(eventType);
            onInitializeAccessibilityEvent(event);
            // Add text only if a headset is used to avoid leaking passwords.
            if (mAudioManager.isBluetoothA2dpOn() || mAudioManager.isWiredHeadsetOn()) {
                event.getText().add(String.valueOf(character));
            } else {
                event.getText().add(mContext.getString(
                        R.string.keyboard_headset_required_to_hear_password));
            }
            mAccessibilityManager.sendAccessibilityEvent(event);
        }
    }

    /**
     * Requests a redraw of the entire keyboard. Calling {@link #invalidate} is not sufficient
     * because the keyboard renders the keys to an off-screen buffer and an invalidate() only 
@@ -1074,11 +1106,49 @@ public class KeyboardView extends View implements View.OnClickListener {
        return false;
    }

    private long mOldEventTime;
    private boolean mUsedVelocity;
    @Override
    public boolean dispatchHoverEvent(MotionEvent event) {
        // If touch exploring is enabled we ignore touch events and transform
        // the stream of hover events as touch events. This allows one consistent
        // event stream to drive the keyboard since during touch exploring the
        // first touch generates only hover events and tapping on the same
        // location generates hover and touch events.
        if (mAccessibilityManager.isEnabled()
                && mAccessibilityManager.isTouchExplorationEnabled()
                && event.getPointerCount() == 1) {
            final int action = event.getAction();
            switch (action) {
                case MotionEvent.ACTION_HOVER_ENTER:
                    event.setAction(MotionEvent.ACTION_DOWN);
                    break;
                case MotionEvent.ACTION_HOVER_MOVE:
                    event.setAction(MotionEvent.ACTION_MOVE);
                    break;
                case MotionEvent.ACTION_HOVER_EXIT:
                    event.setAction(MotionEvent.ACTION_UP);
                    break;
            }
            onTouchEventInternal(event);
            return true;
        }
        return super.dispatchHoverEvent(event);
    }

    @Override
    public boolean onTouchEvent(MotionEvent me) {
    public boolean onTouchEvent(MotionEvent event) {
        // If touch exploring is enabled we ignore touch events and transform
        // the stream of hover events as touch events. This allows one consistent
        // event stream to drive the keyboard since during touch exploring the
        // first touch generates only hover events and tapping on the same
        // location generates hover and touch events.
        if (mAccessibilityManager.isEnabled()
                && mAccessibilityManager.isTouchExplorationEnabled()) {
            return true;
        }
        return onTouchEventInternal(event);
    }

    public boolean onTouchEventInternal(MotionEvent me) {
        // Convert multi-pointer up/down events to single up/down events to 
        // deal with the typical multi-pointer behavior of two-thumb typing
        final int pointerCount = me.getPointerCount();
@@ -1126,7 +1196,6 @@ public class KeyboardView extends View implements View.OnClickListener {
            touchY += mVerticalCorrection;
        final int action = me.getAction();
        final long eventTime = me.getEventTime();
        mOldEventTime = eventTime;
        int keyIndex = getKeyIndices(touchX, touchY, null);
        mPossiblePoly = possiblePoly;

+3 −0
Original line number Diff line number Diff line
@@ -3033,6 +3033,9 @@
    <!-- Description of the not pressed state of a ToggleButton. [CHAR LIMIT=NONE] -->
    <string name="togglebutton_not_pressed">not pressed</string>

    <!-- Announce that a headset is required to hear keyboard keys while typing a password. [CHAR LIMIT=NONE] -->
    <string name="keyboard_headset_required_to_hear_password">Key. Headset required to hear keys while typing a password.</string>

    <!-- Content description for the action bar "home" affordance. [CHAR LIMIT=NONE] -->
    <string name="action_bar_home_description">Navigate home</string>
    <!-- Content description for the action bar "up" affordance. [CHAR LIMIT=NONE] -->