1 /* 2 * Copyright (C) 2024 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 17 package com.android.launcher3 18 19 import android.content.ComponentName 20 import android.content.ContentValues 21 import android.database.sqlite.SQLiteDatabase 22 import android.os.Process.myUserHandle 23 import android.os.UserHandle 24 import android.util.Xml 25 import androidx.test.ext.junit.runners.AndroidJUnit4 26 import androidx.test.filters.SmallTest 27 import com.android.launcher3.AutoInstallsLayout.LayoutParserCallback 28 import com.android.launcher3.AutoInstallsLayout.SourceResources 29 import com.android.launcher3.AutoInstallsLayout.TAG_WORKSPACE 30 import com.android.launcher3.AutoInstallsLayout.USER_TYPE_WORK 31 import com.android.launcher3.LauncherSettings.Favorites.APPWIDGET_PROVIDER 32 import com.android.launcher3.LauncherSettings.Favorites.CONTAINER 33 import com.android.launcher3.LauncherSettings.Favorites.CONTAINER_DESKTOP 34 import com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT 35 import com.android.launcher3.LauncherSettings.Favorites.INTENT 36 import com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE 37 import com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICATION 38 import com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET 39 import com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_FOLDER 40 import com.android.launcher3.LauncherSettings.Favorites.PROFILE_ID 41 import com.android.launcher3.LauncherSettings.Favorites.SPANX 42 import com.android.launcher3.LauncherSettings.Favorites.SPANY 43 import com.android.launcher3.LauncherSettings.Favorites._ID 44 import com.android.launcher3.model.data.AppInfo 45 import com.android.launcher3.pm.UserCache 46 import com.android.launcher3.util.ApiWrapper 47 import com.android.launcher3.util.Executors 48 import com.android.launcher3.util.LauncherLayoutBuilder 49 import com.android.launcher3.util.LauncherModelHelper 50 import com.android.launcher3.util.LauncherModelHelper.SandboxModelContext 51 import com.android.launcher3.util.TestUtil 52 import com.android.launcher3.util.UserIconInfo 53 import com.android.launcher3.util.UserIconInfo.TYPE_MAIN 54 import com.android.launcher3.util.UserIconInfo.TYPE_WORK 55 import com.android.launcher3.widget.LauncherWidgetHolder 56 import com.google.common.truth.Truth.assertThat 57 import java.io.StringReader 58 import org.junit.After 59 import org.junit.Before 60 import org.junit.Test 61 import org.junit.runner.RunWith 62 import org.mockito.Mock 63 import org.mockito.MockitoAnnotations 64 import org.mockito.kotlin.doReturn 65 import org.mockito.kotlin.spy 66 import org.mockito.kotlin.whenever 67 68 /** Tests for [AutoInstallsLayout] */ 69 @SmallTest 70 @RunWith(AndroidJUnit4::class) 71 class AutoInstallsLayoutTest { 72 73 lateinit var modelHelper: LauncherModelHelper 74 lateinit var targetContext: SandboxModelContext 75 76 lateinit var callback: MyCallback 77 78 @Mock lateinit var widgetHolder: LauncherWidgetHolder 79 @Mock lateinit var db: SQLiteDatabase 80 81 @Before setupnull82 fun setup() { 83 MockitoAnnotations.initMocks(this) 84 modelHelper = LauncherModelHelper() 85 targetContext = modelHelper.sandboxContext 86 callback = MyCallback() 87 } 88 89 @After tearDownnull90 fun tearDown() { 91 modelHelper.destroy() 92 } 93 94 @Test pending_icon_added_on_homenull95 fun pending_icon_added_on_home() { 96 LauncherLayoutBuilder() 97 .atWorkspace(1, 1, 0) 98 .putApp("p1", "c1") 99 .toAutoInstallsLayout() 100 .loadLayout(db) 101 102 assertThat(callback.items.size).isEqualTo(1) 103 assertThat(callback.items[0][ITEM_TYPE]).isEqualTo(ITEM_TYPE_APPLICATION) 104 assertThat(callback.items[0][INTENT]) 105 .isEqualTo(AppInfo.makeLaunchIntent(ComponentName("p1", "c1")).toUri(0)) 106 assertThat(callback.items[0][CONTAINER]).isEqualTo(CONTAINER_DESKTOP) 107 assertThat(callback.items[0].containsKey(PROFILE_ID)).isFalse() 108 } 109 110 @Test pending_icon_added_on_hotseatnull111 fun pending_icon_added_on_hotseat() { 112 LauncherLayoutBuilder() 113 .atHotseat(1) 114 .putApp("p1", "c1") 115 .toAutoInstallsLayout() 116 .loadLayout(db) 117 118 assertThat(callback.items.size).isEqualTo(1) 119 assertThat(callback.items[0][ITEM_TYPE]).isEqualTo(ITEM_TYPE_APPLICATION) 120 assertThat(callback.items[0][CONTAINER]).isEqualTo(CONTAINER_HOTSEAT) 121 } 122 123 @Test widget_added_to_homenull124 fun widget_added_to_home() { 125 LauncherLayoutBuilder() 126 .atWorkspace(1, 1, 0) 127 .putWidget("p1", "c1", 2, 3) 128 .toAutoInstallsLayout() 129 .loadLayout(db) 130 131 assertThat(callback.items.size).isEqualTo(1) 132 assertThat(callback.items[0][ITEM_TYPE]).isEqualTo(ITEM_TYPE_APPWIDGET) 133 assertThat(callback.items[0][CONTAINER]).isEqualTo(CONTAINER_DESKTOP) 134 assertThat(callback.items[0][APPWIDGET_PROVIDER]) 135 .isEqualTo(ComponentName("p1", "c1").flattenToString()) 136 assertThat(callback.items[0][SPANX]).isEqualTo(2.toString()) 137 assertThat(callback.items[0][SPANY]).isEqualTo(3.toString()) 138 } 139 140 @Test items_added_to_foldernull141 fun items_added_to_folder() { 142 LauncherLayoutBuilder() 143 .atHotseat(1) 144 .putFolder("Test") 145 .addApp("p1", "c") 146 .addApp("p2", "c") 147 .addApp("p3", "c") 148 .build() 149 .toAutoInstallsLayout() 150 .loadLayout(db) 151 152 assertThat(callback.items.size).isEqualTo(4) 153 assertThat(callback.items[0][ITEM_TYPE]).isEqualTo(ITEM_TYPE_FOLDER) 154 assertThat(callback.items[0][CONTAINER]).isEqualTo(CONTAINER_HOTSEAT) 155 156 val folderId = callback.items[0][_ID] 157 assertThat(callback.items[1][CONTAINER]).isEqualTo(folderId) 158 assertThat(callback.items[2][CONTAINER]).isEqualTo(folderId) 159 assertThat(callback.items[3][CONTAINER]).isEqualTo(folderId) 160 } 161 162 @Test work_item_added_to_homenull163 fun work_item_added_to_home() { 164 val apiWrapperMock = spy(ApiWrapper.INSTANCE[targetContext]) 165 targetContext.putObject(ApiWrapper.INSTANCE, apiWrapperMock) 166 doReturn( 167 mapOf( 168 myUserHandle() to UserIconInfo(myUserHandle(), TYPE_MAIN, 0), 169 UserHandle.of(20) to UserIconInfo(UserHandle.of(20), TYPE_WORK, 20), 170 ) 171 ) 172 .whenever(apiWrapperMock) 173 .queryAllUsers() 174 175 val cache = UserCache.getInstance(targetContext) 176 TestUtil.runOnExecutorSync(Executors.MODEL_EXECUTOR) { 177 assertThat(cache.userProfiles.size).isEqualTo(2) 178 } 179 180 LauncherLayoutBuilder() 181 .atWorkspace(1, 1, 0) 182 .putApp("p1", "c1", USER_TYPE_WORK) 183 .toAutoInstallsLayout() 184 .loadLayout(db) 185 186 assertThat(callback.items.size).isEqualTo(1) 187 assertThat(callback.items[0][ITEM_TYPE]).isEqualTo(ITEM_TYPE_APPLICATION) 188 assertThat(callback.items[0][INTENT]) 189 .isEqualTo(AppInfo.makeLaunchIntent(ComponentName("p1", "c1")).toUri(0)) 190 assertThat(callback.items[0][CONTAINER]).isEqualTo(CONTAINER_DESKTOP) 191 assertThat(callback.items[0][PROFILE_ID]).isEqualTo(20) 192 } 193 LauncherLayoutBuildernull194 private fun LauncherLayoutBuilder.toAutoInstallsLayout() = 195 AutoInstallsLayout( 196 targetContext, 197 widgetHolder, 198 callback, 199 SourceResources.wrap(targetContext.resources), 200 { Xml.newPullParser().also { it.setInput(StringReader(build())) } }, 201 TAG_WORKSPACE 202 ) 203 204 class MyCallback : LayoutParserCallback { 205 206 val items = ArrayList<ContentValues>() 207 generateNewItemIdnull208 override fun generateNewItemId() = items.size 209 210 override fun insertAndCheck(db: SQLiteDatabase?, values: ContentValues): Int { 211 val id = values[_ID] 212 items.add(ContentValues(values)) 213 return if (id is Int) id else 0 214 } 215 } 216 } 217