1 /* 2 * Copyright (C) 2018 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 package com.android.launcher3; 17 18 import android.util.Log; 19 import android.view.View; 20 import android.view.ViewGroup; 21 22 import com.android.launcher3.folder.Folder; 23 import com.android.launcher3.folder.FolderIcon; 24 import com.android.launcher3.model.data.ItemInfo; 25 import com.android.launcher3.touch.ItemLongClickListener; 26 27 public interface WorkspaceLayoutManager { 28 29 String TAG = "Launcher.Workspace"; 30 31 // The screen id used for the empty screen always present at the end. 32 int EXTRA_EMPTY_SCREEN_ID = -201; 33 // The is the first screen. It is always present, even if its empty. 34 int FIRST_SCREEN_ID = 0; 35 36 /** 37 * At bind time, we use the rank (screenId) to compute x and y for hotseat items. 38 * See {@link #addInScreen}. 39 */ addInScreenFromBind(View child, ItemInfo info)40 default void addInScreenFromBind(View child, ItemInfo info) { 41 int x = info.cellX; 42 int y = info.cellY; 43 if (info.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT 44 || info.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION) { 45 int screenId = info.screenId; 46 x = getHotseat().getCellXFromOrder(screenId); 47 y = getHotseat().getCellYFromOrder(screenId); 48 } 49 addInScreen(child, info.container, info.screenId, x, y, info.spanX, info.spanY); 50 } 51 52 /** 53 * Adds the specified child in the specified screen based on the {@param info} 54 * See {@link #addInScreen(View, int, int, int, int, int, int)}. 55 */ addInScreen(View child, ItemInfo info)56 default void addInScreen(View child, ItemInfo info) { 57 addInScreen(child, info.container, info.screenId, info.cellX, info.cellY, 58 info.spanX, info.spanY); 59 } 60 61 /** 62 * Adds the specified child in the specified screen. The position and dimension of 63 * the child are defined by x, y, spanX and spanY. 64 * 65 * @param child The child to add in one of the workspace's screens. 66 * @param screenId The screen in which to add the child. 67 * @param x The X position of the child in the screen's grid. 68 * @param y The Y position of the child in the screen's grid. 69 * @param spanX The number of cells spanned horizontally by the child. 70 * @param spanY The number of cells spanned vertically by the child. 71 */ addInScreen(View child, int container, int screenId, int x, int y, int spanX, int spanY)72 default void addInScreen(View child, int container, int screenId, int x, int y, 73 int spanX, int spanY) { 74 if (container == LauncherSettings.Favorites.CONTAINER_DESKTOP) { 75 if (getScreenWithId(screenId) == null) { 76 Log.e(TAG, "Skipping child, screenId " + screenId + " not found"); 77 // DEBUGGING - Print out the stack trace to see where we are adding from 78 new Throwable().printStackTrace(); 79 return; 80 } 81 } 82 if (screenId == EXTRA_EMPTY_SCREEN_ID) { 83 // This should never happen 84 throw new RuntimeException("Screen id should not be EXTRA_EMPTY_SCREEN_ID"); 85 } 86 87 final CellLayout layout; 88 if (container == LauncherSettings.Favorites.CONTAINER_HOTSEAT 89 || container == LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION) { 90 layout = getHotseat(); 91 92 // Hide folder title in the hotseat 93 if (child instanceof FolderIcon) { 94 ((FolderIcon) child).setTextVisible(false); 95 } 96 } else { 97 // Show folder title if not in the hotseat 98 if (child instanceof FolderIcon) { 99 ((FolderIcon) child).setTextVisible(true); 100 } 101 layout = getScreenWithId(screenId); 102 } 103 104 ViewGroup.LayoutParams genericLp = child.getLayoutParams(); 105 CellLayout.LayoutParams lp; 106 if (genericLp == null || !(genericLp instanceof CellLayout.LayoutParams)) { 107 lp = new CellLayout.LayoutParams(x, y, spanX, spanY); 108 } else { 109 lp = (CellLayout.LayoutParams) genericLp; 110 lp.cellX = x; 111 lp.cellY = y; 112 lp.cellHSpan = spanX; 113 lp.cellVSpan = spanY; 114 } 115 116 if (spanX < 0 && spanY < 0) { 117 lp.isLockedToGrid = false; 118 } 119 120 // Get the canonical child id to uniquely represent this view in this screen 121 ItemInfo info = (ItemInfo) child.getTag(); 122 int childId = info.getViewId(); 123 124 boolean markCellsAsOccupied = !(child instanceof Folder); 125 if (!layout.addViewToCellLayout(child, -1, childId, lp, markCellsAsOccupied)) { 126 // TODO: This branch occurs when the workspace is adding views 127 // outside of the defined grid 128 // maybe we should be deleting these items from the LauncherModel? 129 Log.e(TAG, "Failed to add to item at (" + lp.cellX + "," + lp.cellY + ") to CellLayout"); 130 } 131 132 child.setHapticFeedbackEnabled(false); 133 child.setOnLongClickListener(getWorkspaceChildOnLongClickListener()); 134 if (child instanceof DropTarget) { 135 onAddDropTarget((DropTarget) child); 136 } 137 } 138 getWorkspaceChildOnLongClickListener()139 default View.OnLongClickListener getWorkspaceChildOnLongClickListener() { 140 return ItemLongClickListener.INSTANCE_WORKSPACE; 141 } 142 getHotseat()143 Hotseat getHotseat(); 144 getScreenWithId(int screenId)145 CellLayout getScreenWithId(int screenId); 146 onAddDropTarget(DropTarget target)147 default void onAddDropTarget(DropTarget target) { } 148 } 149