• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 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.celllayout.board
17 
18 import android.content.ComponentName
19 import android.content.Context
20 import android.graphics.Rect
21 import android.os.Process
22 import android.os.UserHandle
23 import android.util.Log
24 import androidx.test.core.app.ApplicationProvider
25 import androidx.test.platform.app.InstrumentationRegistry
26 import com.android.launcher3.InvariantDeviceProfile
27 import com.android.launcher3.LauncherSettings
28 import com.android.launcher3.celllayout.FavoriteItemsTransaction
29 import com.android.launcher3.model.data.AppInfo
30 import com.android.launcher3.model.data.FolderInfo
31 import com.android.launcher3.model.data.ItemInfo
32 import com.android.launcher3.model.data.WorkspaceItemInfo
33 import com.android.launcher3.ui.TestViewHelpers
34 import com.android.launcher3.util.WidgetUtils
35 import java.util.function.Supplier
36 
37 class TestWorkspaceBuilder(private val mContext: Context) {
38 
39     private var appComponentName =
40         ComponentName("com.google.android.calculator", "com.android.calculator2.Calculator")
41     private val myUser: UserHandle = Process.myUserHandle()
42 
43     /** Fills the given rect in WidgetRect with 1x1 widgets. This is useful to equalize cases. */
fillWithWidgetsnull44     private fun fillWithWidgets(
45         widgetRect: WidgetRect,
46         transaction: FavoriteItemsTransaction,
47         screenId: Int,
48     ): FavoriteItemsTransaction {
49         val initX = widgetRect.cellX
50         val initY = widgetRect.cellY
51         for (x in initX until initX + widgetRect.spanX) {
52             for (y in initY until initY + widgetRect.spanY) {
53                 try {
54                     // this widgets are filling, we don't care if we can't place them
55                     transaction.addItem(
56                         createWidgetInCell(WidgetRect(CellType.IGNORE, Rect(x, y, x, y)), screenId)
57                     )
58                 } catch (e: Exception) {
59                     Log.d(TAG, "Unable to place filling widget at $x,$y")
60                 }
61             }
62         }
63         return transaction
64     }
65 
appnull66     private fun app() =
67         AppInfo(appComponentName, "test icon", myUser, AppInfo.makeLaunchIntent(appComponentName))
68 
69     /**
70      * Helper to set the app to use for the test workspace, using activity-alias from
71      * AndroidManifest-common.
72      *
73      * @param testAppName the android:name field of the test app activity-alias to use
74      */
75     fun setTestAppActivityAlias(testAppName: String) {
76         appComponentName =
77             ComponentName(
78                 InstrumentationRegistry.getInstrumentation().context.packageName,
79                 TEST_ACTIVITY_PACKAGE_PREFIX + testAppName,
80             )
81     }
82 
83     /**
84      * Sets the test app for app icons to the specified Component
85      *
86      * @param testAppComponent ComponentName to use for app icons
87      */
setTestAppComponentnull88     fun setTestAppComponent(testAppComponent: ComponentName) {
89         appComponentName = testAppComponent
90     }
91 
addCorrespondingWidgetRectnull92     private fun addCorrespondingWidgetRect(
93         widgetRect: WidgetRect,
94         transaction: FavoriteItemsTransaction,
95         screenId: Int,
96     ) {
97         if (widgetRect.type == 'x') {
98             fillWithWidgets(widgetRect, transaction, screenId)
99         } else {
100             transaction.addItem(createWidgetInCell(widgetRect, screenId))
101         }
102     }
103 
104     /** Builds the given board into the transaction */
buildFromBoardnull105     fun buildFromBoard(
106         board: CellLayoutBoard,
107         transaction: FavoriteItemsTransaction,
108         screenId: Int,
109     ): FavoriteItemsTransaction {
110         board.widgets.forEach { addCorrespondingWidgetRect(it, transaction, screenId) }
111         board.icons.forEach { transaction.addItem { createIconInCell(it, screenId) } }
112         board.folders.forEach { transaction.addItem { createFolderInCell(it, screenId) } }
113         return transaction
114     }
115 
116     /**
117      * Fills the hotseat row with apps instead of suggestions, for this to work the workspace should
118      * be clean otherwise this doesn't overrides the existing icons.
119      */
fillHotseatIconsnull120     fun fillHotseatIcons(transaction: FavoriteItemsTransaction): FavoriteItemsTransaction {
121         for (i in 0..<InvariantDeviceProfile.INSTANCE[mContext].numDatabaseHotseatIcons) {
122             transaction.addItem { getHotseatValues(i) }
123         }
124         return transaction
125     }
126 
createWidgetInCellnull127     private fun createWidgetInCell(widgetRect: WidgetRect, paramScreenId: Int): Supplier<ItemInfo> {
128         // Create the widget lazily since the appWidgetId can get lost during setup
129         return Supplier<ItemInfo> {
130             WidgetUtils.createWidgetInfo(
131                     TestViewHelpers.findWidgetProvider(false),
132                     ApplicationProvider.getApplicationContext(),
133                     true,
134                 )
135                 .apply {
136                     cellX = widgetRect.cellX
137                     cellY = widgetRect.cellY
138                     spanX = widgetRect.spanX
139                     spanY = widgetRect.spanY
140                     screenId = paramScreenId
141                 }
142         }
143     }
144 
createFolderInCellnull145     fun createFolderInCell(folderPoint: FolderPoint, paramScreenId: Int): FolderInfo =
146         FolderInfo().apply {
147             screenId = paramScreenId
148             container = LauncherSettings.Favorites.CONTAINER_DESKTOP
149             cellX = folderPoint.coord.x
150             cellY = folderPoint.coord.y
151             spanY = 1
152             spanX = 1
153             minSpanX = 1
154             minSpanY = 1
155             setOption(FolderInfo.FLAG_MULTI_PAGE_ANIMATION, true, null)
156             for (i in 0 until folderPoint.numberIconsInside) {
157                 add(getDefaultWorkspaceItem(paramScreenId))
158             }
159         }
160 
getDefaultWorkspaceItemnull161     private fun getDefaultWorkspaceItem(paramScreenId: Int): WorkspaceItemInfo =
162         WorkspaceItemInfo(app()).apply {
163             screenId = paramScreenId
164             spanY = 1
165             spanX = 1
166             minSpanX = 1
167             minSpanY = 1
168             container = LauncherSettings.Favorites.CONTAINER_DESKTOP
169         }
170 
createIconInCellnull171     private fun createIconInCell(iconPoint: IconPoint, paramScreenId: Int) =
172         WorkspaceItemInfo(app()).apply {
173             screenId = paramScreenId
174             cellX = iconPoint.coord.x
175             cellY = iconPoint.coord.y
176             spanY = 1
177             spanX = 1
178             minSpanX = 1
179             minSpanY = 1
180             container = LauncherSettings.Favorites.CONTAINER_DESKTOP
181         }
182 
getHotseatValuesnull183     private fun getHotseatValues(x: Int) =
184         WorkspaceItemInfo(app()).apply {
185             cellX = x
186             cellY = 0
187             spanY = 1
188             spanX = 1
189             minSpanX = 1
190             minSpanY = 1
191             rank = x
192             screenId = x
193             container = LauncherSettings.Favorites.CONTAINER_HOTSEAT
194         }
195 
196     companion object {
197         private const val TAG = "CellLayoutBoardBuilder"
198         private const val TEST_ACTIVITY_PACKAGE_PREFIX = "com.android.launcher3.tests."
199     }
200 }
201