Search in sources :

Example 21 with IntSparseArrayMap

use of com.android.launcher3.util.IntSparseArrayMap in project Neo-Launcher by NeoApplications.

the class ImportDataTask method importWorkspaceItems.

/**
 * 1) Imports all the workspace entries from the source provider.
 * 2) For home screen entries, maps the screen id based on {@param screenIdMap}
 * 3) In the end fills any holes in hotseat with items from default hotseat layout.
 */
private void importWorkspaceItems() throws Exception {
    String profileId = Long.toString(UserManagerCompat.getInstance(mContext).getSerialNumberForUser(Process.myUserHandle()));
    boolean createEmptyRowOnFirstScreen;
    if (FeatureFlags.QSB_ON_FIRST_SCREEN) {
        try (Cursor c = mContext.getContentResolver().query(mOtherFavoritesUri, null, // get items on the first row of the first screen (min screen id)
        "profileId = ? AND container = -100 AND cellY = 0 AND screen = " + "(SELECT MIN(screen) FROM favorites WHERE container = -100)", new String[] { profileId }, null)) {
            // First row of first screen is not empty
            createEmptyRowOnFirstScreen = c.moveToNext();
        }
    } else {
        createEmptyRowOnFirstScreen = false;
    }
    ArrayList<ContentProviderOperation> insertOperations = new ArrayList<>(BATCH_INSERT_SIZE);
    // Set of package names present in hotseat
    final HashSet<String> hotseatTargetApps = new HashSet<>();
    int maxId = 0;
    // Number of imported items on workspace and hotseat
    int totalItemsOnWorkspace = 0;
    try (Cursor c = mContext.getContentResolver().query(mOtherFavoritesUri, null, // Only migrate the primary user
    Favorites.PROFILE_ID + " = ?", new String[] { profileId }, // before the corresponding items.
    Favorites.CONTAINER + " , " + Favorites.SCREEN)) {
        // various columns we expect to exist.
        final int idIndex = c.getColumnIndexOrThrow(Favorites._ID);
        final int intentIndex = c.getColumnIndexOrThrow(Favorites.INTENT);
        final int titleIndex = c.getColumnIndexOrThrow(Favorites.TITLE);
        final int containerIndex = c.getColumnIndexOrThrow(Favorites.CONTAINER);
        final int itemTypeIndex = c.getColumnIndexOrThrow(Favorites.ITEM_TYPE);
        final int widgetProviderIndex = c.getColumnIndexOrThrow(Favorites.APPWIDGET_PROVIDER);
        final int screenIndex = c.getColumnIndexOrThrow(Favorites.SCREEN);
        final int cellXIndex = c.getColumnIndexOrThrow(Favorites.CELLX);
        final int cellYIndex = c.getColumnIndexOrThrow(Favorites.CELLY);
        final int spanXIndex = c.getColumnIndexOrThrow(Favorites.SPANX);
        final int spanYIndex = c.getColumnIndexOrThrow(Favorites.SPANY);
        final int rankIndex = c.getColumnIndexOrThrow(Favorites.RANK);
        final int iconIndex = c.getColumnIndexOrThrow(Favorites.ICON);
        final int iconPackageIndex = c.getColumnIndexOrThrow(Favorites.ICON_PACKAGE);
        final int iconResourceIndex = c.getColumnIndexOrThrow(Favorites.ICON_RESOURCE);
        SparseBooleanArray mValidFolders = new SparseBooleanArray();
        ContentValues values = new ContentValues();
        Integer firstScreenId = null;
        while (c.moveToNext()) {
            values.clear();
            int id = c.getInt(idIndex);
            maxId = Math.max(maxId, id);
            int type = c.getInt(itemTypeIndex);
            int container = c.getInt(containerIndex);
            int screen = c.getInt(screenIndex);
            int cellX = c.getInt(cellXIndex);
            int cellY = c.getInt(cellYIndex);
            int spanX = c.getInt(spanXIndex);
            int spanY = c.getInt(spanYIndex);
            switch(container) {
                case Favorites.CONTAINER_DESKTOP:
                    {
                        if (screen < Workspace.FIRST_SCREEN_ID) {
                            FileLog.d(TAG, String.format("Skipping item %d, type %d not on a valid screen %d", id, type, screen));
                            continue;
                        }
                        if (firstScreenId == null) {
                            firstScreenId = screen;
                        }
                        // Reset the screen to 0-index value
                        if (createEmptyRowOnFirstScreen && firstScreenId.equals(screen)) {
                            // Shift items by 1.
                            cellY++;
                            // Change the screen id to first screen
                            screen = Workspace.FIRST_SCREEN_ID;
                        }
                        mMaxGridSizeX = Math.max(mMaxGridSizeX, cellX + spanX);
                        mMaxGridSizeY = Math.max(mMaxGridSizeY, cellY + spanY);
                        break;
                    }
                case Favorites.CONTAINER_HOTSEAT:
                    {
                        mHotseatSize = Math.max(mHotseatSize, screen + 1);
                        break;
                    }
                default:
                    if (!mValidFolders.get(container)) {
                        FileLog.d(TAG, String.format("Skipping item %d, type %d not in a valid folder %d", id, type, container));
                        continue;
                    }
            }
            Intent intent = null;
            switch(type) {
                case Favorites.ITEM_TYPE_FOLDER:
                    {
                        mValidFolders.put(id, true);
                        // Use a empty intent to indicate a folder.
                        intent = new Intent();
                        break;
                    }
                case Favorites.ITEM_TYPE_APPWIDGET:
                    {
                        values.put(Favorites.RESTORED, LauncherAppWidgetInfo.FLAG_ID_NOT_VALID | LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY | LauncherAppWidgetInfo.FLAG_UI_NOT_READY);
                        values.put(Favorites.APPWIDGET_PROVIDER, c.getString(widgetProviderIndex));
                        break;
                    }
                case Favorites.ITEM_TYPE_SHORTCUT:
                case Favorites.ITEM_TYPE_APPLICATION:
                    {
                        intent = Intent.parseUri(c.getString(intentIndex), 0);
                        if (PackageManagerHelper.isLauncherAppTarget(intent)) {
                            type = Favorites.ITEM_TYPE_APPLICATION;
                        } else {
                            values.put(Favorites.ICON_PACKAGE, c.getString(iconPackageIndex));
                            values.put(Favorites.ICON_RESOURCE, c.getString(iconResourceIndex));
                        }
                        values.put(Favorites.ICON, c.getBlob(iconIndex));
                        values.put(Favorites.INTENT, intent.toUri(0));
                        values.put(Favorites.RANK, c.getInt(rankIndex));
                        values.put(Favorites.RESTORED, 1);
                        break;
                    }
                default:
                    FileLog.d(TAG, String.format("Skipping item %d, not a valid type %d", id, type));
                    continue;
            }
            if (container == Favorites.CONTAINER_HOTSEAT) {
                if (intent == null) {
                    FileLog.d(TAG, String.format("Skipping item %d, null intent on hotseat", id));
                    continue;
                }
                if (intent.getComponent() != null) {
                    intent.setPackage(intent.getComponent().getPackageName());
                }
                hotseatTargetApps.add(getPackage(intent));
            }
            values.put(Favorites._ID, id);
            values.put(Favorites.ITEM_TYPE, type);
            values.put(Favorites.CONTAINER, container);
            values.put(Favorites.SCREEN, screen);
            values.put(Favorites.CELLX, cellX);
            values.put(Favorites.CELLY, cellY);
            values.put(Favorites.SPANX, spanX);
            values.put(Favorites.SPANY, spanY);
            values.put(Favorites.TITLE, c.getString(titleIndex));
            insertOperations.add(ContentProviderOperation.newInsert(Favorites.CONTENT_URI).withValues(values).build());
            if (container < 0) {
                totalItemsOnWorkspace++;
            }
            if (insertOperations.size() >= BATCH_INSERT_SIZE) {
                mContext.getContentResolver().applyBatch(LauncherProvider.AUTHORITY, insertOperations);
                insertOperations.clear();
            }
        }
    }
    FileLog.d(TAG, totalItemsOnWorkspace + " items imported from external source");
    if (totalItemsOnWorkspace < MIN_ITEM_COUNT_FOR_SUCCESSFUL_MIGRATION) {
        throw new Exception("Insufficient data");
    }
    if (!insertOperations.isEmpty()) {
        mContext.getContentResolver().applyBatch(LauncherProvider.AUTHORITY, insertOperations);
        insertOperations.clear();
    }
    IntSparseArrayMap<Object> hotseatItems = GridSizeMigrationTask.removeBrokenHotseatItems(mContext);
    int myHotseatCount = LauncherAppState.getIDP(mContext).numHotseatIcons;
    if (hotseatItems.size() < myHotseatCount) {
        // Insufficient hotseat items. Add a few more.
        HotseatParserCallback parserCallback = new HotseatParserCallback(hotseatTargetApps, hotseatItems, insertOperations, maxId + 1, myHotseatCount);
        new HotseatLayoutParser(mContext, parserCallback).loadLayout(null, new IntArray());
        mHotseatSize = hotseatItems.keyAt(hotseatItems.size() - 1) + 1;
        if (!insertOperations.isEmpty()) {
            mContext.getContentResolver().applyBatch(LauncherProvider.AUTHORITY, insertOperations);
        }
    }
}
Also used : ContentValues(android.content.ContentValues) ContentProviderOperation(android.content.ContentProviderOperation) ArrayList(java.util.ArrayList) Intent(android.content.Intent) Cursor(android.database.Cursor) URISyntaxException(java.net.URISyntaxException) IntArray(com.android.launcher3.util.IntArray) SparseBooleanArray(android.util.SparseBooleanArray) HashSet(java.util.HashSet)

Example 22 with IntSparseArrayMap

use of com.android.launcher3.util.IntSparseArrayMap in project Neo-Launcher by NeoApplications.

the class GridSizeMigrationTask method migrateWorkspace.

/**
 * @return true if any DB change was made
 */
protected boolean migrateWorkspace() throws Exception {
    IntArray allScreens = getWorkspaceScreenIds(mDb);
    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 23 with IntSparseArrayMap

use of com.android.launcher3.util.IntSparseArrayMap in project Neo-Launcher by NeoApplications.

the class GridSizeMigrationTask method removeBrokenHotseatItems.

/**
 * Removes any broken item from the hotseat.
 *
 * @return a map with occupied hotseat position set to non-null value.
 */
public static IntSparseArrayMap<Object> removeBrokenHotseatItems(Context context) throws Exception {
    try (SQLiteTransaction transaction = (SQLiteTransaction) Settings.call(context.getContentResolver(), Settings.METHOD_NEW_TRANSACTION).getBinder(Settings.EXTRA_VALUE)) {
        GridSizeMigrationTask task = new GridSizeMigrationTask(context, transaction.getDb(), getValidPackages(context), Integer.MAX_VALUE, Integer.MAX_VALUE);
        // Load all the valid entries
        ArrayList<DbEntry> items = task.loadHotseatEntries();
        // Delete any entry marked for deletion by above load.
        task.applyOperations();
        IntSparseArrayMap<Object> positions = new IntSparseArrayMap<>();
        for (DbEntry item : items) {
            positions.put(item.screenId, item);
        }
        transaction.commit();
        return positions;
    }
}
Also used : IntSparseArrayMap(com.android.launcher3.util.IntSparseArrayMap) SQLiteTransaction(com.android.launcher3.provider.LauncherDbUtils.SQLiteTransaction)

Example 24 with IntSparseArrayMap

use of com.android.launcher3.util.IntSparseArrayMap in project Neo-Launcher by NeoApplications.

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 25 with IntSparseArrayMap

use of com.android.launcher3.util.IntSparseArrayMap in project Neo-Launcher by NeoApplications.

the class BgDataModel method dumpProto.

private synchronized void dumpProto(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
    // Add top parent nodes. (L1)
    DumpTargetWrapper hotseat = new DumpTargetWrapper(ContainerType.HOTSEAT, 0);
    IntSparseArrayMap<DumpTargetWrapper> workspaces = new IntSparseArrayMap<>();
    IntArray workspaceScreens = collectWorkspaceScreens();
    for (int i = 0; i < workspaceScreens.size(); i++) {
        workspaces.put(workspaceScreens.get(i), new DumpTargetWrapper(ContainerType.WORKSPACE, i));
    }
    DumpTargetWrapper dtw;
    // Add non leaf / non top nodes (L2)
    for (int i = 0; i < folders.size(); i++) {
        FolderInfo fInfo = folders.valueAt(i);
        dtw = new DumpTargetWrapper(ContainerType.FOLDER, folders.size());
        dtw.writeToDumpTarget(fInfo);
        for (WorkspaceItemInfo sInfo : fInfo.contents) {
            DumpTargetWrapper child = new DumpTargetWrapper(sInfo);
            child.writeToDumpTarget(sInfo);
            dtw.add(child);
        }
        if (fInfo.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {
            hotseat.add(dtw);
        } else if (fInfo.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {
            workspaces.get(fInfo.screenId).add(dtw);
        }
    }
    // Add leaf nodes (L3): *Info
    for (int i = 0; i < workspaceItems.size(); i++) {
        ItemInfo info = workspaceItems.get(i);
        if (info instanceof FolderInfo) {
            continue;
        }
        dtw = new DumpTargetWrapper(info);
        dtw.writeToDumpTarget(info);
        if (info.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {
            hotseat.add(dtw);
        } else if (info.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {
            workspaces.get(info.screenId).add(dtw);
        }
    }
    for (int i = 0; i < appWidgets.size(); i++) {
        ItemInfo info = appWidgets.get(i);
        dtw = new DumpTargetWrapper(info);
        dtw.writeToDumpTarget(info);
        if (info.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {
            hotseat.add(dtw);
        } else if (info.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {
            workspaces.get(info.screenId).add(dtw);
        }
    }
    // Traverse target wrapper
    ArrayList<DumpTarget> targetList = new ArrayList<>();
    targetList.addAll(hotseat.getFlattenedList());
    for (int i = 0; i < workspaces.size(); i++) {
        targetList.addAll(workspaces.valueAt(i).getFlattenedList());
    }
    if (Arrays.asList(args).contains("--debug")) {
        for (int i = 0; i < targetList.size(); i++) {
            writer.println(prefix + DumpTargetWrapper.getDumpTargetStr(targetList.get(i)));
        }
        return;
    } else {
        LauncherDumpProto.LauncherImpression proto = new LauncherDumpProto.LauncherImpression();
        proto.targets = new DumpTarget[targetList.size()];
        for (int i = 0; i < targetList.size(); i++) {
            proto.targets[i] = targetList.get(i);
        }
        FileOutputStream fos = new FileOutputStream(fd);
        try {
            fos.write(MessageNano.toByteArray(proto));
            Log.d(TAG, MessageNano.toByteArray(proto).length + "Bytes");
        } catch (IOException e) {
            Log.e(TAG, "Exception writing dumpsys --proto", e);
        }
    }
}
Also used : DumpTarget(com.android.launcher3.model.nano.LauncherDumpProto.DumpTarget) WorkspaceItemInfo(com.android.launcher3.WorkspaceItemInfo) ItemInfo(com.android.launcher3.ItemInfo) IntSparseArrayMap(com.android.launcher3.util.IntSparseArrayMap) DumpTargetWrapper(com.android.launcher3.logging.DumpTargetWrapper) ArrayList(java.util.ArrayList) IOException(java.io.IOException) FolderInfo(com.android.launcher3.FolderInfo) LauncherDumpProto(com.android.launcher3.model.nano.LauncherDumpProto) IntArray(com.android.launcher3.util.IntArray) FileOutputStream(java.io.FileOutputStream) WorkspaceItemInfo(com.android.launcher3.WorkspaceItemInfo)

Aggregations

IntArray (com.android.launcher3.util.IntArray)14 IntSparseArrayMap (com.android.launcher3.util.IntSparseArrayMap)14 ItemInfo (com.android.launcher3.model.data.ItemInfo)11 WorkspaceItemInfo (com.android.launcher3.model.data.WorkspaceItemInfo)11 FolderInfo (com.android.launcher3.model.data.FolderInfo)10 InstanceId (com.android.launcher3.logging.InstanceId)9 InstanceIdSequence (com.android.launcher3.logging.InstanceIdSequence)9 Point (android.graphics.Point)8 PredictionHelper.getAppTargetFromItemInfo (com.android.launcher3.model.PredictionHelper.getAppTargetFromItemInfo)8 ArrayList (java.util.ArrayList)8 Before (org.junit.Before)7 Utilities.parsePoint (com.android.launcher3.Utilities.parsePoint)6 GridOccupancy (com.android.launcher3.util.GridOccupancy)6 LauncherModelHelper (com.android.launcher3.util.LauncherModelHelper)6 SharedPreferences (android.content.SharedPreferences)5 WorkerThread (androidx.annotation.WorkerThread)5 HashSet (java.util.HashSet)5 StatsEvent (android.util.StatsEvent)4 LauncherAtom (com.android.launcher3.logger.LauncherAtom)4 ContentProviderOperation (android.content.ContentProviderOperation)3