From 1e0585f3f789e4ea28f31352eced59c73cf8b373 Mon Sep 17 00:00:00 2001 From: Yorke Lee Date: Wed, 24 Jun 2015 17:07:47 -0700 Subject: Make switch access work for incoming call screen An accessibility click on the glowpad now exposes the touch targets as virtual views to accessibility services. Performing an accessibility click on each virtual view performs the same function as swiping towards that target. Mark contact photo as unimportant for accessibility, it doesn't provide any useful context or functionality. Bug: 19075527 Change-Id: I2e980394175bf77379f5cb99126dd5970e0f0555 --- InCallUI/res/layout/call_card_fragment.xml | 2 +- .../incallui/widget/multiwaveview/GlowPadView.java | 115 +++++++++++++++++++++ .../widget/multiwaveview/TargetDrawable.java | 13 +++ 3 files changed, 129 insertions(+), 1 deletion(-) diff --git a/InCallUI/res/layout/call_card_fragment.xml b/InCallUI/res/layout/call_card_fragment.xml index 537eb5119..dabba7662 100644 --- a/InCallUI/res/layout/call_card_fragment.xml +++ b/InCallUI/res/layout/call_card_fragment.xml @@ -74,7 +74,7 @@ android:layout_gravity="center_vertical" android:gravity="top|center_horizontal" android:scaleType="centerCrop" - android:contentDescription="@string/contactPhoto" + android:importantForAccessibility="no" android:background="@android:color/white" android:src="@drawable/img_no_image_automirrored" /> diff --git a/InCallUI/src/com/android/incallui/widget/multiwaveview/GlowPadView.java b/InCallUI/src/com/android/incallui/widget/multiwaveview/GlowPadView.java index 4bd27db9c..23200279e 100644 --- a/InCallUI/src/com/android/incallui/widget/multiwaveview/GlowPadView.java +++ b/InCallUI/src/com/android/incallui/widget/multiwaveview/GlowPadView.java @@ -29,9 +29,14 @@ import android.content.pm.PackageManager.NameNotFoundException; import android.content.res.Resources; import android.content.res.TypedArray; import android.graphics.Canvas; +import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.os.Vibrator; +import android.support.v4.view.ViewCompat; +import android.support.v4.view.accessibility.AccessibilityEventCompat; +import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat; +import android.support.v4.widget.ExploreByTouchHelper; import android.text.TextUtils; import android.util.AttributeSet; import android.util.Log; @@ -39,11 +44,16 @@ import android.util.TypedValue; import android.view.Gravity; import android.view.MotionEvent; import android.view.View; +import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityManager; +import android.view.accessibility.AccessibilityNodeInfo; +import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction; +import android.view.accessibility.AccessibilityNodeProvider; import com.android.incallui.R; import java.util.ArrayList; +import java.util.List; /** * This is a copy of com.android.internal.widget.multiwaveview.GlowPadView with minor changes @@ -124,6 +134,9 @@ public class GlowPadView extends View { private boolean mDragging; private int mNewTargetResources; + private AccessibilityNodeProvider mAccessibilityNodeProvider; + private GlowpadExploreByTouchHelper mExploreByTouchHelper; + private class AnimationBundle extends ArrayList { private static final long serialVersionUID = 0xA84D78726F127468L; private boolean mSuspended; @@ -274,6 +287,9 @@ public class GlowPadView extends View { mPointCloud = new PointCloud(pointDrawable); mPointCloud.makePointCloud(mInnerRadius, mOuterRadius); mPointCloud.glowManager.setRadius(mGlowRadius); + + mExploreByTouchHelper = new GlowpadExploreByTouchHelper(this); + ViewCompat.setAccessibilityDelegate(this, mExploreByTouchHelper); } private int getResourceId(TypedArray a, int id) { @@ -1355,4 +1371,103 @@ public class GlowPadView extends View { } return replaced; } + + public class GlowpadExploreByTouchHelper extends ExploreByTouchHelper { + + private Rect mBounds = new Rect(); + + public GlowpadExploreByTouchHelper(View forView) { + super(forView); + } + + @Override + protected int getVirtualViewAt(float x, float y) { + if (mGrabbedState == OnTriggerListener.CENTER_HANDLE) { + for (int i = 0; i < mTargetDrawables.size(); i++) { + final TargetDrawable target = mTargetDrawables.get(i); + if (target.isEnabled() && target.getBounds().contains((int) x, (int) y)) { + return i; + } + } + return INVALID_ID; + } else { + return HOST_ID; + } + } + + @Override + protected void getVisibleVirtualViews(List virtualViewIds) { + if (mGrabbedState == OnTriggerListener.CENTER_HANDLE) { + // Add virtual views backwards so that accessibility services like switch + // access traverse them in the correct order + for (int i = mTargetDrawables.size() - 1; i >= 0; i--) { + if (mTargetDrawables.get(i).isEnabled()) { + virtualViewIds.add(i); + } + } + } + } + + @Override + protected void onPopulateEventForVirtualView(int virtualViewId, AccessibilityEvent event) { + if (virtualViewId >= 0 && virtualViewId < mTargetDescriptions.size()) { + event.setContentDescription(mTargetDescriptions.get(virtualViewId)); + } + } + + @Override + public void onInitializeAccessibilityEvent(View host, AccessibilityEvent event) { + if (host == GlowPadView.this && event.getEventType() + == AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED) { + event.setContentChangeTypes(AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE); + } + super.onInitializeAccessibilityEvent(host, event); + } + + @Override + public void onPopulateNodeForHost(AccessibilityNodeInfoCompat node) { + if (mGrabbedState == OnTriggerListener.NO_HANDLE) { + node.setClickable(true); + node.addAction(AccessibilityNodeInfoCompat.ACTION_CLICK); + } + mBounds.set(0, 0, GlowPadView.this.getWidth(), GlowPadView.this.getHeight()); + node.setBoundsInParent(mBounds); + } + + @Override + public boolean performAccessibilityAction(View host, int action, Bundle args) { + if (mGrabbedState == OnTriggerListener.NO_HANDLE) { + // Simulate handle being grabbed to expose targets. + trySwitchToFirstTouchState(mWaveCenterX, mWaveCenterY); + invalidateRoot(); + return true; + } + return super.performAccessibilityAction(host, action, args); + } + + @Override + protected void onPopulateNodeForVirtualView(int virtualViewId, + AccessibilityNodeInfoCompat node) { + if (virtualViewId < mTargetDrawables.size()) { + final TargetDrawable target = mTargetDrawables.get(virtualViewId); + node.setBoundsInParent(target.getBounds()); + node.setClickable(true); + node.addAction(AccessibilityNodeInfoCompat.ACTION_CLICK); + node.setContentDescription(getTargetDescription(virtualViewId)); + } + } + + @Override + protected boolean onPerformActionForVirtualView(int virtualViewId, int action, + Bundle arguments) { + if (action == AccessibilityNodeInfo.ACTION_CLICK) { + if (virtualViewId >= 0 && virtualViewId < mTargetDrawables.size()) { + dispatchTriggerEvent(virtualViewId); + return true; + } + } + return false; + } + + } } diff --git a/InCallUI/src/com/android/incallui/widget/multiwaveview/TargetDrawable.java b/InCallUI/src/com/android/incallui/widget/multiwaveview/TargetDrawable.java index d83a28c11..adc5324eb 100644 --- a/InCallUI/src/com/android/incallui/widget/multiwaveview/TargetDrawable.java +++ b/InCallUI/src/com/android/incallui/widget/multiwaveview/TargetDrawable.java @@ -19,6 +19,7 @@ package com.android.incallui.widget.multiwaveview; import android.content.res.Resources; import android.graphics.Canvas; import android.graphics.ColorFilter; +import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.graphics.drawable.StateListDrawable; import android.util.Log; @@ -46,6 +47,7 @@ public class TargetDrawable { private boolean mEnabled = true; private final int mResourceId; private int mNumDrawables = 1; + private Rect mBounds; /** * This is changed from the framework version to pass in the number of drawables in the @@ -214,6 +216,17 @@ public class TargetDrawable { return mDrawable != null ? mDrawable.getIntrinsicHeight() : 0; } + public Rect getBounds() { + if (mBounds == null) { + mBounds = new Rect(); + } + mBounds.set((int) (mTranslationX + mPositionX - getWidth() * 0.5), + (int) (mTranslationY + mPositionY - getHeight() * 0.5), + (int) (mTranslationX + mPositionX + getWidth() * 0.5), + (int) (mTranslationY + mPositionY + getHeight() * 0.5)); + return mBounds; + } + public void draw(Canvas canvas) { if (mDrawable == null || !mEnabled) { return; -- cgit v1.2.3