1 /* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.launcher3.accessibility; 18 19 import android.text.TextUtils; 20 import android.view.View; 21 22 import com.android.launcher3.AppInfo; 23 import com.android.launcher3.CellLayout; 24 import com.android.launcher3.FolderInfo; 25 import com.android.launcher3.ItemInfo; 26 import com.android.launcher3.accessibility.LauncherAccessibilityDelegate.DragType; 27 import com.android.launcher3.R; 28 import com.android.launcher3.ShortcutInfo; 29 30 /** 31 * Implementation of {@link DragAndDropAccessibilityDelegate} to support DnD on workspace. 32 */ 33 public class WorkspaceAccessibilityHelper extends DragAndDropAccessibilityDelegate { 34 35 public WorkspaceAccessibilityHelper(CellLayout layout) { 36 super(layout); 37 } 38 39 /** 40 * Find the virtual view id corresponding to the top left corner of any drop region by which 41 * the passed id is contained. For an icon, this is simply 42 */ 43 @Override 44 protected int intersectsValidDropTarget(int id) { 45 int mCountX = mView.getCountX(); 46 int mCountY = mView.getCountY(); 47 48 int x = id % mCountX; 49 int y = id / mCountX; 50 LauncherAccessibilityDelegate.DragInfo dragInfo = mDelegate.getDragInfo(); 51 52 if (dragInfo.dragType == DragType.WIDGET && mView.isHotseat()) { 53 return INVALID_POSITION; 54 } 55 56 if (dragInfo.dragType == DragType.WIDGET) { 57 // For a widget, every cell must be vacant. In addition, we will return any valid 58 // drop target by which the passed id is contained. 59 boolean fits = false; 60 61 // These represent the amount that we can back off if we hit a problem. They 62 // get consumed as we move up and to the right, trying new regions. 63 int spanX = dragInfo.info.spanX; 64 int spanY = dragInfo.info.spanY; 65 66 for (int m = 0; m < spanX; m++) { 67 for (int n = 0; n < spanY; n++) { 68 69 fits = true; 70 int x0 = x - m; 71 int y0 = y - n; 72 73 if (x0 < 0 || y0 < 0) continue; 74 75 for (int i = x0; i < x0 + spanX; i++) { 76 if (!fits) break; 77 for (int j = y0; j < y0 + spanY; j++) { 78 if (i >= mCountX || j >= mCountY || mView.isOccupied(i, j)) { 79 fits = false; 80 break; 81 } 82 } 83 } 84 if (fits) { 85 return x0 + mCountX * y0; 86 } 87 } 88 } 89 return INVALID_POSITION; 90 } else { 91 // For an icon, we simply check the view directly below 92 View child = mView.getChildAt(x, y); 93 if (child == null || child == dragInfo.item) { 94 // Empty cell. Good for an icon or folder. 95 return id; 96 } else if (dragInfo.dragType != DragType.FOLDER) { 97 // For icons, we can consider cells that have another icon or a folder. 98 ItemInfo info = (ItemInfo) child.getTag(); 99 if (info instanceof AppInfo || info instanceof FolderInfo || 100 info instanceof ShortcutInfo) { 101 return id; 102 } 103 } 104 return INVALID_POSITION; 105 } 106 } 107 108 @Override 109 protected String getConfirmationForIconDrop(int id) { 110 int x = id % mView.getCountX(); 111 int y = id / mView.getCountX(); 112 LauncherAccessibilityDelegate.DragInfo dragInfo = mDelegate.getDragInfo(); 113 114 View child = mView.getChildAt(x, y); 115 if (child == null || child == dragInfo.item) { 116 return mContext.getString(R.string.item_moved); 117 } else { 118 ItemInfo info = (ItemInfo) child.getTag(); 119 if (info instanceof AppInfo || info instanceof ShortcutInfo) { 120 return mContext.getString(R.string.folder_created); 121 122 } else if (info instanceof FolderInfo) { 123 return mContext.getString(R.string.added_to_folder); 124 } 125 } 126 return ""; 127 } 128 129 @Override 130 protected String getLocationDescriptionForIconDrop(int id) { 131 int x = id % mView.getCountX(); 132 int y = id / mView.getCountX(); 133 LauncherAccessibilityDelegate.DragInfo dragInfo = mDelegate.getDragInfo(); 134 135 View child = mView.getChildAt(x, y); 136 if (child == null || child == dragInfo.item) { 137 if (mView.isHotseat()) { 138 return mContext.getString(R.string.move_to_hotseat_position, id + 1); 139 } else { 140 return mContext.getString(R.string.move_to_empty_cell, y + 1, x + 1); 141 } 142 } else { 143 ItemInfo info = (ItemInfo) child.getTag(); 144 if (info instanceof ShortcutInfo) { 145 return mContext.getString(R.string.create_folder_with, info.title); 146 } else if (info instanceof FolderInfo) { 147 if (TextUtils.isEmpty(info.title)) { 148 // Find the first item in the folder. 149 FolderInfo folder = (FolderInfo) info; 150 ShortcutInfo firstItem = null; 151 for (ShortcutInfo shortcut : folder.contents) { 152 if (firstItem == null || firstItem.rank > shortcut.rank) { 153 firstItem = shortcut; 154 } 155 } 156 157 if (firstItem != null) { 158 return mContext.getString(R.string.add_to_folder_with_app, firstItem.title); 159 } 160 } 161 return mContext.getString(R.string.add_to_folder, info.title); 162 } 163 } 164 return ""; 165 } 166 } 167