1 /* <lambda>null2 * Copyright (C) 2022 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.model 17 18 import android.content.ComponentName 19 import android.content.Context 20 import android.content.Intent 21 import android.graphics.Rect 22 import com.android.launcher3.InvariantDeviceProfile 23 import com.android.launcher3.LauncherAppState 24 import com.android.launcher3.LauncherSettings 25 import com.android.launcher3.model.data.WorkspaceItemInfo 26 import com.android.launcher3.util.ContentWriter 27 import com.android.launcher3.util.GridOccupancy 28 import com.android.launcher3.util.IntArray 29 import com.android.launcher3.util.IntSparseArrayMap 30 import com.android.launcher3.util.LauncherModelHelper 31 import java.util.UUID 32 33 /** Base class for workspace related tests. */ 34 abstract class AbstractWorkspaceModelTest { 35 companion object { 36 val emptyScreenSpaces = listOf(Rect(0, 0, 5, 5)) 37 val fullScreenSpaces = emptyList<Rect>() 38 val nonEmptyScreenSpaces = listOf(Rect(1, 2, 3, 4)) 39 } 40 41 protected lateinit var mTargetContext: Context 42 protected lateinit var mIdp: InvariantDeviceProfile 43 protected lateinit var mAppState: LauncherAppState 44 protected lateinit var mModelHelper: LauncherModelHelper 45 protected lateinit var mExistingScreens: IntArray 46 protected lateinit var mNewScreens: IntArray 47 protected lateinit var mScreenOccupancy: IntSparseArrayMap<GridOccupancy> 48 49 open fun setup() { 50 mModelHelper = LauncherModelHelper() 51 mTargetContext = mModelHelper.sandboxContext 52 mIdp = InvariantDeviceProfile.INSTANCE[mTargetContext] 53 mIdp.numRows = 5 54 mIdp.numColumns = mIdp.numRows 55 mAppState = LauncherAppState.getInstance(mTargetContext) 56 mExistingScreens = IntArray() 57 mScreenOccupancy = IntSparseArrayMap() 58 mNewScreens = IntArray() 59 } 60 61 open fun tearDown() { 62 mModelHelper.destroy() 63 } 64 65 /** Sets up workspaces with the given screen IDs with some items and a 2x2 space. */ 66 fun setupWorkspaces(screenIdsWithItems: List<Int>) { 67 var nextItemId = 1 68 screenIdsWithItems.forEach { screenId -> 69 nextItemId = setupWorkspace(nextItemId, screenId, nonEmptyScreenSpaces) 70 } 71 } 72 73 /** 74 * Sets up the given workspaces with the given spaces, and fills the remaining space with items. 75 */ 76 fun setupWorkspacesWithSpaces( 77 screen0: List<Rect>? = null, 78 screen1: List<Rect>? = null, 79 screen2: List<Rect>? = null, 80 screen3: List<Rect>? = null, 81 ) = listOf(screen0, screen1, screen2, screen3).let(this::setupWithSpaces) 82 83 private fun setupWithSpaces(workspaceSpaces: List<List<Rect>?>) { 84 var nextItemId = 1 85 workspaceSpaces.forEachIndexed { screenId, spaces -> 86 if (spaces != null) { 87 nextItemId = setupWorkspace(nextItemId, screenId, spaces) 88 } 89 } 90 } 91 92 private fun setupWorkspace(startId: Int, screenId: Int, spaces: List<Rect>): Int { 93 return mModelHelper.executeSimpleTask { dataModel -> 94 writeWorkspaceWithSpaces(dataModel, startId, screenId, spaces) 95 } 96 } 97 98 private fun writeWorkspaceWithSpaces( 99 bgDataModel: BgDataModel, 100 itemStartId: Int, 101 screenId: Int, 102 spaces: List<Rect>, 103 ): Int { 104 var itemId = itemStartId 105 val occupancy = GridOccupancy(mIdp.numColumns, mIdp.numRows) 106 occupancy.markCells(0, 0, mIdp.numColumns, mIdp.numRows, true) 107 spaces.forEach { spaceRect -> occupancy.markCells(spaceRect, false) } 108 mExistingScreens.add(screenId) 109 mScreenOccupancy.append(screenId, occupancy) 110 for (x in 0 until mIdp.numColumns) { 111 for (y in 0 until mIdp.numRows) { 112 if (!occupancy.cells[x][y]) { 113 continue 114 } 115 val info = getExistingItem() 116 info.id = itemId++ 117 info.screenId = screenId 118 info.cellX = x 119 info.cellY = y 120 info.container = LauncherSettings.Favorites.CONTAINER_DESKTOP 121 bgDataModel.addItem(mTargetContext, info, false) 122 val writer = ContentWriter(mTargetContext) 123 info.writeToValues(writer) 124 writer.put(LauncherSettings.Favorites._ID, info.id) 125 mTargetContext.contentResolver.insert( 126 LauncherSettings.Favorites.CONTENT_URI, 127 writer.getValues(mTargetContext) 128 ) 129 } 130 } 131 return itemId 132 } 133 134 fun getExistingItem() = 135 WorkspaceItemInfo().apply { intent = Intent().setComponent(ComponentName("a", "b")) } 136 137 fun getNewItem(): WorkspaceItemInfo { 138 val itemPackage = UUID.randomUUID().toString() 139 return WorkspaceItemInfo().apply { 140 intent = Intent().setComponent(ComponentName(itemPackage, itemPackage)) 141 } 142 } 143 } 144 145 data class NewItemSpace(val screenId: Int, val cellX: Int, val cellY: Int) { toIntArraynull146 fun toIntArray() = intArrayOf(screenId, cellX, cellY) 147 148 companion object { 149 fun fromIntArray(array: kotlin.IntArray) = NewItemSpace(array[0], array[1], array[2]) 150 } 151 } 152