Search in sources :

Example 1 with GridOccupancy

use of com.android.launcher3.util.GridOccupancy in project android_packages_apps_Launcher3 by crdroidandroid.

the class HotseatEduController method placeFoldersInWorkspace.

private int placeFoldersInWorkspace(ArrayDeque<FolderInfo> folders) {
    if (folders.isEmpty())
        return 0;
    Workspace workspace = mLauncher.getWorkspace();
    InvariantDeviceProfile idp = mLauncher.getDeviceProfile().inv;
    GridOccupancy[] occupancyList = new GridOccupancy[workspace.getChildCount()];
    for (int i = 0; i < occupancyList.length; i++) {
        occupancyList[i] = ((CellLayout) workspace.getChildAt(i)).cloneGridOccupancy();
    }
    // scan every screen to find available spots to place folders
    int occupancyIndex = 0;
    int[] itemXY = new int[2];
    while (occupancyIndex < occupancyList.length && !folders.isEmpty()) {
        GridOccupancy occupancy = occupancyList[occupancyIndex];
        if (occupancy.findVacantCell(itemXY, 1, 1)) {
            FolderInfo info = folders.poll();
            mLauncher.getModelWriter().moveItemInDatabase(info, LauncherSettings.Favorites.CONTAINER_DESKTOP, workspace.getScreenIdForPageIndex(occupancyIndex), itemXY[0], itemXY[1]);
            occupancy.markCells(info, true);
        } else {
            occupancyIndex++;
        }
    }
    if (folders.isEmpty())
        return workspace.getScreenIdForPageIndex(occupancyIndex);
    int screenId = LauncherSettings.Settings.call(mLauncher.getContentResolver(), LauncherSettings.Settings.METHOD_NEW_SCREEN_ID).getInt(LauncherSettings.Settings.EXTRA_VALUE);
    // if all screens are full and we still have folders left, put those on a new page
    FolderInfo folderInfo;
    int col = 0;
    while ((folderInfo = folders.poll()) != null) {
        mLauncher.getModelWriter().moveItemInDatabase(folderInfo, LauncherSettings.Favorites.CONTAINER_DESKTOP, screenId, col++, idp.numRows - 1);
    }
    mNewScreens = IntArray.wrap(screenId);
    return workspace.getPageCount();
}
Also used : InvariantDeviceProfile(com.android.launcher3.InvariantDeviceProfile) GridOccupancy(com.android.launcher3.util.GridOccupancy) FolderInfo(com.android.launcher3.model.data.FolderInfo) Workspace(com.android.launcher3.Workspace)

Example 2 with GridOccupancy

use of com.android.launcher3.util.GridOccupancy in project android_packages_apps_Launcher3 by crdroidandroid.

the class GridSizeMigrationTask method migrateWorkspace.

/**
 * @return true if any DB change was made
 */
protected boolean migrateWorkspace() throws Exception {
    IntArray allScreens = getWorkspaceScreenIds(mDb, mTableName);
    if (allScreens.isEmpty()) {
        throw new Exception("Unable to get workspace screens");
    }
    for (int i = 0; i < allScreens.size(); i++) {
        int screenId = allScreens.get(i);
        if (DEBUG) {
            Log.d(TAG, "Migrating " + screenId);
        }
        migrateScreen(screenId);
    }
    if (!mCarryOver.isEmpty()) {
        IntSparseArrayMap<DbEntry> itemMap = new IntSparseArrayMap<>();
        for (DbEntry e : mCarryOver) {
            itemMap.put(e.id, e);
        }
        do {
            // Some items are still remaining. Try adding a few new screens.
            // At every iteration, make sure that at least one item is removed from
            // {@link #mCarryOver}, to prevent an infinite loop. If no item could be removed,
            // break the loop and abort migration by throwing an exception.
            OptimalPlacementSolution placement = new OptimalPlacementSolution(new GridOccupancy(mTrgX, mTrgY), deepCopy(mCarryOver), 0, true);
            placement.find();
            if (placement.finalPlacedItems.size() > 0) {
                int newScreenId = LauncherSettings.Settings.call(mContext.getContentResolver(), LauncherSettings.Settings.METHOD_NEW_SCREEN_ID).getInt(EXTRA_VALUE);
                for (DbEntry item : placement.finalPlacedItems) {
                    if (!mCarryOver.remove(itemMap.get(item.id))) {
                        throw new Exception("Unable to find matching items");
                    }
                    item.screenId = newScreenId;
                    update(item);
                }
            } else {
                throw new Exception("None of the items can be placed on an empty screen");
            }
        } while (!mCarryOver.isEmpty());
    }
    return applyOperations();
}
Also used : IntArray(com.android.launcher3.util.IntArray) IntSparseArrayMap(com.android.launcher3.util.IntSparseArrayMap) GridOccupancy(com.android.launcher3.util.GridOccupancy) Utilities.parsePoint(com.android.launcher3.Utilities.parsePoint) Point(android.graphics.Point)

Example 3 with GridOccupancy

use of com.android.launcher3.util.GridOccupancy in project android_packages_apps_Launcher3 by crdroidandroid.

the class GridSizeMigrationTask method tryRemove.

/**
 * Tries the remove the provided row and column.
 *
 * @param items   all the items on the screen under operation
 * @param outLoss array of size 2. The first entry is filled with weight loss, and the second
 *                with the overall item movement.
 */
private ArrayList<DbEntry> tryRemove(int col, int row, int startY, ArrayList<DbEntry> items, float[] outLoss) {
    GridOccupancy occupied = new GridOccupancy(mTrgX, mTrgY);
    occupied.markCells(0, 0, mTrgX, startY, true);
    col = mShouldRemoveX ? col : Integer.MAX_VALUE;
    row = mShouldRemoveY ? row : Integer.MAX_VALUE;
    ArrayList<DbEntry> finalItems = new ArrayList<>();
    ArrayList<DbEntry> removedItems = new ArrayList<>();
    for (DbEntry item : items) {
        if ((item.cellX <= col && (item.spanX + item.cellX) > col) || (item.cellY <= row && (item.spanY + item.cellY) > row)) {
            removedItems.add(item);
            if (item.cellX >= col)
                item.cellX--;
            if (item.cellY >= row)
                item.cellY--;
        } else {
            if (item.cellX > col)
                item.cellX--;
            if (item.cellY > row)
                item.cellY--;
            finalItems.add(item);
            occupied.markCells(item, true);
        }
    }
    OptimalPlacementSolution placement = new OptimalPlacementSolution(occupied, removedItems, startY);
    placement.find();
    finalItems.addAll(placement.finalPlacedItems);
    outLoss[0] = placement.lowestWeightLoss;
    outLoss[1] = placement.lowestMoveCost;
    return finalItems;
}
Also used : ArrayList(java.util.ArrayList) GridOccupancy(com.android.launcher3.util.GridOccupancy)

Example 4 with GridOccupancy

use of com.android.launcher3.util.GridOccupancy in project android_packages_apps_Launcher3 by crdroidandroid.

the class GridSizeMigrationTask method migrateScreen.

/**
 * Migrate a particular screen id.
 * Strategy:
 *  1) For all possible combinations of row and column, pick the one which causes the least
 *    data loss: {@link #tryRemove(int, int, int, ArrayList, float[])}
 *  2) Maintain a list of all lost items before this screen, and add any new item lost from
 *    this screen to that list as well.
 *  3) If all those items from the above list can be placed on this screen, place them
 *    (otherwise they are placed on a new screen).
 */
protected void migrateScreen(int screenId) {
    // If we are migrating the first screen, do not touch the first row.
    int startY = (FeatureFlags.QSB_ON_FIRST_SCREEN && screenId == Workspace.FIRST_SCREEN_ID) ? 1 : 0;
    ArrayList<DbEntry> items = loadWorkspaceEntries(screenId);
    int removedCol = Integer.MAX_VALUE;
    int removedRow = Integer.MAX_VALUE;
    // removeWt represents the cost function for loss of items during migration, and moveWt
    // represents the cost function for repositioning the items. moveWt is only considered if
    // removeWt is same for two different configurations.
    // Start with Float.MAX_VALUE (assuming full data) and pick the configuration with least
    // cost.
    float removeWt = Float.MAX_VALUE;
    float moveWt = Float.MAX_VALUE;
    float[] outLoss = new float[2];
    ArrayList<DbEntry> finalItems = null;
    // Try removing all possible combinations
    for (int x = 0; x < mSrcX; x++) {
        // nicely aligned with hotseat.
        for (int y = mSrcY - 1; y >= startY; y--) {
            // Use a deep copy when trying out a particular combination as it can change
            // the underlying object.
            ArrayList<DbEntry> itemsOnScreen = tryRemove(x, y, startY, deepCopy(items), outLoss);
            if ((outLoss[0] < removeWt) || ((outLoss[0] == removeWt) && (outLoss[1] < moveWt))) {
                removeWt = outLoss[0];
                moveWt = outLoss[1];
                removedCol = mShouldRemoveX ? x : removedCol;
                removedRow = mShouldRemoveY ? y : removedRow;
                finalItems = itemsOnScreen;
            }
            // No need to loop over all rows, if a row removal is not needed.
            if (!mShouldRemoveY) {
                break;
            }
        }
        if (!mShouldRemoveX) {
            break;
        }
    }
    if (DEBUG) {
        Log.d(TAG, String.format("Removing row %d, column %d on screen %d", removedRow, removedCol, screenId));
    }
    IntSparseArrayMap<DbEntry> itemMap = new IntSparseArrayMap<>();
    for (DbEntry e : deepCopy(items)) {
        itemMap.put(e.id, e);
    }
    for (DbEntry item : finalItems) {
        DbEntry org = itemMap.get(item.id);
        itemMap.remove(item.id);
        // Check if update is required
        if (!item.columnsSame(org)) {
            update(item);
        }
    }
    // The remaining items in {@link #itemMap} are those which didn't get placed.
    for (DbEntry item : itemMap) {
        mCarryOver.add(item);
    }
    if (!mCarryOver.isEmpty() && removeWt == 0) {
        // No new items were removed in this step. Try placing all the items on this screen.
        GridOccupancy occupied = new GridOccupancy(mTrgX, mTrgY);
        occupied.markCells(0, 0, mTrgX, startY, true);
        for (DbEntry item : finalItems) {
            occupied.markCells(item, true);
        }
        OptimalPlacementSolution placement = new OptimalPlacementSolution(occupied, deepCopy(mCarryOver), startY, true);
        placement.find();
        if (placement.lowestWeightLoss == 0) {
            for (DbEntry item : placement.finalPlacedItems) {
                item.screenId = screenId;
                update(item);
            }
            mCarryOver.clear();
        }
    }
}
Also used : IntSparseArrayMap(com.android.launcher3.util.IntSparseArrayMap) GridOccupancy(com.android.launcher3.util.GridOccupancy) Utilities.parsePoint(com.android.launcher3.Utilities.parsePoint) Point(android.graphics.Point)

Example 5 with GridOccupancy

use of com.android.launcher3.util.GridOccupancy in project android_packages_apps_Launcher3 by crdroidandroid.

the class LoaderCursor method checkItemPlacement.

/**
 * check & update map of what's occupied; used to discard overlapping/invalid items
 */
protected boolean checkItemPlacement(ItemInfo item) {
    int containerIndex = item.screenId;
    if (item.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {
        final GridOccupancy hotseatOccupancy = occupied.get(LauncherSettings.Favorites.CONTAINER_HOTSEAT);
        if (item.screenId >= mIDP.numDatabaseHotseatIcons) {
            Log.e(TAG, "Error loading shortcut " + item + " into hotseat position " + item.screenId + ", position out of bounds: (0 to " + (mIDP.numDatabaseHotseatIcons - 1) + ")");
            return false;
        }
        if (hotseatOccupancy != null) {
            if (hotseatOccupancy.cells[(int) item.screenId][0]) {
                Log.e(TAG, "Error loading shortcut into hotseat " + item + " into position (" + item.screenId + ":" + item.cellX + "," + item.cellY + ") already occupied");
                return false;
            } else {
                hotseatOccupancy.cells[item.screenId][0] = true;
                return true;
            }
        } else {
            final GridOccupancy occupancy = new GridOccupancy(mIDP.numDatabaseHotseatIcons, 1);
            occupancy.cells[item.screenId][0] = true;
            occupied.put(LauncherSettings.Favorites.CONTAINER_HOTSEAT, occupancy);
            return true;
        }
    } else if (item.container != LauncherSettings.Favorites.CONTAINER_DESKTOP) {
        // Skip further checking if it is not the hotseat or workspace container
        return true;
    }
    final int countX = mIDP.numColumns;
    final int countY = mIDP.numRows;
    if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP && item.cellX < 0 || item.cellY < 0 || item.cellX + item.spanX > countX || item.cellY + item.spanY > countY) {
        Log.e(TAG, "Error loading shortcut " + item + " into cell (" + containerIndex + "-" + item.screenId + ":" + item.cellX + "," + item.cellY + ") out of screen bounds ( " + countX + "x" + countY + ")");
        return false;
    }
    if (!occupied.containsKey(item.screenId)) {
        GridOccupancy screen = new GridOccupancy(countX + 1, countY + 1);
        if (item.screenId == Workspace.FIRST_SCREEN_ID) {
            // Mark the first row as occupied (if the feature is enabled)
            // in order to account for the QSB.
            int spanY = FeatureFlags.EXPANDED_SMARTSPACE.get() ? 2 : 1;
            screen.markCells(0, 0, countX + 1, spanY, FeatureFlags.QSB_ON_FIRST_SCREEN);
        }
        occupied.put(item.screenId, screen);
    }
    final GridOccupancy occupancy = occupied.get(item.screenId);
    // Check if any workspace icons overlap with each other
    if (occupancy.isRegionVacant(item.cellX, item.cellY, item.spanX, item.spanY)) {
        occupancy.markCells(item, true);
        return true;
    } else {
        Log.e(TAG, "Error loading shortcut " + item + " into cell (" + containerIndex + "-" + item.screenId + ":" + item.cellX + "," + item.cellX + "," + item.spanX + "," + item.spanY + ") already occupied");
        return false;
    }
}
Also used : GridOccupancy(com.android.launcher3.util.GridOccupancy)

Aggregations

GridOccupancy (com.android.launcher3.util.GridOccupancy)12 Point (android.graphics.Point)5 SuppressLint (android.annotation.SuppressLint)3 Paint (android.graphics.Paint)3 Rect (android.graphics.Rect)2 View (android.view.View)2 InvariantDeviceProfile (com.android.launcher3.InvariantDeviceProfile)2 Utilities.parsePoint (com.android.launcher3.Utilities.parsePoint)2 ItemInfo (com.android.launcher3.model.data.ItemInfo)2 WorkspaceItemInfo (com.android.launcher3.model.data.WorkspaceItemInfo)2 CellAndSpan (com.android.launcher3.util.CellAndSpan)2 IntSparseArrayMap (com.android.launcher3.util.IntSparseArrayMap)2 LauncherAppWidgetHostView (com.android.launcher3.widget.LauncherAppWidgetHostView)2 Animator (android.animation.Animator)1 AnimatorListenerAdapter (android.animation.AnimatorListenerAdapter)1 ObjectAnimator (android.animation.ObjectAnimator)1 ValueAnimator (android.animation.ValueAnimator)1 AnimatorUpdateListener (android.animation.ValueAnimator.AnimatorUpdateListener)1 Intent (android.content.Intent)1 Workspace (com.android.launcher3.Workspace)1