Home | History | Annotate | Download | only in accessibility
      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