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

Commit f058340b authored by Svetoslav Ganov's avatar Svetoslav Ganov
Browse files

Adding accessibility support to the slide lock screen

bug:5210233

Change-Id: I93e876524ae6aaf75aadbe6a21c5c17d41a705f0
parent 42930641
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -370,6 +370,7 @@ package android {
    field public static final int dialogTitle = 16843250; // 0x10101f2
    field public static final int digits = 16843110; // 0x1010166
    field public static final int direction = 16843217; // 0x10101d1
    field public static final int directionDescriptions = 16843695; // 0x10103af
    field public static final int directionPriority = 16843218; // 0x10101d2
    field public static final int disableDependentsState = 16843249; // 0x10101f1
    field public static final int disabledAlpha = 16842803; // 0x1010033
@@ -938,6 +939,7 @@ package android {
    field public static final int tag = 16842961; // 0x10100d1
    field public static final int targetActivity = 16843266; // 0x1010202
    field public static final int targetClass = 16842799; // 0x101002f
    field public static final int targetDescriptions = 16843694; // 0x10103ae
    field public static final int targetDrawables = 16843654; // 0x1010386
    field public static final int targetPackage = 16842785; // 0x1010021
    field public static final int targetSdkVersion = 16843376; // 0x1010270
+186 −5
Original line number Diff line number Diff line
@@ -16,8 +16,6 @@

package com.android.internal.widget.multiwaveview;

import java.util.ArrayList;

import android.animation.Animator;
import android.animation.Animator.AnimatorListener;
import android.animation.AnimatorListenerAdapter;
@@ -31,15 +29,20 @@ import android.graphics.Canvas;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.os.Vibrator;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.MeasureSpec;
import android.view.ViewConfiguration;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;

import com.android.internal.R;

import java.util.ArrayList;

/**
 * A special widget containing a center and outer ring. Moving the center ring to the outer ring
 * causes an event that can be caught by implementing OnTriggerListener.
@@ -82,6 +85,8 @@ public class MultiWaveView extends View {
    private ArrayList<TargetDrawable> mChevronDrawables = new ArrayList<TargetDrawable>();
    private ArrayList<Tweener> mChevronAnimations = new ArrayList<Tweener>();
    private ArrayList<Tweener> mTargetAnimations = new ArrayList<Tweener>();
    private ArrayList<String> mTargetDescriptions;
    private ArrayList<String> mDirectionDescriptions;
    private Tweener mHandleAnimation;
    private OnTriggerListener mOnTriggerListener;
    private TargetDrawable mHandleDrawable;
@@ -103,6 +108,9 @@ public class MultiWaveView extends View {
    private boolean mDragging;
    private int mNewTargetResources;

    private boolean mWaveHovered = false;
    private long mLastHoverExitTimeMillis = 0;

    private AnimatorListener mResetListener = new AnimatorListenerAdapter() {
        public void onAnimationEnd(Animator animator) {
            switchToState(STATE_IDLE, mWaveCenterX, mWaveCenterY);
@@ -128,6 +136,8 @@ public class MultiWaveView extends View {
        }
    };
    private int mTargetResourceId;
    private int mTargetDescriptionsResourceId;
    private int mDirectionDescriptionsResourceId;

    public MultiWaveView(Context context) {
        this(context, null);
@@ -177,6 +187,25 @@ public class MultiWaveView extends View {
            throw new IllegalStateException("Must specify at least one target drawable");
        }

        // Read array of target descriptions
        if (a.getValue(R.styleable.MultiWaveView_targetDescriptions, outValue)) {
            final int resourceId = outValue.resourceId;
            if (resourceId == 0) {
                throw new IllegalStateException("Must specify target descriptions");
            }
            setTargetDescriptionsResourceId(resourceId);
        }

        // Read array of direction descriptions
        if (a.getValue(R.styleable.MultiWaveView_directionDescriptions, outValue)) {
            final int resourceId = outValue.resourceId;
            if (resourceId == 0) {
                throw new IllegalStateException("Must specify direction descriptions");
            }
            setDirectionDescriptionsResourceId(resourceId);
        }

        a.recycle();
        setVibrateEnabled(mVibrationDuration > 0);
    }

@@ -247,6 +276,9 @@ public class MultiWaveView extends View {
                showTargets(true);
                mHandleDrawable.setState(TargetDrawable.STATE_ACTIVE);
                setGrabbedState(OnTriggerListener.CENTER_HANDLE);
                if (AccessibilityManager.getInstance(mContext).isEnabled()) {
                    announceTargets();
                }
                break;

            case STATE_TRACKING:
@@ -347,6 +379,13 @@ public class MultiWaveView extends View {
        }
    }

    private void dispatchGrabbedEvent(int whichHandler) {
        vibrate();
        if (mOnTriggerListener != null) {
            mOnTriggerListener.onGrabbed(this, whichHandler);
        }
    }

    private void doFinish() {
        final int activeTarget = mActiveTarget;
        boolean targetHit =  activeTarget != -1;
@@ -475,6 +514,7 @@ public class MultiWaveView extends View {
            Drawable drawable = array.getDrawable(i);
            targetDrawables.add(new TargetDrawable(res, drawable));
        }
        array.recycle();
        mTargetResourceId = resourceId;
        mTargetDrawables = targetDrawables;
        updateTargetPositions();
@@ -498,6 +538,48 @@ public class MultiWaveView extends View {
        return mTargetResourceId;
    }

    /**
     * Sets the resource id specifying the target descriptions for accessibility.
     *
     * @param resourceId The resource id.
     */
    public void setTargetDescriptionsResourceId(int resourceId) {
        mTargetDescriptionsResourceId = resourceId;
        if (mTargetDescriptions != null) {
            mTargetDescriptions.clear();
        }
    }

    /**
     * Gets the resource id specifying the target descriptions for accessibility.
     *
     * @return The resource id.
     */
    public int getTargetDescriptionsResourceId() {
        return mTargetDescriptionsResourceId;
    }

    /**
     * Sets the resource id specifying the target direction descriptions for accessibility.
     *
     * @param resourceId The resource id.
     */
    public void setDirectionDescriptionsResourceId(int resourceId) {
        mDirectionDescriptionsResourceId = resourceId;
        if (mDirectionDescriptions != null) {
            mDirectionDescriptions.clear();
        }
    }

    /**
     * Gets the resource id specifying the target direction descriptions.
     *
     * @return The resource id.
     */
    public int getDirectionDescriptionsResourceId() {
        return mDirectionDescriptionsResourceId;
    }

    /**
     * Enable or disable vibrate on touch.
     *
@@ -593,6 +675,43 @@ public class MultiWaveView extends View {
        }
    }

    @Override
    public boolean onHoverEvent(MotionEvent event) {
        if (AccessibilityManager.getInstance(mContext).isTouchExplorationEnabled()) {
            final int action = event.getAction();
            switch (action) {
                case MotionEvent.ACTION_HOVER_ENTER:
                case MotionEvent.ACTION_HOVER_MOVE:
                    final float dx = event.getX() - mWaveCenterX;
                    final float dy = event.getY() - mWaveCenterY;
                    if (dist2(dx,dy) <= square(mTapRadius)) {
                        if (!mWaveHovered) {
                            mWaveHovered = true;
                            final long timeSinceLastHoverExitMillis =
                                event.getEventTime() - mLastHoverExitTimeMillis;
                            final long recurringEventsInterval =
                                ViewConfiguration.getSendRecurringAccessibilityEventsInterval();
                            if (timeSinceLastHoverExitMillis > recurringEventsInterval) {
                                String text =
                                    mContext.getString(R.string.content_description_sliding_handle);
                                announceText(text);
                            }
                        }
                    } else {
                        mWaveHovered = false;
                    }
                    break;
                case MotionEvent.ACTION_HOVER_EXIT:
                    mLastHoverExitTimeMillis = event.getEventTime();
                    mWaveHovered = false;
                    break;
                default:
                    mWaveHovered = false;
            }
        }
        return super.onHoverEvent(event);
    }

    private void handleUp(MotionEvent event) {
        if (DEBUG && mDragging) Log.v(TAG, "** Handle RELEASE");
        switchToState(STATE_FINISH, event.getX(), event.getY());
@@ -663,7 +782,11 @@ public class MultiWaveView extends View {
        invalidateGlobalRegion(mHandleDrawable);

        if (mActiveTarget != activeTarget && activeTarget != -1) {
            vibrate();
            dispatchGrabbedEvent(activeTarget);
            if (AccessibilityManager.getInstance(mContext).isEnabled()) {
                String targetContentDescription = getTargetDescription(activeTarget);
                announceText(targetContentDescription);
            }
        }
        mActiveTarget = activeTarget;
    }
@@ -771,4 +894,62 @@ public class MultiWaveView extends View {
        return dx*dx + dy*dy;
    }

    private void announceTargets() {
        StringBuilder utterance = new StringBuilder();
        final int targetCount = mTargetDrawables.size();
        for (int i = 0; i < targetCount; i++) {
            String targetDescription = getTargetDescription(i);
            String directionDescription = getDirectionDescription(i);
            if (!TextUtils.isEmpty(targetDescription)
                    && !TextUtils.isEmpty(directionDescription)) {
                utterance.append(targetDescription);
                utterance.append(" ");
                utterance.append(directionDescription);
                utterance.append(".");
            }
        }
        announceText(utterance.toString());
    }

    private void announceText(String text) {
        setContentDescription(text);
        sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
        setContentDescription(null);
    }

    private String getTargetDescription(int index) {
        if (mTargetDescriptions == null || mTargetDescriptions.isEmpty()) {
            mTargetDescriptions = loadDescriptions(mTargetDescriptionsResourceId);
            if (mTargetDrawables.size() != mTargetDescriptions.size()) {
                Log.w(TAG, "The number of target drawables must be"
                        + " euqal to the number of target descriptions.");
                return null;
            }
        }
        return mTargetDescriptions.get(index);
    }

    private String getDirectionDescription(int index) {
        if (mDirectionDescriptions == null || mDirectionDescriptions.isEmpty()) {
            mDirectionDescriptions = loadDescriptions(mDirectionDescriptionsResourceId);
            if (mTargetDrawables.size() != mDirectionDescriptions.size()) {
                Log.w(TAG, "The number of target drawables must be"
                        + " euqal to the number of direction descriptions.");
                return null;
            }
        }
        return mDirectionDescriptions.get(index);
    }

    private ArrayList<String> loadDescriptions(int resourceId) {
        TypedArray array = getContext().getResources().obtainTypedArray(resourceId);
        final int count = array.length();
        ArrayList<String> targetContentDescriptions = new ArrayList<String>(count);
        for (int i = 0; i < count; i++) {
            String contentDescription = array.getString(i);
            targetContentDescriptions.add(contentDescription);
        }
        array.recycle();
        return targetContentDescriptions;
    }
}
+2 −0
Original line number Diff line number Diff line
@@ -130,6 +130,8 @@
            android:layout_alignParentBottom="true"

            android:targetDrawables="@array/lockscreen_targets_with_camera"
            android:targetDescriptions="@array/lockscreen_target_descriptions_with_camera"
            android:directionDescriptions="@array/lockscreen_direction_descriptions_with_camera"
            android:handleDrawable="@drawable/ic_lockscreen_handle"
            android:waveDrawable="@drawable/ic_lockscreen_outerring"
            android:outerRadius="@dimen/multiwaveview_target_placement_radius"
+2 −0
Original line number Diff line number Diff line
@@ -135,6 +135,8 @@
        android:layout_rowSpan="7"

        android:targetDrawables="@array/lockscreen_targets_with_camera"
        android:targetDescriptions="@array/lockscreen_target_descriptions_with_camera"
        android:directionDescriptions="@array/lockscreen_direction_descriptions_with_camera"
        android:handleDrawable="@drawable/ic_lockscreen_handle"
        android:waveDrawable="@drawable/ic_lockscreen_outerring"
        android:outerRadius="@dimen/multiwaveview_target_placement_radius"
+43 −1
Original line number Diff line number Diff line
@@ -27,13 +27,41 @@
        <item>@drawable/ic_lockscreen_soundon</item>
    </array>

    <array name="lockscreen_target_descriptions_when_silent">
        <item>@null</item>
        <item>@string/description_target_unlock</item>
        <item>@null</item>
        <item>@string/description_target_soundon</item>
    </array>

    <array name="lockscreen_direction_descriptions_when_silent">
        <item>@null</item>
        <item>@string/description_direction_up</item>
        <item>@null</item>
        <item>@string/description_direction_down</item>
    </array>

    <array name="lockscreen_targets_when_soundon">
        <item>@null</item>"
        <item>@null</item>
        <item>@drawable/ic_lockscreen_unlock</item>
        <item>@null</item>
        <item>@drawable/ic_lockscreen_silent</item>
    </array>

    <array name="lockscreen_target_descriptions_when_soundon">
        <item>@null</item>
        <item>@string/description_target_unlock</item>
        <item>@null</item>
        <item>@string/description_target_silent</item>
    </array>

    <array name="lockscreen_direction_descriptions_when_soundon">
        <item>@null</item>
        <item>@string/description_direction_up</item>
        <item>@null</item>
        <item>@string/description_direction_down</item>
    </array>

    <array name="lockscreen_targets_with_camera">
        <item>@null</item>
        <item>@drawable/ic_lockscreen_unlock</item>
@@ -41,4 +69,18 @@
        <item>@drawable/ic_lockscreen_camera</item>
    </array>

    <array name="lockscreen_target_descriptions_with_camera">
        <item>@null</item>
        <item>@string/description_target_unlock</item>
        <item>@null</item>
        <item>@string/description_target_camera</item>
    </array>

    <array name="lockscreen_direction_descriptions_with_camera">
        <item>@null</item>
        <item>@string/description_direction_up</item>
        <item>@null</item>
        <item>@string/description_direction_down</item>
    </array>

</resources>
Loading