From 53805218809cc1f93a0f1307b442df7c65a3068c Mon Sep 17 00:00:00 2001 From: Adam Cohen Date: Tue, 1 Oct 2013 10:39:23 -0700 Subject: First pass on accessibility -> issue 10801717 -> issue 11012432 -> issue 11012764 Change-Id: I9a687a39a358441afd57c0c46b57399ecbf23c36 --- src/com/android/launcher3/Launcher.java | 13 +++--- src/com/android/launcher3/PagedView.java | 55 ++++++++++++++++++----- src/com/android/launcher3/Workspace.java | 77 ++++++++++++++++++++++++++------ 3 files changed, 112 insertions(+), 33 deletions(-) diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index e3e065e03..a11c487bc 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -408,6 +408,7 @@ public class Launcher extends Activity mStats = new Stats(this); mAppWidgetManager = AppWidgetManager.getInstance(this); + mAppWidgetHost = new LauncherAppWidgetHost(this, APPWIDGET_HOST_ID); mAppWidgetHost.startListening(); @@ -421,6 +422,7 @@ public class Launcher extends Activity Environment.getExternalStorageDirectory() + "/launcher"); } + checkForLocaleChange(); setContentView(R.layout.launcher); @@ -920,8 +922,8 @@ public class Launcher extends Activity mWorkspace.getCustomContentCallbacks().onShow(); } } - mWorkspace.updateInteractionForState(); + mWorkspace.onResume(); } @Override @@ -984,14 +986,9 @@ public class Launcher extends Activity public void setScrollY(int scrollY); } - // Add a fullscreen unpadded view to the workspace to the left all other screens. - public QSBScroller addToCustomContentPage(View customContent) { - return addToCustomContentPage(customContent, null); - } - public QSBScroller addToCustomContentPage(View customContent, - CustomContentCallbacks callbacks) { - mWorkspace.addToCustomContentPage(customContent, callbacks); + CustomContentCallbacks callbacks, String description) { + mWorkspace.addToCustomContentPage(customContent, callbacks, description); return mQsbScroller; } diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java index c8e34dda1..96d8c1928 100644 --- a/src/com/android/launcher3/PagedView.java +++ b/src/com/android/launcher3/PagedView.java @@ -32,6 +32,7 @@ import android.graphics.Rect; import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; +import android.support.v4.view.accessibility.AccessibilityEventCompat; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.util.Log; @@ -334,6 +335,8 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc } protected void onAttachedToWindow() { + super.onAttachedToWindow(); + // Hook up the page indicator ViewGroup parent = (ViewGroup) getParent(); if (mPageIndicator == null && mPageIndicatorViewId > -1) { @@ -347,9 +350,19 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc } mPageIndicator.addMarkers(markers, mAllowPagedViewAnimations); + mPageIndicator.setOnClickListener(getPageIndicatorClickListener()); + mPageIndicator.setContentDescription(getPageIndicatorDescription()); } } + protected String getPageIndicatorDescription() { + return getCurrentPageDescription(); + } + + protected OnClickListener getPageIndicatorClickListener() { + return null; + } + protected void onDetachedFromWindow() { // Unhook the page indicator mPageIndicator = null; @@ -649,6 +662,28 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc } } + private void sendScrollAccessibilityEvent() { + AccessibilityManager am = + (AccessibilityManager) getContext().getSystemService(Context.ACCESSIBILITY_SERVICE); + if (am.isEnabled()) { + AccessibilityEvent ev = + AccessibilityEvent.obtain(AccessibilityEvent.TYPE_VIEW_SCROLLED); + ev.getText().add(""); + ev.setItemCount(getChildCount()); + ev.setFromIndex(mCurrentPage); + int action = AccessibilityNodeInfo.ACTION_SCROLL_FORWARD; + + if (getNextPage() >= mCurrentPage) { + action = AccessibilityNodeInfo.ACTION_SCROLL_FORWARD; + } else { + action = AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD; + } + + ev.setAction(action); + sendAccessibilityEventUnchecked(ev); + } + } + // we moved this functionality to a helper function so SmoothPagedView can reuse it protected boolean computeScrollHelper() { if (mScroller.computeScrollOffset()) { @@ -663,6 +698,8 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc invalidate(); return true; } else if (mNextPage != INVALID_PAGE) { + sendScrollAccessibilityEvent(); + mCurrentPage = Math.max(0, Math.min(mNextPage, getPageCount() - 1)); mNextPage = INVALID_PAGE; notifyPageSwitchListener(); @@ -680,14 +717,11 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc } onPostReorderingAnimationCompleted(); - // Notify the user when the page changes - AccessibilityManager accessibilityManager = (AccessibilityManager) + AccessibilityManager am = (AccessibilityManager) getContext().getSystemService(Context.ACCESSIBILITY_SERVICE); - if (accessibilityManager.isEnabled()) { - AccessibilityEvent ev = - AccessibilityEvent.obtain(AccessibilityEvent.TYPE_VIEW_SCROLLED); - ev.getText().add(getCurrentPageDescription()); - sendAccessibilityEventUnchecked(ev); + if (am.isEnabled()) { + // Notify the user when the page changes + announceForAccessibility(getCurrentPageDescription()); } return true; } @@ -2133,6 +2167,8 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc focusedChild.clearFocus(); } + sendScrollAccessibilityEvent(); + pageBeginMoving(); awakenScrollBars(duration); if (immediate) { @@ -2719,11 +2755,6 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc public void onInitializeAccessibilityEvent(AccessibilityEvent event) { super.onInitializeAccessibilityEvent(event); event.setScrollable(true); - if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_SCROLLED) { - event.setFromIndex(mCurrentPage); - event.setToIndex(mCurrentPage); - event.setItemCount(getChildCount()); - } } @Override diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java index 5a8472c01..ef918e944 100644 --- a/src/com/android/launcher3/Workspace.java +++ b/src/com/android/launcher3/Workspace.java @@ -44,6 +44,7 @@ import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.IBinder; import android.os.Parcelable; +import android.support.v4.view.ViewCompat; import android.util.AttributeSet; import android.util.Log; import android.util.SparseArray; @@ -52,6 +53,9 @@ import android.view.Display; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; +import android.view.accessibility.AccessibilityEvent; +import android.view.accessibility.AccessibilityManager; +import android.view.accessibility.AccessibilityNodeInfo; import android.view.animation.DecelerateInterpolator; import android.view.animation.Interpolator; import android.widget.TextView; @@ -113,6 +117,7 @@ public class Workspace extends SmoothPagedView private int mDefaultPage; private ShortcutAndWidgetContainer mDragSourceInternal; + private static boolean sAccessibilityEnabled; // The screen id used for the empty screen always present to the right. private final static long EXTRA_EMPTY_SCREEN_ID = -201; @@ -139,6 +144,7 @@ public class Workspace extends SmoothPagedView CustomContentCallbacks mCustomContentCallbacks; boolean mCustomContentShowing; private float mLastCustomContentScrollProgress = -1f; + private String mCustomContentDescription = ""; /** * The CellLayout that is currently being dragged over @@ -318,11 +324,7 @@ public class Workspace extends SmoothPagedView // Disable multitouch across the workspace/all apps/customize tray setMotionEventSplittingEnabled(true); - - // Unless otherwise specified this view is important for accessibility. - if (getImportantForAccessibility() == View.IMPORTANT_FOR_ACCESSIBILITY_AUTO) { - setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES); - } + setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES); } @Override @@ -450,9 +452,7 @@ public class Workspace extends SmoothPagedView CellLayout cl = ((CellLayout) child); cl.setOnInterceptTouchListener(this); cl.setClickable(true); - cl.setContentDescription(getContext().getString( - R.string.workspace_description_format, getChildCount())); - + cl.setImportantForAccessibility(ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO); super.onChildViewAdded(parent, child); } @@ -555,7 +555,8 @@ public class Workspace extends SmoothPagedView setCurrentPage(getCurrentPage() - 1); } - public void addToCustomContentPage(View customContent, CustomContentCallbacks callbacks) { + public void addToCustomContentPage(View customContent, CustomContentCallbacks callbacks, + String description) { if (getPageIndexForScreenId(CUSTOM_CONTENT_SCREEN_ID) < 0) { throw new RuntimeException("Expected custom content screen to exist"); } @@ -571,6 +572,7 @@ public class Workspace extends SmoothPagedView ((Insettable)customContent).setInsets(mInsets); } customScreen.addViewToCellLayout(customContent, 0, 0, lp, true); + mCustomContentDescription = description; mCustomContentCallbacks = callbacks; } @@ -642,7 +644,6 @@ public class Workspace extends SmoothPagedView return newId; } - public CellLayout getScreenWithId(long screenId) { CellLayout layout = mWorkspaceScreens.get(screenId); return layout; @@ -1039,6 +1040,9 @@ public class Workspace extends SmoothPagedView mLauncher.updateVoiceButtonProxyVisible(false); } } + if (getPageIndicator() != null) { + getPageIndicator().setContentDescription(getPageIndicatorDescription()); + } } protected CustomContentCallbacks getCustomContentCallbacks() { @@ -1411,6 +1415,22 @@ public class Workspace extends SmoothPagedView } } + @Override + protected OnClickListener getPageIndicatorClickListener() { + AccessibilityManager am = (AccessibilityManager) + getContext().getSystemService(Context.ACCESSIBILITY_SERVICE); + if (!am.isTouchExplorationEnabled()) { + return null; + } + OnClickListener listener = new OnClickListener() { + @Override + public void onClick(View arg0) { + enterOverviewMode(); + } + }; + return listener; + } + @Override protected void screenScrolled(int screenCenter) { final boolean isRtl = isLayoutRtl(); @@ -1475,6 +1495,17 @@ public class Workspace extends SmoothPagedView mWindowToken = null; } + protected void onResume() { + if (getPageIndicator() != null) { + // In case accessibility state has changed, we need to perform this on every + // attach to window + getPageIndicator().setOnClickListener(getPageIndicatorClickListener()); + } + AccessibilityManager am = (AccessibilityManager) + getContext().getSystemService(Context.ACCESSIBILITY_SERVICE); + sAccessibilityEnabled = am.isEnabled(); + } + @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { if (mFirstLayout && mCurrentPage >= 0 && mCurrentPage < getChildCount()) { @@ -1852,6 +1883,14 @@ public class Workspace extends SmoothPagedView private void setState(State state) { mState = state; updateInteractionForState(); + updateAccessibilityFlags(); + } + + private void updateAccessibilityFlags() { + int accessible = mState == State.NORMAL ? + ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES : + ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS; + setImportantForAccessibility(accessible); } Animator getChangeStateAnimation(final State state, boolean animated, int delay, int snapPage) { @@ -2036,8 +2075,11 @@ public class Workspace extends SmoothPagedView } public static void updateVisibility(View view) { - if (view.getAlpha() < ALPHA_CUTOFF_THRESHOLD && view.getVisibility() != INVISIBLE) { - view.setVisibility(INVISIBLE); + // We want to avoid the extra layout pass by setting the views to GONE unless + // accessibility is on, in which case not setting them to GONE causes a glitch. + int invisibleState = sAccessibilityEnabled ? GONE : INVISIBLE; + if (view.getAlpha() < ALPHA_CUTOFF_THRESHOLD && view.getVisibility() != invisibleState) { + view.setVisibility(invisibleState); } else if (view.getAlpha() > ALPHA_CUTOFF_THRESHOLD && view.getVisibility() != VISIBLE) { view.setVisibility(VISIBLE); @@ -4308,10 +4350,19 @@ public class Workspace extends SmoothPagedView public void syncPageItems(int page, boolean immediate) { } + protected String getPageIndicatorDescription() { + String settings = getResources().getString(R.string.settings_button_text); + return getCurrentPageDescription() + ", " + settings; + } + protected String getCurrentPageDescription() { int page = (mNextPage != INVALID_PAGE) ? mNextPage : mCurrentPage; + int delta = numCustomPages(); + if (hasCustomContent() && getNextPage() == 0) { + return mCustomContentDescription; + } return String.format(getContext().getString(R.string.workspace_scroll_format), - page + 1, getChildCount()); + page + 1 - delta, getChildCount() - delta); } public void getLocationInDragLayer(int[] loc) { -- cgit v1.2.3