Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0a7ff878 authored by Thales Lima's avatar Thales Lima
Browse files

Create new logic for grid migration

Fixes 217564863
Test: manual, changing grids from Wallpaper & Style and checking against spec

Change-Id: I94cf77111b37810282527f1a212b6e4126d3eba1
parent e424f57d
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -256,6 +256,10 @@ public final class FeatureFlags {
            "ENABLE_SPLIT_FROM_WORKSPACE", true,
            "Enable initiating split screen from workspace.");

    public static final BooleanFlag ENABLE_NEW_MIGRATION_LOGIC = getDebugFlag(
            "ENABLE_NEW_MIGRATION_LOGIC", true,
            "Enable the new grid migration logic, keeping pages when src < dest");

    public static void initialize(Context context) {
        synchronized (sDebugFlags) {
            for (DebugFlag flag : sDebugFlags) {
+24 −7
Original line number Diff line number Diff line
@@ -38,7 +38,7 @@ import java.util.Objects;
/**
 * Utility class representing persisted grid properties.
 */
public class DeviceGridState {
public class DeviceGridState implements Comparable<DeviceGridState> {

    public static final String KEY_WORKSPACE_SIZE = "migration_src_workspace_size";
    public static final String KEY_HOTSEAT_COUNT = "migration_src_hotseat_count";
@@ -84,16 +84,16 @@ public class DeviceGridState {
     */
    public LauncherEvent getWorkspaceSizeEvent() {
        if (!TextUtils.isEmpty(mGridSizeString)) {
            switch (mGridSizeString.charAt(0)) {
                case '6':
            switch (getColumns()) {
                case 6:
                    return LAUNCHER_GRID_SIZE_6;
                case '5':
                case 5:
                    return LAUNCHER_GRID_SIZE_5;
                case '4':
                case 4:
                    return LAUNCHER_GRID_SIZE_4;
                case '3':
                case 3:
                    return LAUNCHER_GRID_SIZE_3;
                case '2':
                case 2:
                    return LAUNCHER_GRID_SIZE_2;
            }
        }
@@ -119,4 +119,21 @@ public class DeviceGridState {
        return mNumHotseat == other.mNumHotseat
                && Objects.equals(mGridSizeString, other.mGridSizeString);
    }

    public Integer getColumns() {
        return Integer.parseInt(String.valueOf(mGridSizeString.charAt(0)));
    }

    public Integer getRows() {
        return Integer.parseInt(String.valueOf(mGridSizeString.charAt(2)));
    }

    @Override
    public int compareTo(DeviceGridState other) {
        Integer size = getColumns() * getRows();
        Integer otherSize = other.getColumns() * other.getRows();

        return size.compareTo(otherSize);
    }

}
+24 −8
Original line number Diff line number Diff line
@@ -38,6 +38,7 @@ import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.Utilities;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.graphics.LauncherPreviewRenderer;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.pm.InstallSessionHelper;
@@ -225,13 +226,21 @@ public class GridSizeMigrationTaskV2 {
            screens.add(screenId);
        }

        boolean preservePages = false;
        if (screens.isEmpty() && FeatureFlags.ENABLE_NEW_MIGRATION_LOGIC.get()) {
            DeviceGridState srcDeviceState = new DeviceGridState(mContext);
            DeviceGridState destDeviceState = new DeviceGridState(idp);
            preservePages = destDeviceState.compareTo(srcDeviceState) >= 0
                    && destDeviceState.getColumns() - srcDeviceState.getColumns() <= 2;
        }

        // Then we place the items on the screens
        for (int screenId : screens) {
            if (DEBUG) {
                Log.d(TAG, "Migrating " + screenId);
            }
            GridPlacementSolution workspaceSolution = new GridPlacementSolution(mDb, mSrcReader,
                    mDestReader, mContext, screenId, mTrgX, mTrgY, mWorkspaceDiff);
                    mDestReader, mContext, screenId, mTrgX, mTrgY, mWorkspaceDiff, false);
            workspaceSolution.find();
            if (mWorkspaceDiff.isEmpty()) {
                break;
@@ -243,10 +252,12 @@ public class GridSizeMigrationTaskV2 {
        int screenId = mDestReader.mLastScreenId + 1;
        while (!mWorkspaceDiff.isEmpty()) {
            GridPlacementSolution workspaceSolution = new GridPlacementSolution(mDb, mSrcReader,
                    mDestReader, mContext, screenId, mTrgX, mTrgY, mWorkspaceDiff);
                    mDestReader, mContext, screenId, mTrgX, mTrgY, mWorkspaceDiff,
                    preservePages);
            workspaceSolution.find();
            screenId++;
        }

        return true;
    }

@@ -363,13 +374,15 @@ public class GridSizeMigrationTaskV2 {
        private final int mScreenId;
        private final int mTrgX;
        private final int mTrgY;
        private final List<DbEntry> mItemsToPlace;
        private final List<DbEntry> mSortedItemsToPlace;
        private final boolean mMatchingScreenIdOnly;

        private int mNextStartX;
        private int mNextStartY;

        GridPlacementSolution(SQLiteDatabase db, DbReader srcReader, DbReader destReader,
                Context context, int screenId, int trgX, int trgY, List<DbEntry> itemsToPlace) {
                Context context, int screenId, int trgX, int trgY, List<DbEntry> sortedItemsToPlace,
                boolean matchingScreenIdOnly) {
            mDb = db;
            mSrcReader = srcReader;
            mDestReader = destReader;
@@ -386,13 +399,16 @@ public class GridSizeMigrationTaskV2 {
                    mOccupied.markCells(entry, true);
                }
            }
            mItemsToPlace = itemsToPlace;
            mSortedItemsToPlace = sortedItemsToPlace;
            mMatchingScreenIdOnly = matchingScreenIdOnly;
        }

        public void find() {
            Iterator<DbEntry> iterator = mItemsToPlace.iterator();
            Iterator<DbEntry> iterator = mSortedItemsToPlace.iterator();
            while (iterator.hasNext()) {
                final DbEntry entry = iterator.next();
                if (mMatchingScreenIdOnly && entry.screenId < mScreenId) continue;
                if (mMatchingScreenIdOnly && entry.screenId > mScreenId) break;
                if (entry.minSpanX > mTrgX || entry.minSpanY > mTrgY) {
                    iterator.remove();
                    continue;
@@ -494,7 +510,7 @@ public class GridSizeMigrationTaskV2 {
        private final SQLiteDatabase mDb;
        private final String mTableName;
        private final Context mContext;
        private final HashSet<String> mValidPackages;
        private final Set<String> mValidPackages;
        private int mLastScreenId = -1;

        private final ArrayList<DbEntry> mHotseatEntries = new ArrayList<>();
@@ -503,7 +519,7 @@ public class GridSizeMigrationTaskV2 {
                new ArrayMap<>();

        DbReader(SQLiteDatabase db, String tableName, Context context,
                HashSet<String> validPackages) {
                Set<String> validPackages) {
            mDb = db;
            mTableName = tableName;
            mContext = context;
+0 −278
Original line number Diff line number Diff line
/*
 * Copyright (C) 2020 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.launcher3.model;

import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_DESKTOP;
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT;
import static com.android.launcher3.LauncherSettings.Favorites.TMP_CONTENT_URI;
import static com.android.launcher3.provider.LauncherDbUtils.dropTable;
import static com.android.launcher3.util.LauncherModelHelper.APP_ICON;
import static com.android.launcher3.util.LauncherModelHelper.DESKTOP;
import static com.android.launcher3.util.LauncherModelHelper.HOTSEAT;
import static com.android.launcher3.util.LauncherModelHelper.SHORTCUT;
import static com.android.launcher3.util.LauncherModelHelper.TEST_PACKAGE;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.graphics.Point;
import android.os.Process;

import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;

import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.pm.UserCache;
import com.android.launcher3.util.LauncherModelHelper;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;

import java.util.HashMap;
import java.util.HashSet;

/** Unit tests for {@link GridSizeMigrationTaskV2} */
@SmallTest
@RunWith(AndroidJUnit4.class)
public class GridSizeMigrationTaskV2Test {

    private LauncherModelHelper mModelHelper;
    private Context mContext;
    private SQLiteDatabase mDb;

    private HashSet<String> mValidPackages;
    private InvariantDeviceProfile mIdp;

    private final String testPackage1 = "com.android.launcher3.validpackage1";
    private final String testPackage2 = "com.android.launcher3.validpackage2";
    private final String testPackage3 = "com.android.launcher3.validpackage3";
    private final String testPackage4 = "com.android.launcher3.validpackage4";
    private final String testPackage5 = "com.android.launcher3.validpackage5";
    private final String testPackage6 = "com.android.launcher3.validpackage6";
    private final String testPackage7 = "com.android.launcher3.validpackage7";
    private final String testPackage8 = "com.android.launcher3.validpackage8";
    private final String testPackage9 = "com.android.launcher3.validpackage9";
    private final String testPackage10 = "com.android.launcher3.validpackage10";

    @Before
    public void setUp() {
        mModelHelper = new LauncherModelHelper();
        mContext = mModelHelper.sandboxContext;
        mDb = mModelHelper.provider.getDb();

        mValidPackages = new HashSet<>();
        mValidPackages.add(TEST_PACKAGE);
        mValidPackages.add(testPackage1);
        mValidPackages.add(testPackage2);
        mValidPackages.add(testPackage3);
        mValidPackages.add(testPackage4);
        mValidPackages.add(testPackage5);
        mValidPackages.add(testPackage6);
        mValidPackages.add(testPackage7);
        mValidPackages.add(testPackage8);
        mValidPackages.add(testPackage9);
        mValidPackages.add(testPackage10);

        mIdp = InvariantDeviceProfile.INSTANCE.get(mContext);

        long userSerial = UserCache.INSTANCE.get(mContext).getSerialNumberForUser(
                Process.myUserHandle());
        dropTable(mDb, LauncherSettings.Favorites.TMP_TABLE);
        LauncherSettings.Favorites.addTableToDb(mDb, userSerial, false,
                LauncherSettings.Favorites.TMP_TABLE);
    }

    @After
    public void tearDown() {
        mModelHelper.destroy();
    }

    @Test
    public void testMigration() throws Exception {
        int[] srcHotseatItems = {
                mModelHelper.addItem(APP_ICON, 0, HOTSEAT, 0, 0, testPackage1, 1, TMP_CONTENT_URI),
                mModelHelper.addItem(SHORTCUT, 1, HOTSEAT, 0, 0, testPackage2, 2, TMP_CONTENT_URI),
                -1,
                mModelHelper.addItem(SHORTCUT, 3, HOTSEAT, 0, 0, testPackage3, 3, TMP_CONTENT_URI),
                mModelHelper.addItem(APP_ICON, 4, HOTSEAT, 0, 0, testPackage4, 4, TMP_CONTENT_URI),
        };
        mModelHelper.addItem(APP_ICON, 0, DESKTOP, 2, 2, testPackage5, 5, TMP_CONTENT_URI);
        mModelHelper.addItem(APP_ICON, 0, DESKTOP, 2, 3, testPackage6, 6, TMP_CONTENT_URI);
        mModelHelper.addItem(APP_ICON, 0, DESKTOP, 4, 1, testPackage8, 8, TMP_CONTENT_URI);
        mModelHelper.addItem(APP_ICON, 0, DESKTOP, 4, 2, testPackage9, 9, TMP_CONTENT_URI);
        mModelHelper.addItem(APP_ICON, 0, DESKTOP, 4, 3, testPackage10, 10, TMP_CONTENT_URI);

        int[] destHotseatItems = {
                -1,
                mModelHelper.addItem(SHORTCUT, 1, HOTSEAT, 0, 0, testPackage2),
                -1,
        };
        mModelHelper.addItem(APP_ICON, 0, DESKTOP, 2, 2, testPackage7);

        mIdp.numDatabaseHotseatIcons = 4;
        mIdp.numColumns = 4;
        mIdp.numRows = 4;
        GridSizeMigrationTaskV2.DbReader srcReader = new GridSizeMigrationTaskV2.DbReader(mDb,
                LauncherSettings.Favorites.TMP_TABLE, mContext, mValidPackages);
        GridSizeMigrationTaskV2.DbReader destReader = new GridSizeMigrationTaskV2.DbReader(mDb,
                LauncherSettings.Favorites.TABLE_NAME, mContext, mValidPackages);
        GridSizeMigrationTaskV2 task = new GridSizeMigrationTaskV2(mContext, mDb, srcReader,
                destReader, mIdp.numDatabaseHotseatIcons, new Point(mIdp.numColumns, mIdp.numRows));
        task.migrate(mIdp);

        // Check hotseat items
        Cursor c = mContext.getContentResolver().query(LauncherSettings.Favorites.CONTENT_URI,
                new String[]{LauncherSettings.Favorites.SCREEN, LauncherSettings.Favorites.INTENT},
                "container=" + CONTAINER_HOTSEAT, null, LauncherSettings.Favorites.SCREEN, null);
        assertEquals(c.getCount(), mIdp.numDatabaseHotseatIcons);
        int screenIndex = c.getColumnIndex(LauncherSettings.Favorites.SCREEN);
        int intentIndex = c.getColumnIndex(LauncherSettings.Favorites.INTENT);
        c.moveToNext();
        assertEquals(c.getInt(screenIndex), 0);
        assertTrue(c.getString(intentIndex).contains(testPackage1));
        c.moveToNext();
        assertEquals(c.getInt(screenIndex), 1);
        assertTrue(c.getString(intentIndex).contains(testPackage2));
        c.moveToNext();
        assertEquals(c.getInt(screenIndex), 2);
        assertTrue(c.getString(intentIndex).contains(testPackage3));
        c.moveToNext();
        assertEquals(c.getInt(screenIndex), 3);
        assertTrue(c.getString(intentIndex).contains(testPackage4));
        c.close();

        // Check workspace items
        c = mContext.getContentResolver().query(LauncherSettings.Favorites.CONTENT_URI,
                new String[]{LauncherSettings.Favorites.CELLX, LauncherSettings.Favorites.CELLY,
                        LauncherSettings.Favorites.INTENT},
                "container=" + CONTAINER_DESKTOP, null, null, null);
        intentIndex = c.getColumnIndex(LauncherSettings.Favorites.INTENT);
        int cellXIndex = c.getColumnIndex(LauncherSettings.Favorites.CELLX);
        int cellYIndex = c.getColumnIndex(LauncherSettings.Favorites.CELLY);

        HashMap<String, Point> locMap = new HashMap<>();
        while (c.moveToNext()) {
            locMap.put(
                    Intent.parseUri(c.getString(intentIndex), 0).getPackage(),
                    new Point(c.getInt(cellXIndex), c.getInt(cellYIndex)));
        }
        c.close();

        assertEquals(locMap.size(), 6);
        assertEquals(new Point(0, 2), locMap.get(testPackage8));
        assertEquals(new Point(0, 3), locMap.get(testPackage6));
        assertEquals(new Point(1, 3), locMap.get(testPackage10));
        assertEquals(new Point(2, 3), locMap.get(testPackage5));
        assertEquals(new Point(3, 3), locMap.get(testPackage9));
    }

    @Test
    public void migrateToLargerHotseat() {
        int[] srcHotseatItems = {
                mModelHelper.addItem(APP_ICON, 0, HOTSEAT, 0, 0, testPackage1, 1, TMP_CONTENT_URI),
                mModelHelper.addItem(SHORTCUT, 1, HOTSEAT, 0, 0, testPackage2, 2, TMP_CONTENT_URI),
                mModelHelper.addItem(APP_ICON, 2, HOTSEAT, 0, 0, testPackage3, 3, TMP_CONTENT_URI),
                mModelHelper.addItem(SHORTCUT, 3, HOTSEAT, 0, 0, testPackage4, 4, TMP_CONTENT_URI),
        };

        int numSrcDatabaseHotseatIcons = srcHotseatItems.length;
        mIdp.numDatabaseHotseatIcons = 6;
        mIdp.numColumns = 4;
        mIdp.numRows = 4;
        GridSizeMigrationTaskV2.DbReader srcReader = new GridSizeMigrationTaskV2.DbReader(mDb,
                LauncherSettings.Favorites.TMP_TABLE, mContext, mValidPackages);
        GridSizeMigrationTaskV2.DbReader destReader = new GridSizeMigrationTaskV2.DbReader(mDb,
                LauncherSettings.Favorites.TABLE_NAME, mContext, mValidPackages);
        GridSizeMigrationTaskV2 task = new GridSizeMigrationTaskV2(mContext, mDb, srcReader,
                destReader, mIdp.numDatabaseHotseatIcons, new Point(mIdp.numColumns, mIdp.numRows));
        task.migrate(mIdp);

        // Check hotseat items
        Cursor c = mContext.getContentResolver().query(LauncherSettings.Favorites.CONTENT_URI,
                new String[]{LauncherSettings.Favorites.SCREEN, LauncherSettings.Favorites.INTENT},
                "container=" + CONTAINER_HOTSEAT, null, LauncherSettings.Favorites.SCREEN, null);
        assertEquals(c.getCount(), numSrcDatabaseHotseatIcons);
        int screenIndex = c.getColumnIndex(LauncherSettings.Favorites.SCREEN);
        int intentIndex = c.getColumnIndex(LauncherSettings.Favorites.INTENT);
        c.moveToNext();
        assertEquals(c.getInt(screenIndex), 0);
        assertTrue(c.getString(intentIndex).contains(testPackage1));
        c.moveToNext();
        assertEquals(c.getInt(screenIndex), 1);
        assertTrue(c.getString(intentIndex).contains(testPackage2));
        c.moveToNext();
        assertEquals(c.getInt(screenIndex), 2);
        assertTrue(c.getString(intentIndex).contains(testPackage3));
        c.moveToNext();
        assertEquals(c.getInt(screenIndex), 3);
        assertTrue(c.getString(intentIndex).contains(testPackage4));

        c.close();
    }

    @Test
    public void migrateFromLargerHotseat() {
        int[] srcHotseatItems = {
                mModelHelper.addItem(APP_ICON, 0, HOTSEAT, 0, 0, testPackage1, 1, TMP_CONTENT_URI),
                -1,
                mModelHelper.addItem(SHORTCUT, 2, HOTSEAT, 0, 0, testPackage2, 2, TMP_CONTENT_URI),
                mModelHelper.addItem(APP_ICON, 3, HOTSEAT, 0, 0, testPackage3, 3, TMP_CONTENT_URI),
                mModelHelper.addItem(SHORTCUT, 4, HOTSEAT, 0, 0, testPackage4, 4, TMP_CONTENT_URI),
                mModelHelper.addItem(APP_ICON, 5, HOTSEAT, 0, 0, testPackage5, 5, TMP_CONTENT_URI),
        };

        mIdp.numDatabaseHotseatIcons = 4;
        mIdp.numColumns = 4;
        mIdp.numRows = 4;
        GridSizeMigrationTaskV2.DbReader srcReader = new GridSizeMigrationTaskV2.DbReader(mDb,
                LauncherSettings.Favorites.TMP_TABLE, mContext, mValidPackages);
        GridSizeMigrationTaskV2.DbReader destReader = new GridSizeMigrationTaskV2.DbReader(mDb,
                LauncherSettings.Favorites.TABLE_NAME, mContext, mValidPackages);
        GridSizeMigrationTaskV2 task = new GridSizeMigrationTaskV2(mContext, mDb, srcReader,
                destReader, mIdp.numDatabaseHotseatIcons, new Point(mIdp.numColumns, mIdp.numRows));
        task.migrate(mIdp);

        // Check hotseat items
        Cursor c = mContext.getContentResolver().query(LauncherSettings.Favorites.CONTENT_URI,
                new String[]{LauncherSettings.Favorites.SCREEN, LauncherSettings.Favorites.INTENT},
                "container=" + CONTAINER_HOTSEAT, null, LauncherSettings.Favorites.SCREEN, null);
        assertEquals(c.getCount(), mIdp.numDatabaseHotseatIcons);
        int screenIndex = c.getColumnIndex(LauncherSettings.Favorites.SCREEN);
        int intentIndex = c.getColumnIndex(LauncherSettings.Favorites.INTENT);
        c.moveToNext();
        assertEquals(c.getInt(screenIndex), 0);
        assertTrue(c.getString(intentIndex).contains(testPackage1));
        c.moveToNext();
        assertEquals(c.getInt(screenIndex), 1);
        assertTrue(c.getString(intentIndex).contains(testPackage2));
        c.moveToNext();
        assertEquals(c.getInt(screenIndex), 2);
        assertTrue(c.getString(intentIndex).contains(testPackage3));
        c.moveToNext();
        assertEquals(c.getInt(screenIndex), 3);
        assertTrue(c.getString(intentIndex).contains(testPackage4));

        c.close();
    }
}
+500 −0

File added.

Preview size limit exceeded, changes collapsed.