From 83a8f042adda926489494dff217c15ab696139b4 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Tue, 19 May 2015 12:52:12 -0700 Subject: Moving LauncherAccessibilityDelegate to accessibility package Change-Id: I510204a5a12abf2da2757f3e3f8b0e8869a6b04a --- src/com/android/launcher3/CellLayout.java | 4 +- src/com/android/launcher3/DragLayer.java | 1 + src/com/android/launcher3/Folder.java | 6 +- src/com/android/launcher3/Launcher.java | 5 +- .../launcher3/LauncherAccessibilityDelegate.java | 412 -------------------- src/com/android/launcher3/LauncherAppState.java | 1 + src/com/android/launcher3/LauncherModel.java | 4 +- src/com/android/launcher3/PagedView.java | 4 +- src/com/android/launcher3/SmoothPagedView.java | 2 +- src/com/android/launcher3/Workspace.java | 9 +- .../DragAndDropAccessibilityDelegate.java | 1 - .../LauncherAccessibilityDelegate.java | 430 +++++++++++++++++++++ .../WorkspaceAccessibilityHelper.java | 3 +- 13 files changed, 453 insertions(+), 429 deletions(-) delete mode 100644 src/com/android/launcher3/LauncherAccessibilityDelegate.java create mode 100644 src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java (limited to 'src/com/android') diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java index a348008d8..a6e11b683 100644 --- a/src/com/android/launcher3/CellLayout.java +++ b/src/com/android/launcher3/CellLayout.java @@ -3010,7 +3010,7 @@ public class CellLayout extends ViewGroup { // 2. When long clicking on an empty cell in a CellLayout, we save information about the // cellX and cellY coordinates and which page was clicked. We then set this as a tag on // the CellLayout that was long clicked - static final class CellInfo { + public static final class CellInfo { View cell; int cellX = -1; int cellY = -1; @@ -3019,7 +3019,7 @@ public class CellLayout extends ViewGroup { long screenId; long container; - CellInfo(View v, ItemInfo info) { + public CellInfo(View v, ItemInfo info) { cell = v; cellX = info.cellX; cellY = info.cellY; diff --git a/src/com/android/launcher3/DragLayer.java b/src/com/android/launcher3/DragLayer.java index e25e6152c..e8661e331 100644 --- a/src/com/android/launcher3/DragLayer.java +++ b/src/com/android/launcher3/DragLayer.java @@ -39,6 +39,7 @@ import android.view.animation.Interpolator; import android.widget.FrameLayout; import android.widget.TextView; +import com.android.launcher3.accessibility.LauncherAccessibilityDelegate; import com.android.launcher3.util.Thunk; import java.util.ArrayList; diff --git a/src/com/android/launcher3/Folder.java b/src/com/android/launcher3/Folder.java index 69b18374a..d0a7ba3f8 100644 --- a/src/com/android/launcher3/Folder.java +++ b/src/com/android/launcher3/Folder.java @@ -49,13 +49,15 @@ import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputMethodManager; import android.widget.LinearLayout; import android.widget.TextView; + import com.android.launcher3.CellLayout.CellInfo; import com.android.launcher3.DragController.DragListener; import com.android.launcher3.FolderInfo.FolderListener; -import com.android.launcher3.LauncherAccessibilityDelegate.AccessibilityDragSource; import com.android.launcher3.UninstallDropTarget.UninstallSource; import com.android.launcher3.Workspace.ItemOperator; +import com.android.launcher3.accessibility.LauncherAccessibilityDelegate.AccessibilityDragSource; import com.android.launcher3.util.Thunk; + import java.util.ArrayList; import java.util.Collections; @@ -352,7 +354,7 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList /** * @return the FolderInfo object associated with this folder */ - FolderInfo getInfo() { + public FolderInfo getInfo() { return mInfo; } diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index 51ba2dfc9..7b7b61795 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -96,6 +96,7 @@ import android.widget.Toast; import com.android.launcher3.DropTarget.DragObject; import com.android.launcher3.PagedView.PageSwitchListener; +import com.android.launcher3.accessibility.LauncherAccessibilityDelegate; import com.android.launcher3.compat.AppWidgetManagerCompat; import com.android.launcher3.compat.LauncherActivityInfoCompat; import com.android.launcher3.compat.LauncherAppsCompat; @@ -3184,7 +3185,7 @@ public class Launcher extends Activity } } - void closeFolder(Folder folder) { + public void closeFolder(Folder folder) { folder.getInfo().opened = false; ViewGroup parent = (ViewGroup) folder.getParent().getParent(); @@ -3337,7 +3338,7 @@ public class Launcher extends Activity true); } - protected void showWorkspace(boolean animated, Runnable onCompleteRunnable) { + public void showWorkspace(boolean animated, Runnable onCompleteRunnable) { showWorkspace(WorkspaceStateTransitionAnimation.SCROLL_TO_CURRENT_PAGE, animated, onCompleteRunnable, true); } diff --git a/src/com/android/launcher3/LauncherAccessibilityDelegate.java b/src/com/android/launcher3/LauncherAccessibilityDelegate.java deleted file mode 100644 index 3992e6390..000000000 --- a/src/com/android/launcher3/LauncherAccessibilityDelegate.java +++ /dev/null @@ -1,412 +0,0 @@ -package com.android.launcher3; - -import android.annotation.TargetApi; -import android.app.AlertDialog; -import android.appwidget.AppWidgetProviderInfo; -import android.content.DialogInterface; -import android.graphics.Rect; -import android.os.Build; -import android.os.Bundle; -import android.os.Handler; -import android.text.TextUtils; -import android.util.Log; -import android.util.SparseArray; -import android.view.View; -import android.view.View.AccessibilityDelegate; -import android.view.accessibility.AccessibilityNodeInfo; -import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction; - -import com.android.launcher3.util.Thunk; - -import java.util.ArrayList; - -@TargetApi(Build.VERSION_CODES.LOLLIPOP) -public class LauncherAccessibilityDelegate extends AccessibilityDelegate { - - private static final String TAG = "LauncherAccessibilityDelegate"; - - private static final int REMOVE = R.id.action_remove; - private static final int INFO = R.id.action_info; - private static final int UNINSTALL = R.id.action_uninstall; - private static final int ADD_TO_WORKSPACE = R.id.action_add_to_workspace; - private static final int MOVE = R.id.action_move; - private static final int MOVE_TO_WORKSPACE = R.id.action_move_to_workspace; - private static final int RESIZE = R.id.action_resize; - - public enum DragType { - ICON, - FOLDER, - WIDGET - } - - public static class DragInfo { - public DragType dragType; - public ItemInfo info; - public View item; - } - - private final SparseArray mActions = new SparseArray<>(); - @Thunk final Launcher mLauncher; - - private DragInfo mDragInfo = null; - private AccessibilityDragSource mDragSource = null; - - public LauncherAccessibilityDelegate(Launcher launcher) { - mLauncher = launcher; - - mActions.put(REMOVE, new AccessibilityAction(REMOVE, - launcher.getText(R.string.delete_target_label))); - mActions.put(INFO, new AccessibilityAction(INFO, - launcher.getText(R.string.info_target_label))); - mActions.put(UNINSTALL, new AccessibilityAction(UNINSTALL, - launcher.getText(R.string.delete_target_uninstall_label))); - mActions.put(ADD_TO_WORKSPACE, new AccessibilityAction(ADD_TO_WORKSPACE, - launcher.getText(R.string.action_add_to_workspace))); - mActions.put(MOVE, new AccessibilityAction(MOVE, - launcher.getText(R.string.action_move))); - mActions.put(MOVE_TO_WORKSPACE, new AccessibilityAction(MOVE_TO_WORKSPACE, - launcher.getText(R.string.action_move_to_workspace))); - mActions.put(RESIZE, new AccessibilityAction(RESIZE, - launcher.getText(R.string.action_resize))); - } - - @Override - public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) { - super.onInitializeAccessibilityNodeInfo(host, info); - 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)) { - info.addAction(mActions.get(MOVE)); - - if (item.container >= 0) { - info.addAction(mActions.get(MOVE_TO_WORKSPACE)); - } else if (item instanceof LauncherAppWidgetInfo) { - if (!getSupportedResizeActions(host, (LauncherAppWidgetInfo) item).isEmpty()) { - info.addAction(mActions.get(RESIZE)); - } - } - } if ((item instanceof AppInfo) || (item instanceof PendingAddItemInfo)) { - info.addAction(mActions.get(ADD_TO_WORKSPACE)); - } - } - - @Override - public boolean performAccessibilityAction(View host, int action, Bundle args) { - if ((host.getTag() instanceof ItemInfo) - && performAction(host, (ItemInfo) host.getTag(), action)) { - return true; - } - return super.performAccessibilityAction(host, action, args); - } - - 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; - } else if (action == INFO) { - InfoDropTarget.startDetailsActivityForInfo(item, mLauncher); - return true; - } else if (action == UNINSTALL) { - return UninstallDropTarget.startUninstallActivity(mLauncher, item); - } else if (action == MOVE) { - beginAccessibleDrag(host, item); - } else if (action == ADD_TO_WORKSPACE) { - final int[] coordinates = new int[2]; - final long screenId = findSpaceOnWorkspace(item, coordinates); - mLauncher.showWorkspace(true, new Runnable() { - - @Override - public void run() { - if (item instanceof AppInfo) { - ShortcutInfo info = ((AppInfo) item).makeShortcut(); - LauncherModel.addItemToDatabase(mLauncher, info, - LauncherSettings.Favorites.CONTAINER_DESKTOP, - screenId, coordinates[0], coordinates[1]); - - ArrayList itemList = new ArrayList<>(); - itemList.add(info); - mLauncher.bindItems(itemList, 0, itemList.size(), true); - } else if (item instanceof PendingAddItemInfo) { - PendingAddItemInfo info = (PendingAddItemInfo) item; - Workspace workspace = mLauncher.getWorkspace(); - workspace.snapToPage(workspace.getPageIndexForScreenId(screenId)); - mLauncher.addPendingItem(info, LauncherSettings.Favorites.CONTAINER_DESKTOP, - screenId, coordinates, info.spanX, info.spanY); - } - announceConfirmation(R.string.item_added_to_workspace); - } - }); - return true; - } else if (action == MOVE_TO_WORKSPACE) { - Folder folder = mLauncher.getWorkspace().getOpenFolder(); - mLauncher.closeFolder(folder); - ShortcutInfo info = (ShortcutInfo) item; - folder.getInfo().remove(info); - - final int[] coordinates = new int[2]; - final long screenId = findSpaceOnWorkspace(item, coordinates); - LauncherModel.moveItemInDatabase(mLauncher, info, - LauncherSettings.Favorites.CONTAINER_DESKTOP, - screenId, coordinates[0], coordinates[1]); - - // Bind the item in next frame so that if a new workspace page was created, - // it will get laid out. - new Handler().post(new Runnable() { - - @Override - public void run() { - ArrayList itemList = new ArrayList<>(); - itemList.add(item); - mLauncher.bindItems(itemList, 0, itemList.size(), true); - announceConfirmation(R.string.item_moved); - } - }); - } else if (action == RESIZE) { - final LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) item; - final ArrayList actions = getSupportedResizeActions(host, info); - CharSequence[] labels = new CharSequence[actions.size()]; - for (int i = 0; i < actions.size(); i++) { - labels[i] = mLauncher.getText(actions.get(i)); - } - - new AlertDialog.Builder(mLauncher) - .setTitle(R.string.action_resize) - .setItems(labels, new DialogInterface.OnClickListener() { - - @Override - public void onClick(DialogInterface dialog, int which) { - performResizeAction(actions.get(which), host, info); - dialog.dismiss(); - } - }) - .show(); - } - return false; - } - - private ArrayList getSupportedResizeActions(View host, LauncherAppWidgetInfo info) { - AppWidgetProviderInfo providerInfo = ((LauncherAppWidgetHostView) host).getAppWidgetInfo(); - ArrayList actions = new ArrayList<>(); - - CellLayout layout = (CellLayout) host.getParent().getParent(); - if ((providerInfo.resizeMode & AppWidgetProviderInfo.RESIZE_HORIZONTAL) != 0) { - if (layout.isRegionVacant(info.cellX + info.spanX, info.cellY, 1, info.spanY) || - layout.isRegionVacant(info.cellX - 1, info.cellY, 1, info.spanY)) { - actions.add(R.string.action_increase_width); - } - - if (info.spanX > info.minSpanX && info.spanX > 1) { - actions.add(R.string.action_decrease_width); - } - } - - if ((providerInfo.resizeMode & AppWidgetProviderInfo.RESIZE_VERTICAL) != 0) { - if (layout.isRegionVacant(info.cellX, info.cellY + info.spanY, info.spanX, 1) || - layout.isRegionVacant(info.cellX, info.cellY - 1, info.spanX, 1)) { - actions.add(R.string.action_increase_height); - } - - if (info.spanY > info.minSpanY && info.spanY > 1) { - actions.add(R.string.action_decrease_height); - } - } - return actions; - } - - private void performResizeAction(int action, View host, LauncherAppWidgetInfo info) { - CellLayout.LayoutParams lp = (CellLayout.LayoutParams) host.getLayoutParams(); - CellLayout layout = (CellLayout) host.getParent().getParent(); - layout.markCellsAsUnoccupiedForView(host); - - if (action == R.string.action_increase_width) { - if (((host.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL) - && layout.isRegionVacant(info.cellX - 1, info.cellY, 1, info.spanY)) - || !layout.isRegionVacant(info.cellX + info.spanX, info.cellY, 1, info.spanY)) { - lp.cellX --; - info.cellX --; - } - lp.cellHSpan ++; - info.spanX ++; - } else if (action == R.string.action_decrease_width) { - lp.cellHSpan --; - info.spanX --; - } else if (action == R.string.action_increase_height) { - if (!layout.isRegionVacant(info.cellX, info.cellY + info.spanY, info.spanX, 1)) { - lp.cellY --; - info.cellY --; - } - lp.cellVSpan ++; - info.spanY ++; - } else if (action == R.string.action_decrease_height) { - lp.cellVSpan --; - info.spanY --; - } - - layout.markCellsAsOccupiedForView(host); - Rect sizeRange = new Rect(); - AppWidgetResizeFrame.getWidgetSizeRanges(mLauncher, info.spanX, info.spanY, sizeRange); - ((LauncherAppWidgetHostView) host).updateAppWidgetSize(null, - sizeRange.left, sizeRange.top, sizeRange.right, sizeRange.bottom); - host.requestLayout(); - LauncherModel.updateItemInDatabase(mLauncher, info); - announceConfirmation(mLauncher.getString(R.string.widget_resized, info.spanX, info.spanY)); - } - - @Thunk void announceConfirmation(int resId) { - announceConfirmation(mLauncher.getResources().getString(resId)); - } - - @Thunk void announceConfirmation(String confirmation) { - mLauncher.getDragLayer().announceForAccessibility(confirmation); - - } - - public boolean isInAccessibleDrag() { - return mDragInfo != null; - } - - public DragInfo getDragInfo() { - return mDragInfo; - } - - /** - * @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]; - 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(clickedTarget, loc); - mLauncher.getDragController().completeAccessibleDrag(loc); - - endAccessibleDrag(); - if (!TextUtils.isEmpty(confirmation)) { - announceConfirmation(confirmation); - } - } - - public void beginAccessibleDrag(View item, ItemInfo info) { - mDragInfo = new DragInfo(); - mDragInfo.info = info; - mDragInfo.item = item; - mDragInfo.dragType = DragType.ICON; - if (info instanceof FolderInfo) { - mDragInfo.dragType = DragType.FOLDER; - } else if (info instanceof LauncherAppWidgetInfo) { - mDragInfo.dragType = DragType.WIDGET; - } - - CellLayout.CellInfo cellInfo = new CellLayout.CellInfo(item, info); - - Rect pos = new Rect(); - mLauncher.getDragLayer().getDescendantRectRelativeToSelf(item, pos); - mLauncher.getDragController().prepareAccessibleDrag(pos.centerX(), pos.centerY()); - - Workspace workspace = mLauncher.getWorkspace(); - - Folder folder = workspace.getOpenFolder(); - if (folder != null) { - if (folder.getItemsInReadingOrder().contains(item)) { - mDragSource = folder; - } else { - mLauncher.closeFolder(); - } - } - if (mDragSource == null) { - mDragSource = workspace; - } - mDragSource.enableAccessibleDrag(true); - mDragSource.startDrag(cellInfo, true); - } - - public boolean onBackPressed() { - if (isInAccessibleDrag()) { - cancelAccessibleDrag(); - return true; - } - return false; - } - - private void cancelAccessibleDrag() { - mLauncher.getDragController().cancelDrag(); - endAccessibleDrag(); - } - - private void endAccessibleDrag() { - mDragInfo = null; - if (mDragSource != null) { - mDragSource.enableAccessibleDrag(false); - mDragSource = null; - } - } - - public static interface AccessibilityDragSource { - void startDrag(CellLayout.CellInfo cellInfo, boolean accessible); - - void enableAccessibleDrag(boolean enable); - } - - /** - * Find empty space on the workspace and returns the screenId. - */ - private long findSpaceOnWorkspace(ItemInfo info, int[] outCoordinates) { - Workspace workspace = mLauncher.getWorkspace(); - ArrayList workspaceScreens = workspace.getScreenOrder(); - long screenId; - - // First check if there is space on the current screen. - int screenIndex = workspace.getCurrentPage(); - screenId = workspaceScreens.get(screenIndex); - CellLayout layout = (CellLayout) workspace.getPageAt(screenIndex); - - boolean found = layout.findCellForSpan(outCoordinates, info.spanX, info.spanY); - screenIndex = workspace.hasCustomContent() ? 1 : 0; - while (!found && screenIndex < workspaceScreens.size()) { - screenId = workspaceScreens.get(screenIndex); - layout = (CellLayout) workspace.getPageAt(screenIndex); - found = layout.findCellForSpan(outCoordinates, info.spanX, info.spanY); - screenIndex++; - } - - if (found) { - return screenId; - } - - workspace.addExtraEmptyScreen(); - screenId = workspace.commitExtraEmptyScreen(); - layout = workspace.getScreenWithId(screenId); - found = layout.findCellForSpan(outCoordinates, info.spanX, info.spanY); - - if (!found) { - Log.wtf(TAG, "Not enough space on an empty screen"); - } - return screenId; - } -} diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java index bde54c335..f540eb47d 100644 --- a/src/com/android/launcher3/LauncherAppState.java +++ b/src/com/android/launcher3/LauncherAppState.java @@ -31,6 +31,7 @@ import android.util.Log; import android.view.Display; import android.view.WindowManager; +import com.android.launcher3.accessibility.LauncherAccessibilityDelegate; import com.android.launcher3.compat.LauncherAppsCompat; import com.android.launcher3.compat.PackageInstallerCompat; import com.android.launcher3.util.Thunk; diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java index 0b3049c2e..635c86320 100644 --- a/src/com/android/launcher3/LauncherModel.java +++ b/src/com/android/launcher3/LauncherModel.java @@ -793,7 +793,7 @@ public class LauncherModel extends BroadcastReceiver /** * Move an item in the DB to a new */ - static void moveItemInDatabase(Context context, final ItemInfo item, final long container, + public static void moveItemInDatabase(Context context, final ItemInfo item, final long container, final long screenId, final int cellX, final int cellY) { item.container = container; item.cellX = cellX; @@ -889,7 +889,7 @@ public class LauncherModel extends BroadcastReceiver /** * Update an item to the database in a specified container. */ - static void updateItemInDatabase(Context context, final ItemInfo item) { + public static void updateItemInDatabase(Context context, final ItemInfo item) { final ContentValues values = new ContentValues(); item.onAddToDatabase(context, values); updateItemInDatabaseHelper(context, values, item, "updateItemInDatabase"); diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java index 554a975e7..62f1bc9d7 100644 --- a/src/com/android/launcher3/PagedView.java +++ b/src/com/android/launcher3/PagedView.java @@ -407,7 +407,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc /** * Returns the index of the currently displayed page. */ - int getCurrentPage() { + public int getCurrentPage() { return mCurrentPage; } @@ -422,7 +422,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc return getChildCount(); } - View getPageAt(int index) { + public View getPageAt(int index) { return getChildAt(index); } diff --git a/src/com/android/launcher3/SmoothPagedView.java b/src/com/android/launcher3/SmoothPagedView.java index 4e331aa2c..0f9b23cda 100644 --- a/src/com/android/launcher3/SmoothPagedView.java +++ b/src/com/android/launcher3/SmoothPagedView.java @@ -152,7 +152,7 @@ public abstract class SmoothPagedView extends PagedView { } @Override - protected void snapToPage(int whichPage) { + public void snapToPage(int whichPage) { if (mScrollMode == X_LARGE_MODE) { super.snapToPage(whichPage); } else { diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java index 58e5877a6..8c1c7d689 100644 --- a/src/com/android/launcher3/Workspace.java +++ b/src/com/android/launcher3/Workspace.java @@ -57,19 +57,22 @@ import android.view.accessibility.AccessibilityManager; import android.view.animation.DecelerateInterpolator; import android.view.animation.Interpolator; import android.widget.TextView; + import com.android.launcher3.FolderIcon.FolderRingAnimator; import com.android.launcher3.Launcher.CustomContentCallbacks; import com.android.launcher3.Launcher.LauncherOverlay; -import com.android.launcher3.LauncherAccessibilityDelegate.AccessibilityDragSource; import com.android.launcher3.LauncherSettings.Favorites; import com.android.launcher3.UninstallDropTarget.UninstallSource; +import com.android.launcher3.accessibility.LauncherAccessibilityDelegate; import com.android.launcher3.accessibility.OverviewScreenAccessibilityDelegate; +import com.android.launcher3.accessibility.LauncherAccessibilityDelegate.AccessibilityDragSource; import com.android.launcher3.compat.UserHandleCompat; import com.android.launcher3.util.LongArrayMap; import com.android.launcher3.util.Thunk; import com.android.launcher3.util.WallpaperUtils; import com.android.launcher3.widget.PendingAddShortcutInfo; import com.android.launcher3.widget.PendingAddWidgetInfo; + import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; @@ -494,7 +497,7 @@ public class Workspace extends SmoothPagedView /** * @return The open folder on the current screen, or null if there is none */ - Folder getOpenFolder() { + public Folder getOpenFolder() { DragLayer dragLayer = mLauncher.getDragLayer(); int count = dragLayer.getChildCount(); for (int i = 0; i < count; i++) { @@ -857,7 +860,7 @@ public class Workspace extends SmoothPagedView return -1; } - ArrayList getScreenOrder() { + public ArrayList getScreenOrder() { return mScreenOrder; } diff --git a/src/com/android/launcher3/accessibility/DragAndDropAccessibilityDelegate.java b/src/com/android/launcher3/accessibility/DragAndDropAccessibilityDelegate.java index 0f1724155..78accf720 100644 --- a/src/com/android/launcher3/accessibility/DragAndDropAccessibilityDelegate.java +++ b/src/com/android/launcher3/accessibility/DragAndDropAccessibilityDelegate.java @@ -26,7 +26,6 @@ import android.view.View.OnClickListener; import android.view.accessibility.AccessibilityEvent; import com.android.launcher3.CellLayout; -import com.android.launcher3.LauncherAccessibilityDelegate; import com.android.launcher3.LauncherAppState; import com.android.launcher3.R; diff --git a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java new file mode 100644 index 000000000..eeec8c580 --- /dev/null +++ b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java @@ -0,0 +1,430 @@ +package com.android.launcher3.accessibility; + +import android.annotation.TargetApi; +import android.app.AlertDialog; +import android.appwidget.AppWidgetProviderInfo; +import android.content.DialogInterface; +import android.graphics.Rect; +import android.os.Build; +import android.os.Bundle; +import android.os.Handler; +import android.text.TextUtils; +import android.util.Log; +import android.util.SparseArray; +import android.view.View; +import android.view.View.AccessibilityDelegate; +import android.view.accessibility.AccessibilityNodeInfo; +import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction; + +import com.android.launcher3.AppInfo; +import com.android.launcher3.AppWidgetResizeFrame; +import com.android.launcher3.CellLayout; +import com.android.launcher3.DeleteDropTarget; +import com.android.launcher3.Folder; +import com.android.launcher3.FolderInfo; +import com.android.launcher3.InfoDropTarget; +import com.android.launcher3.ItemInfo; +import com.android.launcher3.Launcher; +import com.android.launcher3.LauncherAppWidgetHostView; +import com.android.launcher3.LauncherAppWidgetInfo; +import com.android.launcher3.LauncherModel; +import com.android.launcher3.LauncherSettings; +import com.android.launcher3.PendingAddItemInfo; +import com.android.launcher3.R; +import com.android.launcher3.ShortcutInfo; +import com.android.launcher3.UninstallDropTarget; +import com.android.launcher3.Workspace; +import com.android.launcher3.util.Thunk; + +import java.util.ArrayList; + +@TargetApi(Build.VERSION_CODES.LOLLIPOP) +public class LauncherAccessibilityDelegate extends AccessibilityDelegate { + + private static final String TAG = "LauncherAccessibilityDelegate"; + + private static final int REMOVE = R.id.action_remove; + private static final int INFO = R.id.action_info; + private static final int UNINSTALL = R.id.action_uninstall; + private static final int ADD_TO_WORKSPACE = R.id.action_add_to_workspace; + private static final int MOVE = R.id.action_move; + private static final int MOVE_TO_WORKSPACE = R.id.action_move_to_workspace; + private static final int RESIZE = R.id.action_resize; + + public enum DragType { + ICON, + FOLDER, + WIDGET + } + + public static class DragInfo { + public DragType dragType; + public ItemInfo info; + public View item; + } + + private final SparseArray mActions = new SparseArray<>(); + @Thunk final Launcher mLauncher; + + private DragInfo mDragInfo = null; + private AccessibilityDragSource mDragSource = null; + + public LauncherAccessibilityDelegate(Launcher launcher) { + mLauncher = launcher; + + mActions.put(REMOVE, new AccessibilityAction(REMOVE, + launcher.getText(R.string.delete_target_label))); + mActions.put(INFO, new AccessibilityAction(INFO, + launcher.getText(R.string.info_target_label))); + mActions.put(UNINSTALL, new AccessibilityAction(UNINSTALL, + launcher.getText(R.string.delete_target_uninstall_label))); + mActions.put(ADD_TO_WORKSPACE, new AccessibilityAction(ADD_TO_WORKSPACE, + launcher.getText(R.string.action_add_to_workspace))); + mActions.put(MOVE, new AccessibilityAction(MOVE, + launcher.getText(R.string.action_move))); + mActions.put(MOVE_TO_WORKSPACE, new AccessibilityAction(MOVE_TO_WORKSPACE, + launcher.getText(R.string.action_move_to_workspace))); + mActions.put(RESIZE, new AccessibilityAction(RESIZE, + launcher.getText(R.string.action_resize))); + } + + @Override + public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) { + super.onInitializeAccessibilityNodeInfo(host, info); + 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)) { + info.addAction(mActions.get(MOVE)); + + if (item.container >= 0) { + info.addAction(mActions.get(MOVE_TO_WORKSPACE)); + } else if (item instanceof LauncherAppWidgetInfo) { + if (!getSupportedResizeActions(host, (LauncherAppWidgetInfo) item).isEmpty()) { + info.addAction(mActions.get(RESIZE)); + } + } + } if ((item instanceof AppInfo) || (item instanceof PendingAddItemInfo)) { + info.addAction(mActions.get(ADD_TO_WORKSPACE)); + } + } + + @Override + public boolean performAccessibilityAction(View host, int action, Bundle args) { + if ((host.getTag() instanceof ItemInfo) + && performAction(host, (ItemInfo) host.getTag(), action)) { + return true; + } + return super.performAccessibilityAction(host, action, args); + } + + 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; + } else if (action == INFO) { + InfoDropTarget.startDetailsActivityForInfo(item, mLauncher); + return true; + } else if (action == UNINSTALL) { + return UninstallDropTarget.startUninstallActivity(mLauncher, item); + } else if (action == MOVE) { + beginAccessibleDrag(host, item); + } else if (action == ADD_TO_WORKSPACE) { + final int[] coordinates = new int[2]; + final long screenId = findSpaceOnWorkspace(item, coordinates); + mLauncher.showWorkspace(true, new Runnable() { + + @Override + public void run() { + if (item instanceof AppInfo) { + ShortcutInfo info = ((AppInfo) item).makeShortcut(); + LauncherModel.addItemToDatabase(mLauncher, info, + LauncherSettings.Favorites.CONTAINER_DESKTOP, + screenId, coordinates[0], coordinates[1]); + + ArrayList itemList = new ArrayList<>(); + itemList.add(info); + mLauncher.bindItems(itemList, 0, itemList.size(), true); + } else if (item instanceof PendingAddItemInfo) { + PendingAddItemInfo info = (PendingAddItemInfo) item; + Workspace workspace = mLauncher.getWorkspace(); + workspace.snapToPage(workspace.getPageIndexForScreenId(screenId)); + mLauncher.addPendingItem(info, LauncherSettings.Favorites.CONTAINER_DESKTOP, + screenId, coordinates, info.spanX, info.spanY); + } + announceConfirmation(R.string.item_added_to_workspace); + } + }); + return true; + } else if (action == MOVE_TO_WORKSPACE) { + Folder folder = mLauncher.getWorkspace().getOpenFolder(); + mLauncher.closeFolder(folder); + ShortcutInfo info = (ShortcutInfo) item; + folder.getInfo().remove(info); + + final int[] coordinates = new int[2]; + final long screenId = findSpaceOnWorkspace(item, coordinates); + LauncherModel.moveItemInDatabase(mLauncher, info, + LauncherSettings.Favorites.CONTAINER_DESKTOP, + screenId, coordinates[0], coordinates[1]); + + // Bind the item in next frame so that if a new workspace page was created, + // it will get laid out. + new Handler().post(new Runnable() { + + @Override + public void run() { + ArrayList itemList = new ArrayList<>(); + itemList.add(item); + mLauncher.bindItems(itemList, 0, itemList.size(), true); + announceConfirmation(R.string.item_moved); + } + }); + } else if (action == RESIZE) { + final LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) item; + final ArrayList actions = getSupportedResizeActions(host, info); + CharSequence[] labels = new CharSequence[actions.size()]; + for (int i = 0; i < actions.size(); i++) { + labels[i] = mLauncher.getText(actions.get(i)); + } + + new AlertDialog.Builder(mLauncher) + .setTitle(R.string.action_resize) + .setItems(labels, new DialogInterface.OnClickListener() { + + @Override + public void onClick(DialogInterface dialog, int which) { + performResizeAction(actions.get(which), host, info); + dialog.dismiss(); + } + }) + .show(); + } + return false; + } + + private ArrayList getSupportedResizeActions(View host, LauncherAppWidgetInfo info) { + AppWidgetProviderInfo providerInfo = ((LauncherAppWidgetHostView) host).getAppWidgetInfo(); + ArrayList actions = new ArrayList<>(); + + CellLayout layout = (CellLayout) host.getParent().getParent(); + if ((providerInfo.resizeMode & AppWidgetProviderInfo.RESIZE_HORIZONTAL) != 0) { + if (layout.isRegionVacant(info.cellX + info.spanX, info.cellY, 1, info.spanY) || + layout.isRegionVacant(info.cellX - 1, info.cellY, 1, info.spanY)) { + actions.add(R.string.action_increase_width); + } + + if (info.spanX > info.minSpanX && info.spanX > 1) { + actions.add(R.string.action_decrease_width); + } + } + + if ((providerInfo.resizeMode & AppWidgetProviderInfo.RESIZE_VERTICAL) != 0) { + if (layout.isRegionVacant(info.cellX, info.cellY + info.spanY, info.spanX, 1) || + layout.isRegionVacant(info.cellX, info.cellY - 1, info.spanX, 1)) { + actions.add(R.string.action_increase_height); + } + + if (info.spanY > info.minSpanY && info.spanY > 1) { + actions.add(R.string.action_decrease_height); + } + } + return actions; + } + + private void performResizeAction(int action, View host, LauncherAppWidgetInfo info) { + CellLayout.LayoutParams lp = (CellLayout.LayoutParams) host.getLayoutParams(); + CellLayout layout = (CellLayout) host.getParent().getParent(); + layout.markCellsAsUnoccupiedForView(host); + + if (action == R.string.action_increase_width) { + if (((host.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL) + && layout.isRegionVacant(info.cellX - 1, info.cellY, 1, info.spanY)) + || !layout.isRegionVacant(info.cellX + info.spanX, info.cellY, 1, info.spanY)) { + lp.cellX --; + info.cellX --; + } + lp.cellHSpan ++; + info.spanX ++; + } else if (action == R.string.action_decrease_width) { + lp.cellHSpan --; + info.spanX --; + } else if (action == R.string.action_increase_height) { + if (!layout.isRegionVacant(info.cellX, info.cellY + info.spanY, info.spanX, 1)) { + lp.cellY --; + info.cellY --; + } + lp.cellVSpan ++; + info.spanY ++; + } else if (action == R.string.action_decrease_height) { + lp.cellVSpan --; + info.spanY --; + } + + layout.markCellsAsOccupiedForView(host); + Rect sizeRange = new Rect(); + AppWidgetResizeFrame.getWidgetSizeRanges(mLauncher, info.spanX, info.spanY, sizeRange); + ((LauncherAppWidgetHostView) host).updateAppWidgetSize(null, + sizeRange.left, sizeRange.top, sizeRange.right, sizeRange.bottom); + host.requestLayout(); + LauncherModel.updateItemInDatabase(mLauncher, info); + announceConfirmation(mLauncher.getString(R.string.widget_resized, info.spanX, info.spanY)); + } + + @Thunk void announceConfirmation(int resId) { + announceConfirmation(mLauncher.getResources().getString(resId)); + } + + @Thunk void announceConfirmation(String confirmation) { + mLauncher.getDragLayer().announceForAccessibility(confirmation); + + } + + public boolean isInAccessibleDrag() { + return mDragInfo != null; + } + + public DragInfo getDragInfo() { + return mDragInfo; + } + + /** + * @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]; + 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(clickedTarget, loc); + mLauncher.getDragController().completeAccessibleDrag(loc); + + endAccessibleDrag(); + if (!TextUtils.isEmpty(confirmation)) { + announceConfirmation(confirmation); + } + } + + public void beginAccessibleDrag(View item, ItemInfo info) { + mDragInfo = new DragInfo(); + mDragInfo.info = info; + mDragInfo.item = item; + mDragInfo.dragType = DragType.ICON; + if (info instanceof FolderInfo) { + mDragInfo.dragType = DragType.FOLDER; + } else if (info instanceof LauncherAppWidgetInfo) { + mDragInfo.dragType = DragType.WIDGET; + } + + CellLayout.CellInfo cellInfo = new CellLayout.CellInfo(item, info); + + Rect pos = new Rect(); + mLauncher.getDragLayer().getDescendantRectRelativeToSelf(item, pos); + mLauncher.getDragController().prepareAccessibleDrag(pos.centerX(), pos.centerY()); + + Workspace workspace = mLauncher.getWorkspace(); + + Folder folder = workspace.getOpenFolder(); + if (folder != null) { + if (folder.getItemsInReadingOrder().contains(item)) { + mDragSource = folder; + } else { + mLauncher.closeFolder(); + } + } + if (mDragSource == null) { + mDragSource = workspace; + } + mDragSource.enableAccessibleDrag(true); + mDragSource.startDrag(cellInfo, true); + } + + public boolean onBackPressed() { + if (isInAccessibleDrag()) { + cancelAccessibleDrag(); + return true; + } + return false; + } + + private void cancelAccessibleDrag() { + mLauncher.getDragController().cancelDrag(); + endAccessibleDrag(); + } + + private void endAccessibleDrag() { + mDragInfo = null; + if (mDragSource != null) { + mDragSource.enableAccessibleDrag(false); + mDragSource = null; + } + } + + public static interface AccessibilityDragSource { + void startDrag(CellLayout.CellInfo cellInfo, boolean accessible); + + void enableAccessibleDrag(boolean enable); + } + + /** + * Find empty space on the workspace and returns the screenId. + */ + private long findSpaceOnWorkspace(ItemInfo info, int[] outCoordinates) { + Workspace workspace = mLauncher.getWorkspace(); + ArrayList workspaceScreens = workspace.getScreenOrder(); + long screenId; + + // First check if there is space on the current screen. + int screenIndex = workspace.getCurrentPage(); + screenId = workspaceScreens.get(screenIndex); + CellLayout layout = (CellLayout) workspace.getPageAt(screenIndex); + + boolean found = layout.findCellForSpan(outCoordinates, info.spanX, info.spanY); + screenIndex = workspace.hasCustomContent() ? 1 : 0; + while (!found && screenIndex < workspaceScreens.size()) { + screenId = workspaceScreens.get(screenIndex); + layout = (CellLayout) workspace.getPageAt(screenIndex); + found = layout.findCellForSpan(outCoordinates, info.spanX, info.spanY); + screenIndex++; + } + + if (found) { + return screenId; + } + + workspace.addExtraEmptyScreen(); + screenId = workspace.commitExtraEmptyScreen(); + layout = workspace.getScreenWithId(screenId); + found = layout.findCellForSpan(outCoordinates, info.spanX, info.spanY); + + if (!found) { + Log.wtf(TAG, "Not enough space on an empty screen"); + } + return screenId; + } +} diff --git a/src/com/android/launcher3/accessibility/WorkspaceAccessibilityHelper.java b/src/com/android/launcher3/accessibility/WorkspaceAccessibilityHelper.java index 6f89d0eb0..80ddc13b7 100644 --- a/src/com/android/launcher3/accessibility/WorkspaceAccessibilityHelper.java +++ b/src/com/android/launcher3/accessibility/WorkspaceAccessibilityHelper.java @@ -23,8 +23,7 @@ import com.android.launcher3.AppInfo; import com.android.launcher3.CellLayout; import com.android.launcher3.FolderInfo; import com.android.launcher3.ItemInfo; -import com.android.launcher3.LauncherAccessibilityDelegate; -import com.android.launcher3.LauncherAccessibilityDelegate.DragType; +import com.android.launcher3.accessibility.LauncherAccessibilityDelegate.DragType; import com.android.launcher3.R; import com.android.launcher3.ShortcutInfo; -- cgit v1.2.3