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
This commit is contained in:
Sunny Goyal 2015-09-24 11:23:31 -07:00
parent 2949fb5b16
commit e78e3d734b
14 changed files with 204 additions and 64 deletions

View File

@ -50,6 +50,8 @@
<!-- Widgets -->
<!-- Message to tell the user to press and hold on a widget to add it [CHAR_LIMIT=50] -->
<string name="long_press_widget_to_add">Touch &amp; hold to pick up a widget.</string>
<!-- Accessibility spoken hint message in widget picker, which allows user to add a widget. Custom action is the label for additional accessibility actions available in this mode [CHAR_LIMIT=100] -->
<string name="long_accessible_way_to_add">Double-tap &amp; hold to pick up a widget or use custom actions.</string>
<!-- The format string for the dimensions of a widget in the drawer -->
<!-- There is a special version of this format string for Farsi -->
<string name="widget_dims_format">%1$d \u00d7 %2$d</string>
@ -125,6 +127,8 @@
<string name="default_scroll_format">Page %1$d of %2$d</string>
<!-- The format string for Workspace page scroll text [CHAR_LIMIT=none] -->
<string name="workspace_scroll_format">Home screen %1$d of %2$d</string>
<!-- Description for a new page on homescreen[CHAR_LIMIT=none] -->
<string name="workspace_new_page">New home screen page</string>
<!-- Clings -->
<!-- The title text for the workspace cling [CHAR_LIMIT=30] -->

View File

@ -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);
}

View File

@ -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

View File

@ -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);
}
}
}

View File

@ -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

View File

@ -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));
}

View File

@ -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() {
}

View File

@ -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];

View File

@ -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;
}
}
}

View File

@ -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) {

View File

@ -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;
}
}
}

View File

@ -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;

View File

@ -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 "";
}

View File

@ -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);