From e78e3d734b577c1ab6dc0738a83600374908ea52 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Thu, 24 Sep 2015 11:23:31 -0700 Subject: Accessibility fixes 1) Use a different content description for temporary new page 2) Use different accessibility description for add widget toast 3) Announce when an item is deleted 4) Announce when hovering over a drop target 5) Announce state during drag-n-drop and widget resize (similar to seekbar) Bug: 23573321, 24057944 Change-Id: Icabb317625e70c78e11c0b4f99b9339172d93594 --- res/values/strings.xml | 4 ++ .../android/launcher3/AppWidgetResizeFrame.java | 12 ++++ src/com/android/launcher3/ButtonDropTarget.java | 2 + src/com/android/launcher3/CellLayout.java | 17 ++++- src/com/android/launcher3/DeleteDropTarget.java | 6 +- src/com/android/launcher3/DragController.java | 11 ++-- src/com/android/launcher3/DropTarget.java | 4 ++ src/com/android/launcher3/Folder.java | 5 ++ src/com/android/launcher3/Utilities.java | 21 ++++++ src/com/android/launcher3/Workspace.java | 77 +++++++++++++--------- .../accessibility/DragViewStateAnnouncer.java | 57 ++++++++++++++++ .../LauncherAccessibilityDelegate.java | 7 +- .../WorkspaceAccessibilityHelper.java | 37 ++++++----- .../launcher3/widget/WidgetsContainerView.java | 8 ++- 14 files changed, 204 insertions(+), 64 deletions(-) create mode 100644 src/com/android/launcher3/accessibility/DragViewStateAnnouncer.java diff --git a/res/values/strings.xml b/res/values/strings.xml index fefadef28..f93b363cc 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -50,6 +50,8 @@ Touch & hold to pick up a widget. + + Double-tap & hold to pick up a widget or use custom actions. %1$d \u00d7 %2$d @@ -125,6 +127,8 @@ Page %1$d of %2$d Home screen %1$d of %2$d + + New home screen page diff --git a/src/com/android/launcher3/AppWidgetResizeFrame.java b/src/com/android/launcher3/AppWidgetResizeFrame.java index e6bf52531..d86853608 100644 --- a/src/com/android/launcher3/AppWidgetResizeFrame.java +++ b/src/com/android/launcher3/AppWidgetResizeFrame.java @@ -14,6 +14,8 @@ import android.view.Gravity; import android.widget.FrameLayout; import android.widget.ImageView; +import com.android.launcher3.accessibility.DragViewStateAnnouncer; + public class AppWidgetResizeFrame extends FrameLayout { private static final int SNAP_DURATION = 150; private static final float DIMMED_HANDLE_ALPHA = 0f; @@ -40,6 +42,8 @@ public class AppWidgetResizeFrame extends FrameLayout { private final int[] mLastDirectionVector = new int[2]; private final int[] mTmpPt = new int[2]; + private final DragViewStateAnnouncer mStateAnnouncer; + private boolean mLeftBorderActive; private boolean mRightBorderActive; private boolean mTopBorderActive; @@ -78,6 +82,8 @@ public class AppWidgetResizeFrame extends FrameLayout { mMinHSpan = info.minSpanX; mMinVSpan = info.minSpanY; + mStateAnnouncer = DragViewStateAnnouncer.createFor(this); + setBackgroundResource(R.drawable.widget_resize_shadow); setForeground(getResources().getDrawable(R.drawable.widget_resize_frame)); setPadding(0, 0, 0, 0); @@ -320,12 +326,18 @@ public class AppWidgetResizeFrame extends FrameLayout { if (mCellLayout.createAreaForResize(cellX, cellY, spanX, spanY, mWidgetView, mDirectionVector, onDismiss)) { + if (mStateAnnouncer != null && (lp.cellHSpan != spanX || lp.cellVSpan != spanY) ) { + mStateAnnouncer.announce( + mLauncher.getString(R.string.widget_resized, spanX, spanY)); + } + lp.tmpCellX = cellX; lp.tmpCellY = cellY; lp.cellHSpan = spanX; lp.cellVSpan = spanY; mRunningVInc += vSpanDelta; mRunningHInc += hSpanDelta; + if (!onDismiss) { updateWidgetSizeRanges(mWidgetView, mLauncher, spanX, spanY); } diff --git a/src/com/android/launcher3/ButtonDropTarget.java b/src/com/android/launcher3/ButtonDropTarget.java index 2baa6d8ee..9caa7ad87 100644 --- a/src/com/android/launcher3/ButtonDropTarget.java +++ b/src/com/android/launcher3/ButtonDropTarget.java @@ -34,6 +34,7 @@ import android.util.AttributeSet; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; +import android.view.accessibility.AccessibilityEvent; import android.view.animation.DecelerateInterpolator; import android.view.animation.LinearInterpolator; import android.widget.TextView; @@ -123,6 +124,7 @@ public abstract class ButtonDropTarget extends TextView mDrawable.setColorFilter(new ColorMatrixColorFilter(mCurrentFilter)); setTextColor(mHoverColor); } + sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED); } @Override diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java index d48873762..5ae7310ff 100644 --- a/src/com/android/launcher3/CellLayout.java +++ b/src/com/android/launcher3/CellLayout.java @@ -1021,7 +1021,7 @@ public class CellLayout extends ViewGroup implements BubbleTextShadowHandler { } void visualizeDropLocation(View v, Bitmap dragOutline, int originX, int originY, int cellX, - int cellY, int spanX, int spanY, boolean resize, Point dragOffset, Rect dragRegion) { + int cellY, int spanX, int spanY, boolean resize, DropTarget.DragObject dragObject) { final int oldDragCellX = mDragCell[0]; final int oldDragCellY = mDragCell[1]; @@ -1030,6 +1030,9 @@ public class CellLayout extends ViewGroup implements BubbleTextShadowHandler { } if (cellX != oldDragCellX || cellY != oldDragCellY) { + Point dragOffset = dragObject.dragView.getDragVisualizeOffset(); + Rect dragRegion = dragObject.dragView.getDragRegion(); + mDragCell[0] = cellX; mDragCell[1] = cellY; // Find the top left corner of the rect the object will occupy @@ -1081,6 +1084,18 @@ public class CellLayout extends ViewGroup implements BubbleTextShadowHandler { mDragOutlineAnims[mDragOutlineCurrent].setTag(dragOutline); mDragOutlineAnims[mDragOutlineCurrent].animateIn(); + + if (dragObject.stateAnnouncer != null) { + String msg; + if (isHotseat()) { + msg = getContext().getString(R.string.move_to_hotseat_position, + Math.max(cellX, cellY) + 1); + } else { + msg = getContext().getString(R.string.move_to_empty_cell, + cellY + 1, cellX + 1); + } + dragObject.stateAnnouncer.announce(msg); + } } } diff --git a/src/com/android/launcher3/DeleteDropTarget.java b/src/com/android/launcher3/DeleteDropTarget.java index 5b1e84efb..2a0e203e6 100644 --- a/src/com/android/launcher3/DeleteDropTarget.java +++ b/src/com/android/launcher3/DeleteDropTarget.java @@ -19,7 +19,6 @@ package com.android.launcher3; import android.animation.TimeInterpolator; import android.content.Context; import android.graphics.PointF; -import android.os.AsyncTask; import android.util.AttributeSet; import android.view.View; import android.view.animation.AnimationUtils; @@ -67,15 +66,14 @@ public class DeleteDropTarget extends ButtonDropTarget { /** * Removes the item from the workspace. If the view is not null, it also removes the view. - * @return true if the item was removed. */ - public static boolean removeWorkspaceOrFolderItem(Launcher launcher, ItemInfo item, View view) { + public static void removeWorkspaceOrFolderItem(Launcher launcher, ItemInfo item, View view) { // Remove the item from launcher and the db, we can ignore the containerInfo in this call // because we already remove the drag view from the folder (if the drag originated from // a folder) in Folder.beginDrag() launcher.removeItem(view, item, true /* deleteFromDb */); launcher.getWorkspace().stripEmptyScreens(); - return true; + launcher.getDragLayer().announceForAccessibility(launcher.getString(R.string.item_removed)); } @Override diff --git a/src/com/android/launcher3/DragController.java b/src/com/android/launcher3/DragController.java index 2191455d5..204dddfdf 100644 --- a/src/com/android/launcher3/DragController.java +++ b/src/com/android/launcher3/DragController.java @@ -32,8 +32,10 @@ import android.view.MotionEvent; import android.view.VelocityTracker; import android.view.View; import android.view.ViewConfiguration; +import android.view.accessibility.AccessibilityManager; import android.view.inputmethod.InputMethodManager; +import com.android.launcher3.accessibility.DragViewStateAnnouncer; import com.android.launcher3.util.Thunk; import java.util.ArrayList; @@ -145,8 +147,6 @@ public class DragController { /** * Used to create a new DragLayer from XML. - * - * @param context The application's context. */ public DragController(Launcher launcher) { Resources r = launcher.getResources(); @@ -239,6 +239,9 @@ public class DragController { mDragObject = new DropTarget.DragObject(); + final DragView dragView = mDragObject.dragView = new DragView(mLauncher, b, registrationX, + registrationY, 0, 0, b.getWidth(), b.getHeight(), initialDragViewScale); + mDragObject.dragComplete = false; if (mIsAccessibleDrag) { // For an accessible drag, we assume the view is being dragged from the center. @@ -248,14 +251,12 @@ public class DragController { } else { mDragObject.xOffset = mMotionDownX - (dragLayerX + dragRegionLeft); mDragObject.yOffset = mMotionDownY - (dragLayerY + dragRegionTop); + mDragObject.stateAnnouncer = DragViewStateAnnouncer.createFor(dragView); } mDragObject.dragSource = source; mDragObject.dragInfo = dragInfo; - final DragView dragView = mDragObject.dragView = new DragView(mLauncher, b, registrationX, - registrationY, 0, 0, b.getWidth(), b.getHeight(), initialDragViewScale); - if (dragOffset != null) { dragView.setDragVisualizeOffset(new Point(dragOffset)); } diff --git a/src/com/android/launcher3/DropTarget.java b/src/com/android/launcher3/DropTarget.java index c8fac5466..434059168 100644 --- a/src/com/android/launcher3/DropTarget.java +++ b/src/com/android/launcher3/DropTarget.java @@ -19,6 +19,8 @@ package com.android.launcher3; import android.graphics.PointF; import android.graphics.Rect; +import com.android.launcher3.accessibility.DragViewStateAnnouncer; + /** * Interface defining an object that can receive a drag. * @@ -64,6 +66,8 @@ public interface DropTarget { /** Defers removing the DragView from the DragLayer until after the drop animation. */ public boolean deferDragViewCleanupPostAnimation = true; + public DragViewStateAnnouncer stateAnnouncer; + public DragObject() { } diff --git a/src/com/android/launcher3/Folder.java b/src/com/android/launcher3/Folder.java index 58efaaa9d..1499a2736 100644 --- a/src/com/android/launcher3/Folder.java +++ b/src/com/android/launcher3/Folder.java @@ -706,6 +706,11 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList mReorderAlarm.setOnAlarmListener(mReorderAlarmListener); mReorderAlarm.setAlarm(REORDER_DELAY); mPrevTargetRank = mTargetRank; + + if (d.stateAnnouncer != null) { + d.stateAnnouncer.announce(getContext().getString(R.string.move_to_position, + mTargetRank + 1)); + } } float x = r[0]; diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java index acc809089..d5b28985c 100644 --- a/src/com/android/launcher3/Utilities.java +++ b/src/com/android/launcher3/Utilities.java @@ -47,7 +47,10 @@ import android.graphics.drawable.PaintDrawable; import android.os.Build; import android.os.Bundle; import android.os.Process; +import android.text.Spannable; +import android.text.SpannableString; import android.text.TextUtils; +import android.text.style.TtsSpan; import android.util.DisplayMetrics; import android.util.Log; import android.util.Pair; @@ -726,4 +729,22 @@ public final class Utilities { public static String createDbSelectionQuery(String columnName, Iterable values) { return String.format(Locale.ENGLISH, "%s IN (%s)", columnName, TextUtils.join(", ", values)); } + + /** + * Wraps a message with a TTS span, so that a different message is spoken than + * what is getting displayed. + * @param msg original message + * @param ttsMsg message to be spoken + */ + @TargetApi(Build.VERSION_CODES.LOLLIPOP) + public static CharSequence wrapForTts(CharSequence msg, String ttsMsg) { + if (Utilities.ATLEAST_LOLLIPOP) { + SpannableString spanned = new SpannableString(msg); + spanned.setSpan(new TtsSpan.TextBuilder(ttsMsg).build(), + 0, spanned.length(), Spannable.SPAN_INCLUSIVE_INCLUSIVE); + return spanned; + } else { + return msg; + } + } } diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java index ee2382609..b63ddbaa7 100644 --- a/src/com/android/launcher3/Workspace.java +++ b/src/com/android/launcher3/Workspace.java @@ -67,6 +67,7 @@ import com.android.launcher3.UninstallDropTarget.UninstallSource; import com.android.launcher3.accessibility.LauncherAccessibilityDelegate; import com.android.launcher3.accessibility.LauncherAccessibilityDelegate.AccessibilityDragSource; import com.android.launcher3.accessibility.OverviewScreenAccessibilityDelegate; +import com.android.launcher3.accessibility.WorkspaceAccessibilityHelper; import com.android.launcher3.compat.UserHandleCompat; import com.android.launcher3.util.LongArrayMap; import com.android.launcher3.util.Thunk; @@ -2024,7 +2025,7 @@ public class Workspace extends PagedView } setImportantForAccessibility((mState == State.NORMAL || mState == State.OVERVIEW) ? IMPORTANT_FOR_ACCESSIBILITY_AUTO - : IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS); + : IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS); } else { int accessible = mState == State.NORMAL ? IMPORTANT_FOR_ACCESSIBILITY_AUTO : @@ -2473,11 +2474,14 @@ public class Workspace extends PagedView return true; } - boolean willCreateUserFolder(ItemInfo info, CellLayout target, int[] targetCell, float - distance, boolean considerTimeout) { + boolean willCreateUserFolder(ItemInfo info, CellLayout target, int[] targetCell, + float distance, boolean considerTimeout) { if (distance > mMaxDistanceForFolderCreation) return false; View dropOverView = target.getChildAt(targetCell[0], targetCell[1]); + return willCreateUserFolder(info, dropOverView, considerTimeout); + } + boolean willCreateUserFolder(ItemInfo info, View dropOverView, boolean considerTimeout) { if (dropOverView != null) { CellLayout.LayoutParams lp = (CellLayout.LayoutParams) dropOverView.getLayoutParams(); if (lp.useTmpCoords && (lp.tmpCellX != lp.cellX || lp.tmpCellY != lp.tmpCellY)) { @@ -2497,7 +2501,7 @@ public class Workspace extends PagedView boolean aboveShortcut = (dropOverView.getTag() instanceof ShortcutInfo); boolean willBecomeShortcut = (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION || - info.itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT); + info.itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT); return (aboveShortcut && willBecomeShortcut); } @@ -2506,7 +2510,10 @@ public class Workspace extends PagedView float distance) { if (distance > mMaxDistanceForFolderCreation) return false; View dropOverView = target.getChildAt(targetCell[0], targetCell[1]); + return willAddToExistingUserFolder(dragInfo, dropOverView); + } + boolean willAddToExistingUserFolder(Object dragInfo, View dropOverView) { if (dropOverView != null) { CellLayout.LayoutParams lp = (CellLayout.LayoutParams) dropOverView.getLayoutParams(); if (lp.useTmpCoords && (lp.tmpCellX != lp.cellX || lp.tmpCellY != lp.tmpCellY)) { @@ -3209,8 +3216,6 @@ public class Workspace extends PagedView mapPointFromSelfToChild(mDragTargetLayout, mDragViewVisualCenter, null); } - ItemInfo info = (ItemInfo) d.dragInfo; - int minSpanX = item.spanX; int minSpanY = item.spanY; if (item.minSpanX > 0 && item.minSpanY > 0) { @@ -3229,11 +3234,7 @@ public class Workspace extends PagedView float targetCellDistance = mDragTargetLayout.getDistanceFromCell( mDragViewVisualCenter[0], mDragViewVisualCenter[1], mTargetCell); - final View dragOverView = mDragTargetLayout.getChildAt(mTargetCell[0], - mTargetCell[1]); - - manageFolderFeedback(info, mDragTargetLayout, mTargetCell, - targetCellDistance, dragOverView, d.accessibleDrag); + manageFolderFeedback(mDragTargetLayout, mTargetCell, targetCellDistance, d); boolean nearestDropOccupied = mDragTargetLayout.isNearestDropLocationOccupied((int) mDragViewVisualCenter[0], (int) mDragViewVisualCenter[1], item.spanX, @@ -3242,8 +3243,7 @@ public class Workspace extends PagedView if (!nearestDropOccupied) { mDragTargetLayout.visualizeDropLocation(child, mDragOutline, (int) mDragViewVisualCenter[0], (int) mDragViewVisualCenter[1], - mTargetCell[0], mTargetCell[1], item.spanX, item.spanY, false, - d.dragView.getDragVisualizeOffset(), d.dragView.getDragRegion()); + mTargetCell[0], mTargetCell[1], item.spanX, item.spanY, false, d); } else if ((mDragMode == DRAG_MODE_NONE || mDragMode == DRAG_MODE_REORDER) && !mReorderAlarm.alarmPending() && (mLastReorderX != reorderX || mLastReorderY != reorderY)) { @@ -3256,7 +3256,7 @@ public class Workspace extends PagedView // Otherwise, if we aren't adding to or creating a folder and there's no pending // reorder, then we schedule a reorder ReorderAlarmListener listener = new ReorderAlarmListener(mDragViewVisualCenter, - minSpanX, minSpanY, item.spanX, item.spanY, d.dragView, child); + minSpanX, minSpanY, item.spanX, item.spanY, d, child); mReorderAlarm.setOnAlarmListener(listener); mReorderAlarm.setAlarm(REORDER_TIMEOUT); } @@ -3270,28 +3270,34 @@ public class Workspace extends PagedView } } - private void manageFolderFeedback(ItemInfo info, CellLayout targetLayout, - int[] targetCell, float distance, View dragOverView, boolean accessibleDrag) { - boolean userFolderPending = willCreateUserFolder(info, targetLayout, targetCell, distance, - false); + private void manageFolderFeedback(CellLayout targetLayout, + int[] targetCell, float distance, DragObject dragObject) { + if (distance > mMaxDistanceForFolderCreation) return; + + final View dragOverView = mDragTargetLayout.getChildAt(mTargetCell[0], mTargetCell[1]); + ItemInfo info = (ItemInfo) dragObject.dragInfo; + boolean userFolderPending = willCreateUserFolder(info, dragOverView, false); if (mDragMode == DRAG_MODE_NONE && userFolderPending && !mFolderCreationAlarm.alarmPending()) { FolderCreationAlarmListener listener = new FolderCreationAlarmListener(targetLayout, targetCell[0], targetCell[1]); - if (!accessibleDrag) { + if (!dragObject.accessibleDrag) { mFolderCreationAlarm.setOnAlarmListener(listener); mFolderCreationAlarm.setAlarm(FOLDER_CREATION_TIMEOUT); } else { listener.onAlarm(mFolderCreationAlarm); } + + if (dragObject.stateAnnouncer != null) { + dragObject.stateAnnouncer.announce(WorkspaceAccessibilityHelper + .getDescriptionForDropOver(dragOverView, getContext())); + } return; } - boolean willAddToFolder = - willAddToExistingUserFolder(info, targetLayout, targetCell, distance); - + boolean willAddToFolder = willAddToExistingUserFolder(info, dragOverView); if (willAddToFolder && mDragMode == DRAG_MODE_NONE) { mDragOverFolderIcon = ((FolderIcon) dragOverView); mDragOverFolderIcon.onDragEnter(info); @@ -3299,6 +3305,11 @@ public class Workspace extends PagedView targetLayout.clearDragOutlines(); } setDragMode(DRAG_MODE_ADD_TO_FOLDER); + + if (dragObject.stateAnnouncer != null) { + dragObject.stateAnnouncer.announce(WorkspaceAccessibilityHelper + .getDescriptionForDropOver(dragOverView, getContext())); + } return; } @@ -3308,8 +3319,6 @@ public class Workspace extends PagedView if (mDragMode == DRAG_MODE_CREATE_FOLDER && !userFolderPending) { setDragMode(DRAG_MODE_NONE); } - - return; } class FolderCreationAlarmListener implements OnAlarmListener { @@ -3341,18 +3350,18 @@ public class Workspace extends PagedView class ReorderAlarmListener implements OnAlarmListener { float[] dragViewCenter; int minSpanX, minSpanY, spanX, spanY; - DragView dragView; + DragObject dragObject; View child; public ReorderAlarmListener(float[] dragViewCenter, int minSpanX, int minSpanY, int spanX, - int spanY, DragView dragView, View child) { + int spanY, DragObject dragObject, View child) { this.dragViewCenter = dragViewCenter; this.minSpanX = minSpanX; this.minSpanY = minSpanY; this.spanX = spanX; this.spanY = spanY; this.child = child; - this.dragView = dragView; + this.dragObject = dragObject; } public void onAlarm(Alarm alarm) { @@ -3376,8 +3385,7 @@ public class Workspace extends PagedView boolean resize = resultSpan[0] != spanX || resultSpan[1] != spanY; mDragTargetLayout.visualizeDropLocation(child, mDragOutline, (int) mDragViewVisualCenter[0], (int) mDragViewVisualCenter[1], - mTargetCell[0], mTargetCell[1], resultSpan[0], resultSpan[1], resize, - dragView.getDragVisualizeOffset(), dragView.getDragRegion()); + mTargetCell[0], mTargetCell[1], resultSpan[0], resultSpan[1], resize, dragObject); } } @@ -4472,8 +4480,17 @@ public class Workspace extends PagedView private String getPageDescription(int page) { int delta = numCustomPages(); + int nScreens = getChildCount() - delta; + int extraScreenId = mScreenOrder.indexOf(EXTRA_EMPTY_SCREEN_ID); + if (extraScreenId >= 0 && nScreens > 1) { + if (page == extraScreenId) { + return getContext().getString(R.string.workspace_new_page); + } + nScreens--; + } return String.format(getContext().getString(R.string.workspace_scroll_format), - page + 1 - delta, getChildCount() - delta); + page + 1 - delta, nScreens); + } public void getLocationInDragLayer(int[] loc) { diff --git a/src/com/android/launcher3/accessibility/DragViewStateAnnouncer.java b/src/com/android/launcher3/accessibility/DragViewStateAnnouncer.java new file mode 100644 index 000000000..b5e6194a0 --- /dev/null +++ b/src/com/android/launcher3/accessibility/DragViewStateAnnouncer.java @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.launcher3.accessibility; + +import android.content.Context; +import android.view.View; +import android.view.accessibility.AccessibilityEvent; +import android.view.accessibility.AccessibilityManager; + +/** + * Periodically sends accessibility events to announce ongoing state changed. Based on the + * implementation in ProgressBar. + */ +public class DragViewStateAnnouncer implements Runnable { + + private static final int TIMEOUT_SEND_ACCESSIBILITY_EVENT = 200; + + private final View mTargetView; + + private DragViewStateAnnouncer(View view) { + mTargetView = view; + } + + public void announce(CharSequence msg) { + mTargetView.setContentDescription(msg); + mTargetView.removeCallbacks(this); + mTargetView.postDelayed(this, TIMEOUT_SEND_ACCESSIBILITY_EVENT); + } + + @Override + public void run() { + mTargetView.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED); + } + + public static DragViewStateAnnouncer createFor(View v) { + if (((AccessibilityManager) v.getContext().getSystemService(Context.ACCESSIBILITY_SERVICE)) + .isEnabled()) { + return new DragViewStateAnnouncer(v); + } else { + return null; + } + } +} diff --git a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java index fe7b25edd..2233ebb7a 100644 --- a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java +++ b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java @@ -134,11 +134,8 @@ public class LauncherAccessibilityDelegate extends AccessibilityDelegate impleme public boolean performAction(final View host, final ItemInfo item, int action) { if (action == REMOVE) { - if (DeleteDropTarget.removeWorkspaceOrFolderItem(mLauncher, item, host)) { - announceConfirmation(R.string.item_removed); - return true; - } - return false; + DeleteDropTarget.removeWorkspaceOrFolderItem(mLauncher, item, host); + return true; } else if (action == INFO) { InfoDropTarget.startDetailsActivityForInfo(item, mLauncher); return true; diff --git a/src/com/android/launcher3/accessibility/WorkspaceAccessibilityHelper.java b/src/com/android/launcher3/accessibility/WorkspaceAccessibilityHelper.java index 80ddc13b7..73b824bb5 100644 --- a/src/com/android/launcher3/accessibility/WorkspaceAccessibilityHelper.java +++ b/src/com/android/launcher3/accessibility/WorkspaceAccessibilityHelper.java @@ -16,6 +16,7 @@ package com.android.launcher3.accessibility; +import android.content.Context; import android.text.TextUtils; import android.view.View; @@ -140,26 +141,30 @@ public class WorkspaceAccessibilityHelper extends DragAndDropAccessibilityDelega return mContext.getString(R.string.move_to_empty_cell, y + 1, x + 1); } } else { - ItemInfo info = (ItemInfo) child.getTag(); - if (info instanceof ShortcutInfo) { - return mContext.getString(R.string.create_folder_with, info.title); - } else if (info instanceof FolderInfo) { - if (TextUtils.isEmpty(info.title)) { - // Find the first item in the folder. - FolderInfo folder = (FolderInfo) info; - ShortcutInfo firstItem = null; - for (ShortcutInfo shortcut : folder.contents) { - if (firstItem == null || firstItem.rank > shortcut.rank) { - firstItem = shortcut; - } - } + return getDescriptionForDropOver(child, mContext); + } + } - if (firstItem != null) { - return mContext.getString(R.string.add_to_folder_with_app, firstItem.title); + public static String getDescriptionForDropOver(View overChild, Context context) { + ItemInfo info = (ItemInfo) overChild.getTag(); + if (info instanceof ShortcutInfo) { + return context.getString(R.string.create_folder_with, info.title); + } else if (info instanceof FolderInfo) { + if (TextUtils.isEmpty(info.title)) { + // Find the first item in the folder. + FolderInfo folder = (FolderInfo) info; + ShortcutInfo firstItem = null; + for (ShortcutInfo shortcut : folder.contents) { + if (firstItem == null || firstItem.rank > shortcut.rank) { + firstItem = shortcut; } } - return mContext.getString(R.string.add_to_folder, info.title); + + if (firstItem != null) { + return context.getString(R.string.add_to_folder_with_app, firstItem.title); + } } + return context.getString(R.string.add_to_folder, info.title); } return ""; } diff --git a/src/com/android/launcher3/widget/WidgetsContainerView.java b/src/com/android/launcher3/widget/WidgetsContainerView.java index 0c6ea31bb..64d33aa09 100644 --- a/src/com/android/launcher3/widget/WidgetsContainerView.java +++ b/src/com/android/launcher3/widget/WidgetsContainerView.java @@ -148,8 +148,11 @@ public class WidgetsContainerView extends BaseContainerView if (mWidgetInstructionToast != null) { mWidgetInstructionToast.cancel(); } - mWidgetInstructionToast = Toast.makeText(getContext(),R.string.long_press_widget_to_add, - Toast.LENGTH_SHORT); + + CharSequence msg = Utilities.wrapForTts( + getContext().getText(R.string.long_press_widget_to_add), + getContext().getString(R.string.long_accessible_way_to_add)); + mWidgetInstructionToast = Toast.makeText(getContext(), msg, Toast.LENGTH_SHORT); mWidgetInstructionToast.show(); } @@ -164,7 +167,6 @@ public class WidgetsContainerView extends BaseContainerView if (!mLauncher.isWidgetsViewVisible() || mLauncher.getWorkspace().isSwitchingState()) return false; // Return if global dragging is not enabled - Log.d(TAG, String.format("onLonglick dragging enabled?.", v)); if (!mLauncher.isDraggingEnabled()) return false; boolean status = beginDragging(v); -- cgit v1.2.3