Accessibility fixes
> Enabling top bar buttons in accessibility drag-drop > Unifying logic to show delete/uninstall/app-info targets > Announcing cell loction as 1-index instead of 0-index Change-Id: Ibc7801f77e938b2646f0655462cbe9b7f781818b
This commit is contained in:
@@ -309,13 +309,13 @@ s -->
|
||||
|
||||
<!-- Strings for accessibility actions -->
|
||||
<!-- Accessibility action to add an app to workspace. [CHAR_LIMIT=30] [DO NOT TRANSLATE] -->
|
||||
<string name="action_add_to_workspace">Add To Workspace</string>
|
||||
<string name="action_add_to_workspace">Add to workspace</string>
|
||||
|
||||
<!-- Accessibility confirmation for item added to workspace [DO NOT TRANSLATE] -->
|
||||
<string name="item_added_to_workspace">Item added to workspace</string>
|
||||
|
||||
<!-- Accessibility confirmation for item removed [DO NOT TRANSLATE] -->
|
||||
<string name="item_removed_from_workspace">Item removed from workspace</string>
|
||||
<string name="item_removed">Item removed</string>
|
||||
|
||||
<!-- Accessibility action to move an item on the workspace. [CHAR_LIMIT=30] [DO NOT TRANSLATE] -->
|
||||
<string name="action_move">Move Item</string>
|
||||
|
||||
@@ -26,18 +26,19 @@ import android.graphics.drawable.Drawable;
|
||||
import android.graphics.drawable.TransitionDrawable;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.animation.DecelerateInterpolator;
|
||||
import android.view.animation.LinearInterpolator;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.util.Thunk;
|
||||
|
||||
/**
|
||||
* Implements a DropTarget.
|
||||
*/
|
||||
public abstract class ButtonDropTarget extends TextView implements DropTarget, DragController.DragListener {
|
||||
public abstract class ButtonDropTarget extends TextView
|
||||
implements DropTarget, DragController.DragListener, OnClickListener {
|
||||
|
||||
private static int DRAG_VIEW_DROP_DURATION = 285;
|
||||
|
||||
@@ -256,4 +257,18 @@ public abstract class ButtonDropTarget extends TextView implements DropTarget, D
|
||||
public void getLocationInDragLayer(int[] loc) {
|
||||
mLauncher.getDragLayer().getLocationInDragLayer(this, loc);
|
||||
}
|
||||
|
||||
public void enableAccessibleDrag(boolean enable) {
|
||||
setOnClickListener(enable ? this : null);
|
||||
}
|
||||
|
||||
protected String getAccessibilityDropConfirmation() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
LauncherAppState.getInstance().getAccessibilityDelegate()
|
||||
.handleAccessibleDrop(this, null, getAccessibilityDropConfirmation());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -557,7 +557,7 @@ public class CellLayout extends ViewGroup {
|
||||
Resources res = getContext().getResources();
|
||||
View child = getChildAt(x, y);
|
||||
if (child == null || child == dragInfo.item) {
|
||||
return res.getString(R.string.move_to_empty_cell, x, y);
|
||||
return res.getString(R.string.move_to_empty_cell, x + 1, y + 1);
|
||||
} else {
|
||||
ItemInfo info = (ItemInfo) child.getTag();
|
||||
if (info instanceof AppInfo || info instanceof ShortcutInfo) {
|
||||
|
||||
@@ -29,7 +29,6 @@ import android.view.ViewConfiguration;
|
||||
import android.view.animation.AnimationUtils;
|
||||
import android.view.animation.DecelerateInterpolator;
|
||||
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.util.Thunk;
|
||||
import com.android.launcher3.widget.WidgetsContainerView;
|
||||
|
||||
@@ -59,13 +58,15 @@ public class DeleteDropTarget extends ButtonDropTarget {
|
||||
setDrawable(R.drawable.remove_target_selector);
|
||||
}
|
||||
|
||||
public static boolean willAcceptDrop(DragSource source, Object info) {
|
||||
return (info instanceof ItemInfo) && source.supportsDeleteDropTarget();
|
||||
public static boolean supportsDrop(Object info) {
|
||||
return (info instanceof ShortcutInfo)
|
||||
|| (info instanceof LauncherAppWidgetInfo)
|
||||
|| (info instanceof FolderInfo);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean supportsDrop(DragSource source, Object info) {
|
||||
return willAcceptDrop(source, info);
|
||||
return source.supportsDeleteDropTarget() && supportsDrop(info);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -304,4 +305,9 @@ public class DeleteDropTarget extends ButtonDropTarget {
|
||||
dragLayer.animateView(d.dragView, updateCb, duration, tInterpolator, onAnimationEndRunnable,
|
||||
DragLayer.ANIMATION_END_DISAPPEAR, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getAccessibilityDropConfirmation() {
|
||||
return getResources().getString(R.string.item_removed);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -462,8 +462,7 @@ public class DragController {
|
||||
mLastTouchUpTime = System.currentTimeMillis();
|
||||
if (mDragging) {
|
||||
PointF vec = isFlingingToDelete(mDragObject.dragSource);
|
||||
if (!DeleteDropTarget.willAcceptDrop(mDragObject.dragSource,
|
||||
mDragObject.dragInfo)) {
|
||||
if (!DeleteDropTarget.supportsDrop(mDragObject.dragInfo)) {
|
||||
vec = null;
|
||||
}
|
||||
if (vec != null) {
|
||||
@@ -617,7 +616,7 @@ public class DragController {
|
||||
|
||||
if (mDragging) {
|
||||
PointF vec = isFlingingToDelete(mDragObject.dragSource);
|
||||
if (!DeleteDropTarget.willAcceptDrop(mDragObject.dragSource, mDragObject.dragInfo)) {
|
||||
if (!DeleteDropTarget.supportsDrop(mDragObject.dragInfo)) {
|
||||
vec = null;
|
||||
}
|
||||
if (vec != null) {
|
||||
|
||||
@@ -21,7 +21,6 @@ import android.content.Context;
|
||||
import android.provider.Settings;
|
||||
import android.util.AttributeSet;
|
||||
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.compat.UserHandleCompat;
|
||||
|
||||
public class InfoDropTarget extends ButtonDropTarget {
|
||||
@@ -66,9 +65,13 @@ public class InfoDropTarget extends ButtonDropTarget {
|
||||
|
||||
@Override
|
||||
protected boolean supportsDrop(DragSource source, Object info) {
|
||||
return source.supportsAppInfoDropTarget() &&
|
||||
Settings.Global.getInt(getContext().getContentResolver(),
|
||||
Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 0) == 1;
|
||||
return source.supportsAppInfoDropTarget() && supportsDrop(getContext(), info);
|
||||
}
|
||||
|
||||
public static boolean supportsDrop(Context context, Object info) {
|
||||
return (Settings.Global.getInt(context.getContentResolver(),
|
||||
Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 0) == 1) &&
|
||||
(info instanceof AppInfo || info instanceof PendingAddItemInfo);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,16 +1,13 @@
|
||||
package com.android.launcher3;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Rect;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.view.accessibility.AccessibilityEventCompat;
|
||||
import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
|
||||
import android.text.TextUtils;
|
||||
import android.util.SparseArray;
|
||||
import android.view.View;
|
||||
import android.view.View.AccessibilityDelegate;
|
||||
import android.view.accessibility.AccessibilityEvent;
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
|
||||
|
||||
@@ -68,18 +65,21 @@ public class LauncherAccessibilityDelegate extends AccessibilityDelegate {
|
||||
if (!(host.getTag() instanceof ItemInfo)) return;
|
||||
ItemInfo item = (ItemInfo) host.getTag();
|
||||
|
||||
if (DeleteDropTarget.supportsDrop(item)) {
|
||||
info.addAction(mActions.get(REMOVE));
|
||||
}
|
||||
if (UninstallDropTarget.supportsDrop(host.getContext(), item)) {
|
||||
info.addAction(mActions.get(UNINSTALL));
|
||||
}
|
||||
if (InfoDropTarget.supportsDrop(host.getContext(), item)) {
|
||||
info.addAction(mActions.get(INFO));
|
||||
}
|
||||
|
||||
if ((item instanceof ShortcutInfo)
|
||||
|| (item instanceof LauncherAppWidgetInfo)
|
||||
|| (item instanceof FolderInfo)) {
|
||||
// Workspace shortcut / widget
|
||||
info.addAction(mActions.get(REMOVE));
|
||||
info.addAction(mActions.get(MOVE));
|
||||
} else if ((item instanceof AppInfo) || (item instanceof PendingAddItemInfo)) {
|
||||
// App or Widget from customization tray
|
||||
if (item instanceof AppInfo) {
|
||||
info.addAction(mActions.get(UNINSTALL));
|
||||
}
|
||||
info.addAction(mActions.get(INFO));
|
||||
} if ((item instanceof AppInfo) || (item instanceof PendingAddItemInfo)) {
|
||||
info.addAction(mActions.get(ADD_TO_WORKSPACE));
|
||||
}
|
||||
}
|
||||
@@ -94,10 +94,9 @@ public class LauncherAccessibilityDelegate extends AccessibilityDelegate {
|
||||
}
|
||||
|
||||
public boolean performAction(View host, ItemInfo item, int action) {
|
||||
Resources res = mLauncher.getResources();
|
||||
if (action == REMOVE) {
|
||||
if (DeleteDropTarget.removeWorkspaceOrFolderItem(mLauncher, item, host)) {
|
||||
announceConfirmation(R.string.item_removed_from_workspace);
|
||||
announceConfirmation(R.string.item_removed);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -105,9 +104,7 @@ public class LauncherAccessibilityDelegate extends AccessibilityDelegate {
|
||||
InfoDropTarget.startDetailsActivityForInfo(item, mLauncher);
|
||||
return true;
|
||||
} else if (action == UNINSTALL) {
|
||||
AppInfo info = (AppInfo) item;
|
||||
mLauncher.startApplicationUninstallActivity(info.componentName, info.flags, info.user);
|
||||
return true;
|
||||
return UninstallDropTarget.startUninstallActivity(mLauncher, item);
|
||||
} else if (action == MOVE) {
|
||||
beginAccessibleDrag(host, item);
|
||||
} else if (action == ADD_TO_WORKSPACE) {
|
||||
@@ -158,19 +155,31 @@ public class LauncherAccessibilityDelegate extends AccessibilityDelegate {
|
||||
return mDragInfo;
|
||||
}
|
||||
|
||||
public void handleAccessibleDrop(CellLayout targetContainer, Rect dropLocation,
|
||||
/**
|
||||
* @param clickedTarget the actual view that was clicked
|
||||
* @param dropLocation relative to {@param clickedTarget}. If provided, its center is used
|
||||
* as the actual drop location otherwise the views center is used.
|
||||
*/
|
||||
public void handleAccessibleDrop(View clickedTarget, Rect dropLocation,
|
||||
String confirmation) {
|
||||
if (!isInAccessibleDrag()) return;
|
||||
|
||||
int[] loc = new int[2];
|
||||
loc[0] = dropLocation.centerX();
|
||||
loc[1] = dropLocation.centerY();
|
||||
if (dropLocation == null) {
|
||||
loc[0] = clickedTarget.getWidth() / 2;
|
||||
loc[1] = clickedTarget.getHeight() / 2;
|
||||
} else {
|
||||
loc[0] = dropLocation.centerX();
|
||||
loc[1] = dropLocation.centerY();
|
||||
}
|
||||
|
||||
mLauncher.getDragLayer().getDescendantCoordRelativeToSelf(targetContainer, loc);
|
||||
mLauncher.getDragLayer().getDescendantCoordRelativeToSelf(clickedTarget, loc);
|
||||
mLauncher.getDragController().completeAccessibleDrag(loc);
|
||||
|
||||
endAccessibleDrag();
|
||||
announceConfirmation(confirmation);
|
||||
if (!TextUtils.isEmpty(confirmation)) {
|
||||
announceConfirmation(confirmation);
|
||||
}
|
||||
}
|
||||
|
||||
public void beginAccessibleDrag(View item, ItemInfo info) {
|
||||
|
||||
@@ -180,6 +180,9 @@ public class SearchDropTargetBar extends FrameLayout implements DragController.D
|
||||
prepareStartAnimation(mDropTargetBar);
|
||||
mShowDropTargetBarAnim.start();
|
||||
hideSearchBar(true);
|
||||
if (mQSBSearchBar != null) {
|
||||
mQSBSearchBar.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -190,6 +193,9 @@ public class SearchDropTargetBar extends FrameLayout implements DragController.D
|
||||
prepareStartAnimation(mDropTargetBar);
|
||||
mShowDropTargetBarAnim.reverse();
|
||||
showSearchBar(true);
|
||||
if (mQSBSearchBar != null) {
|
||||
mQSBSearchBar.setVisibility(View.VISIBLE);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -228,4 +234,13 @@ public class SearchDropTargetBar extends FrameLayout implements DragController.D
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public void enableAccessibleDrag(boolean enable) {
|
||||
if (mQSBSearchBar != null) {
|
||||
mQSBSearchBar.setVisibility(enable ? View.GONE : View.VISIBLE);
|
||||
}
|
||||
mInfoDropTarget.enableAccessibleDrag(enable);
|
||||
mDeleteDropTarget.enableAccessibleDrag(enable);
|
||||
mUninstallDropTarget.enableAccessibleDrag(enable);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,9 +33,12 @@ public class UninstallDropTarget extends ButtonDropTarget {
|
||||
|
||||
@Override
|
||||
protected boolean supportsDrop(DragSource source, Object info) {
|
||||
return supportsDrop(getContext(), info);
|
||||
}
|
||||
|
||||
public static boolean supportsDrop(Context context, Object info) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
|
||||
UserManager userManager = (UserManager)
|
||||
getContext().getSystemService(Context.USER_SERVICE);
|
||||
UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
|
||||
Bundle restrictions = userManager.getUserRestrictions();
|
||||
if (restrictions.getBoolean(UserManager.DISALLOW_APPS_CONTROL, false)
|
||||
|| restrictions.getBoolean(UserManager.DISALLOW_UNINSTALL_APPS, false)) {
|
||||
@@ -78,8 +81,7 @@ public class UninstallDropTarget extends ButtonDropTarget {
|
||||
void completeDrop(final DragObject d) {
|
||||
final Pair<ComponentName, Integer> componentInfo = getAppInfoFlags(d.dragInfo);
|
||||
final UserHandleCompat user = ((ItemInfo) d.dragInfo).user;
|
||||
if (mLauncher.startApplicationUninstallActivity(
|
||||
componentInfo.first, componentInfo.second, user)) {
|
||||
if (startUninstallActivity(mLauncher, d.dragInfo)) {
|
||||
|
||||
final Runnable checkIfUninstallWasSuccess = new Runnable() {
|
||||
@Override
|
||||
@@ -96,6 +98,13 @@ public class UninstallDropTarget extends ButtonDropTarget {
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean startUninstallActivity(Launcher launcher, Object info) {
|
||||
final Pair<ComponentName, Integer> componentInfo = getAppInfoFlags(info);
|
||||
final UserHandleCompat user = ((ItemInfo) info).user;
|
||||
return launcher.startApplicationUninstallActivity(
|
||||
componentInfo.first, componentInfo.second, user);
|
||||
}
|
||||
|
||||
@Thunk void sendUninstallResult(DragSource target, boolean result) {
|
||||
if (target instanceof UninstallSource) {
|
||||
((UninstallSource) target).onUninstallActivityReturned(result);
|
||||
|
||||
@@ -1615,6 +1615,7 @@ public class Workspace extends SmoothPagedView
|
||||
// Reset our click listener
|
||||
setOnClickListener(mLauncher);
|
||||
}
|
||||
mLauncher.getSearchBar().enableAccessibleDrag(enable);
|
||||
mLauncher.getHotseat().getLayout().enableAccessibleDrag(enable);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user