From c5939393a92e3a07fbd6e17527b8b2a1d108f1d7 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Fri, 7 Dec 2018 11:43:47 -0800 Subject: Bye bye workspace screens table Removing a separate table for workspace screens. List of screens are automatically parsed using the items in the favorites DB. Order of the screen based on the screen id and rearranging screens is no longer supported. In case the screens need to be rearranged, all the items in the favorites db will need to be updated with new screen ids. This makes backing up the DB (in the same database) easier as only one table needs to be duplicates. Change-Id: I8ba947a898f637d780e2f49925e78604263126e8 --- robolectric_tests/resources/db_schema_v10.json | 4 + .../launcher3/model/AddWorkspaceItemsTaskTest.java | 48 ++--- .../launcher3/model/DbDowngradeHelperTest.java | 209 +++++++++++++++++++++ .../launcher3/model/GridSizeMigrationTaskTest.java | 12 +- 4 files changed, 235 insertions(+), 38 deletions(-) create mode 100644 robolectric_tests/resources/db_schema_v10.json create mode 100644 robolectric_tests/src/com/android/launcher3/model/DbDowngradeHelperTest.java (limited to 'robolectric_tests') diff --git a/robolectric_tests/resources/db_schema_v10.json b/robolectric_tests/resources/db_schema_v10.json new file mode 100644 index 000000000..a5e290ef7 --- /dev/null +++ b/robolectric_tests/resources/db_schema_v10.json @@ -0,0 +1,4 @@ +{ + "version" : 10, + "downgrade_to_9" : [] +} \ No newline at end of file diff --git a/robolectric_tests/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.java b/robolectric_tests/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.java index fd31033db..4f49817bf 100644 --- a/robolectric_tests/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.java +++ b/robolectric_tests/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.java @@ -18,7 +18,9 @@ import android.util.Pair; import com.android.launcher3.ItemInfo; import com.android.launcher3.LauncherProvider; import com.android.launcher3.LauncherSettings; +import com.android.launcher3.LauncherSettings.Favorites; import com.android.launcher3.ShortcutInfo; +import com.android.launcher3.util.ContentWriter; import com.android.launcher3.util.GridOccupancy; import com.android.launcher3.util.IntArray; import com.android.launcher3.util.IntSparseArrayMap; @@ -31,6 +33,8 @@ import org.robolectric.RobolectricTestRunner; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; /** * Tests for {@link AddWorkspaceItemsTask} @@ -60,15 +64,11 @@ public class AddWorkspaceItemsTaskTest extends BaseModelUpdateTaskTestCase { for (ItemInfo item : items) { list.add(Pair.create(item, null)); } - return new AddWorkspaceItemsTask(list) { - - @Override - protected void updateScreens(Context context, IntArray workspaceScreens) { } - }; + return new AddWorkspaceItemsTask(list); } @Test - public void testFindSpaceForItem_prefers_second() { + public void testFindSpaceForItem_prefers_second() throws Exception { // First screen has only one hole of size 1 int nextId = setupWorkspaceWithHoles(1, 1, new Rect(2, 2, 3, 3)); @@ -93,7 +93,6 @@ public class AddWorkspaceItemsTaskTest extends BaseModelUpdateTaskTestCase { public void testFindSpaceForItem_adds_new_screen() throws Exception { // First screen has 2 holes of sizes 3x2 and 2x3 setupWorkspaceWithHoles(1, 1, new Rect(2, 0, 5, 2), new Rect(0, 2, 2, 5)); - commitScreensToDb(); IntArray oldScreens = existingScreens.clone(); int[] spaceFound = newTask() @@ -109,7 +108,6 @@ public class AddWorkspaceItemsTaskTest extends BaseModelUpdateTaskTestCase { // Setup a screen with a hole setupWorkspaceWithHoles(1, 1, new Rect(2, 2, 3, 3)); - commitScreensToDb(); // Nothing was added assertTrue(executeTaskForTest(newTask(info)).isEmpty()); @@ -125,7 +123,6 @@ public class AddWorkspaceItemsTaskTest extends BaseModelUpdateTaskTestCase { // Setup a screen with a hole setupWorkspaceWithHoles(1, 1, new Rect(2, 2, 3, 3)); - commitScreensToDb(); executeTaskForTest(newTask(info, info2)).get(0).run(); ArgumentCaptor notAnimated = ArgumentCaptor.forClass(ArrayList.class); @@ -141,7 +138,7 @@ public class AddWorkspaceItemsTaskTest extends BaseModelUpdateTaskTestCase { assertTrue(animated.getValue().contains(info2)); } - private int setupWorkspaceWithHoles(int startId, int screenId, Rect... holes) { + private int setupWorkspaceWithHoles(int startId, int screenId, Rect... holes) throws Exception { GridOccupancy occupancy = new GridOccupancy(idp.numColumns, idp.numRows); occupancy.markCells(0, 0, idp.numColumns, idp.numRows, true); for (Rect r : holes) { @@ -151,6 +148,7 @@ public class AddWorkspaceItemsTaskTest extends BaseModelUpdateTaskTestCase { existingScreens.add(screenId); screenOccupancy.append(screenId, occupancy); + ExecutorService executor = Executors.newSingleThreadExecutor(); for (int x = 0; x < idp.numColumns; x++) { for (int y = 0; y < idp.numRows; y++) { if (!occupancy.cells[x][y]) { @@ -165,27 +163,19 @@ public class AddWorkspaceItemsTaskTest extends BaseModelUpdateTaskTestCase { info.cellY = y; info.container = LauncherSettings.Favorites.CONTAINER_DESKTOP; bgDataModel.addItem(targetContext, info, false); + + executor.execute(() -> { + ContentWriter writer = new ContentWriter(targetContext); + info.writeToValues(writer); + writer.put(Favorites._ID, info.id); + targetContext.getContentResolver().insert(Favorites.CONTENT_URI, + writer.getValues(targetContext)); + }); } } - return startId; - } - private void commitScreensToDb() throws Exception { - LauncherSettings.Settings.call(targetContext.getContentResolver(), - LauncherSettings.Settings.METHOD_CREATE_EMPTY_DB); - - Uri uri = LauncherSettings.WorkspaceScreens.CONTENT_URI; - ArrayList ops = new ArrayList<>(); - // Clear the table - ops.add(ContentProviderOperation.newDelete(uri).build()); - int count = existingScreens.size(); - for (int i = 0; i < count; i++) { - ContentValues v = new ContentValues(); - int screenId = existingScreens.get(i); - v.put(LauncherSettings.WorkspaceScreens._ID, screenId); - v.put(LauncherSettings.WorkspaceScreens.SCREEN_RANK, i); - ops.add(ContentProviderOperation.newInsert(uri).withValues(v).build()); - } - targetContext.getContentResolver().applyBatch(LauncherProvider.AUTHORITY, ops); + executor.submit(() -> null).get(); + executor.shutdown(); + return startId; } } diff --git a/robolectric_tests/src/com/android/launcher3/model/DbDowngradeHelperTest.java b/robolectric_tests/src/com/android/launcher3/model/DbDowngradeHelperTest.java new file mode 100644 index 000000000..a46617ec2 --- /dev/null +++ b/robolectric_tests/src/com/android/launcher3/model/DbDowngradeHelperTest.java @@ -0,0 +1,209 @@ +/* + * Copyright (C) 2017 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 junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertFalse; +import static junit.framework.Assert.assertNotSame; +import static junit.framework.Assert.assertTrue; + +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.when; + +import android.content.ContentValues; +import android.content.Context; +import android.content.res.Resources; +import android.database.Cursor; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteOpenHelper; + +import com.android.launcher3.LauncherProvider; +import com.android.launcher3.LauncherProvider.DatabaseHelper; +import com.android.launcher3.LauncherSettings.Favorites; +import com.android.launcher3.R; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.RuntimeEnvironment; + +import java.io.File; + +/** + * Tests for {@link DbDowngradeHelper} + */ +@RunWith(RobolectricTestRunner.class) +public class DbDowngradeHelperTest { + + private static final String SCHEMA_FILE = "test_schema.json"; + private static final String DB_FILE = "test.db"; + + private Context mContext; + private File mSchemaFile; + private File mDbFile; + + @Before + public void setup() { + mContext = RuntimeEnvironment.application; + mSchemaFile = mContext.getFileStreamPath(SCHEMA_FILE); + mDbFile = mContext.getDatabasePath(DB_FILE); + } + + @Test + public void testDowngradeSchemaMatchesVersion() throws Exception { + mSchemaFile.delete(); + assertFalse(mSchemaFile.exists()); + DbDowngradeHelper.updateSchemaFile(mSchemaFile, 0, mContext); + assertEquals(LauncherProvider.SCHEMA_VERSION, DbDowngradeHelper.parse(mSchemaFile).version); + } + + @Test + public void testUpdateSchemaFile() throws Exception { + // Setup mock resources + Resources res = spy(mContext.getResources()); + doAnswer(i ->this.getClass().getResourceAsStream("/db_schema_v10.json")) + .when(res).openRawResource(eq(R.raw.downgrade_schema)); + Context context = spy(mContext); + when(context.getResources()).thenReturn(res); + + mSchemaFile.delete(); + assertFalse(mSchemaFile.exists()); + + DbDowngradeHelper.updateSchemaFile(mSchemaFile, 10, context); + assertTrue(mSchemaFile.exists()); + assertEquals(10, DbDowngradeHelper.parse(mSchemaFile).version); + + // Schema is updated on version upgrade + assertTrue(mSchemaFile.setLastModified(0)); + DbDowngradeHelper.updateSchemaFile(mSchemaFile, 11, context); + assertNotSame(0, mSchemaFile.lastModified()); + + // Schema is not updated when version is same + assertTrue(mSchemaFile.setLastModified(0)); + DbDowngradeHelper.updateSchemaFile(mSchemaFile, 10, context); + assertEquals(0, mSchemaFile.lastModified()); + + // Schema is not updated on version downgrade + DbDowngradeHelper.updateSchemaFile(mSchemaFile, 3, context); + assertEquals(0, mSchemaFile.lastModified()); + } + + @Test + public void testDowngrade_success_v24() throws Exception { + setupTestDb(); + + TestOpenHelper helper = new TestOpenHelper(24); + assertEquals(24, helper.getReadableDatabase().getVersion()); + helper.close(); + } + + @Test + public void testDowngrade_success_v22() throws Exception { + setupTestDb(); + + SQLiteOpenHelper helper = new TestOpenHelper(22); + assertEquals(22, helper.getWritableDatabase().getVersion()); + + // Check column does not exist + try (Cursor c = helper.getWritableDatabase().query(Favorites.TABLE_NAME, + null, null, null, null, null, null)) { + assertEquals(-1, c.getColumnIndex(Favorites.OPTIONS)); + + // Check data is present + assertEquals(10, c.getCount()); + } + helper.close(); + + helper = new DatabaseHelper(mContext, null, DB_FILE) { + @Override + public void onOpen(SQLiteDatabase db) { } + }; + assertEquals(LauncherProvider.SCHEMA_VERSION, helper.getWritableDatabase().getVersion()); + + try (Cursor c = helper.getWritableDatabase().query(Favorites.TABLE_NAME, + null, null, null, null, null, null)) { + // Check column exists + assertNotSame(-1, c.getColumnIndex(Favorites.OPTIONS)); + + // Check data is present + assertEquals(10, c.getCount()); + } + helper.close(); + } + + @Test(expected = DowngradeFailException.class) + public void testDowngrade_fail_v20() throws Exception { + setupTestDb(); + + TestOpenHelper helper = new TestOpenHelper(20); + helper.getReadableDatabase().getVersion(); + } + + private void setupTestDb() throws Exception { + mSchemaFile.delete(); + mDbFile.delete(); + + DbDowngradeHelper.updateSchemaFile(mSchemaFile, LauncherProvider.SCHEMA_VERSION, mContext); + + DatabaseHelper dbHelper = new DatabaseHelper(mContext, null, DB_FILE) { + @Override + public void onOpen(SQLiteDatabase db) { } + }; + // Insert dummy data + for (int i = 0; i < 10; i++) { + ContentValues values = new ContentValues(); + values.put(Favorites._ID, i); + values.put(Favorites.TITLE, "title " + i); + dbHelper.getWritableDatabase().insert(Favorites.TABLE_NAME, null, values); + } + dbHelper.close(); + } + + private class TestOpenHelper extends SQLiteOpenHelper { + + public TestOpenHelper(int version) { + super(mContext, DB_FILE, null, version); + } + + @Override + public void onCreate(SQLiteDatabase sqLiteDatabase) { + throw new RuntimeException("DB should already be created"); + } + + @Override + public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { + throw new RuntimeException("Only downgrade supported"); + } + + @Override + public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) { + try { + DbDowngradeHelper.parse(mSchemaFile).onDowngrade(db, oldVersion, newVersion); + } catch (Exception e) { + throw new DowngradeFailException(e); + } + } + } + + private static class DowngradeFailException extends RuntimeException { + public DowngradeFailException(Exception e) { + super(e); + } + } +} diff --git a/robolectric_tests/src/com/android/launcher3/model/GridSizeMigrationTaskTest.java b/robolectric_tests/src/com/android/launcher3/model/GridSizeMigrationTaskTest.java index 67580ddd8..d4188aa8e 100644 --- a/robolectric_tests/src/com/android/launcher3/model/GridSizeMigrationTaskTest.java +++ b/robolectric_tests/src/com/android/launcher3/model/GridSizeMigrationTaskTest.java @@ -1,5 +1,7 @@ package com.android.launcher3.model; +import static com.android.launcher3.model.GridSizeMigrationTask.getWorkspaceScreenIds; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; @@ -10,7 +12,6 @@ import android.database.Cursor; import android.graphics.Point; import com.android.launcher3.InvariantDeviceProfile; -import com.android.launcher3.LauncherModel; import com.android.launcher3.LauncherProvider; import com.android.launcher3.LauncherSettings; import com.android.launcher3.config.FlagOverrideRule; @@ -55,7 +56,6 @@ public class GridSizeMigrationTaskTest { @Before public void setUp() { - mValidPackages = new HashSet<>(); mValidPackages.add(TEST_PACKAGE); mIdp = new InvariantDeviceProfile(); @@ -307,11 +307,6 @@ public class GridSizeMigrationTaskTest { LauncherSettings.Settings.call(mContext.getContentResolver(), LauncherSettings.Settings.METHOD_NEW_SCREEN_ID); - ContentValues v = new ContentValues(); - v.put(LauncherSettings.WorkspaceScreens._ID, screenId); - v.put(LauncherSettings.WorkspaceScreens.SCREEN_RANK, i); - mContext.getContentResolver().insert(LauncherSettings.WorkspaceScreens.CONTENT_URI, v); - ids[i] = new int[typeArray[i].length][]; for (int y = 0; y < typeArray[i].length; y++) { ids[i][y] = new int[typeArray[i][y].length]; @@ -326,7 +321,6 @@ public class GridSizeMigrationTaskTest { } } - IntArray allScreens = LauncherModel.loadWorkspaceScreensDb(mContext); return ids; } @@ -336,7 +330,7 @@ public class GridSizeMigrationTaskTest { * represent the workspace grid. */ private void verifyWorkspace(int[][][] ids) { - IntArray allScreens = LauncherModel.loadWorkspaceScreensDb(mContext); + IntArray allScreens = getWorkspaceScreenIds(mContext); assertEquals(ids.length, allScreens.size()); int total = 0; -- cgit v1.2.3