/* * Copyright (C) 2024 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 import android.content.ComponentName import android.content.ContentValues import android.database.sqlite.SQLiteDatabase import android.util.Xml import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.internal.R.attr.x import com.android.internal.R.attr.y import com.android.launcher3.AutoInstallsLayout.ATTR_CONTAINER import com.android.launcher3.AutoInstallsLayout.ATTR_X import com.android.launcher3.AutoInstallsLayout.ATTR_Y import com.android.launcher3.AutoInstallsLayout.LayoutParserCallback import com.android.launcher3.AutoInstallsLayout.SourceResources import com.android.launcher3.AutoInstallsLayout.TAG_WORKSPACE import com.android.launcher3.AutoInstallsLayout.USER_TYPE_WORK import com.android.launcher3.LauncherSettings.Favorites.APPWIDGET_PROVIDER import com.android.launcher3.LauncherSettings.Favorites.CONTAINER import com.android.launcher3.LauncherSettings.Favorites.CONTAINER_DESKTOP import com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT import com.android.launcher3.LauncherSettings.Favorites.INTENT import com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE import com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICATION import com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET import com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_FOLDER import com.android.launcher3.LauncherSettings.Favorites.PROFILE_ID import com.android.launcher3.LauncherSettings.Favorites.SPANX import com.android.launcher3.LauncherSettings.Favorites.SPANY import com.android.launcher3.LauncherSettings.Favorites._ID import com.android.launcher3.LauncherSettings.Favorites.containerToString import com.android.launcher3.model.data.AppInfo import com.android.launcher3.pm.UserCache import com.android.launcher3.util.Executors import com.android.launcher3.util.LauncherLayoutBuilder import com.android.launcher3.util.SandboxApplication import com.android.launcher3.util.TestUtil import com.android.launcher3.util.UserIconInfo.Companion.TYPE_MAIN import com.android.launcher3.util.UserIconInfo.Companion.TYPE_WORK import com.android.launcher3.util.rule.MockUsersRule import com.android.launcher3.util.rule.MockUsersRule.MockUser import com.android.launcher3.widget.LauncherWidgetHolder import com.google.common.truth.Truth.assertThat import java.io.StringReader import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mock import org.mockito.junit.MockitoJUnit /** Tests for [AutoInstallsLayout] */ @SmallTest @RunWith(AndroidJUnit4::class) class AutoInstallsLayoutTest { @get:Rule val mockitoRule = MockitoJUnit.rule() @get:Rule val targetContext = SandboxApplication().withModelDependency() @get:Rule val mockUsersRule = MockUsersRule(targetContext) private val callback: MyCallback = MyCallback() @Mock lateinit var widgetHolder: LauncherWidgetHolder @Mock lateinit var db: SQLiteDatabase @Test fun pending_icon_added_on_home() { LauncherLayoutBuilder() .atWorkspace(1, 1, 0) .putApp("p1", "c1") .toAutoInstallsLayout() .loadLayout(db) assertThat(callback.items.size).isEqualTo(1) assertThat(callback.items[0][ITEM_TYPE]).isEqualTo(ITEM_TYPE_APPLICATION) assertThat(callback.items[0][INTENT]) .isEqualTo(AppInfo.makeLaunchIntent(ComponentName("p1", "c1")).toUri(0)) assertThat(callback.items[0][CONTAINER]).isEqualTo(CONTAINER_DESKTOP) assertThat(callback.items[0].containsKey(PROFILE_ID)).isFalse() } @Test fun pending_icon_added_on_home_missingScreenAttr_logsExpection() { val result = LauncherLayoutBuilder() .withBaseValues( mapOf( ATTR_CONTAINER to containerToString(CONTAINER_DESKTOP), ATTR_X to x.toString(), ATTR_Y to y.toString(), ) ) .putApp("p1", "c1") .toAutoInstallsLayout() .loadLayout(db) assertThat(result).isEqualTo(-1) } @Test fun pending_icon_hotseat_missingRankAttr_logsException() { val result = LauncherLayoutBuilder() .withBaseValues(mapOf(ATTR_CONTAINER to containerToString(CONTAINER_HOTSEAT))) .putApp("p1", "c1") .toAutoInstallsLayout() .loadLayout(db) assertThat(result).isEqualTo(-1) } @Test fun pending_icon_added_on_hotseat() { LauncherLayoutBuilder() .atHotseat(1) .putApp("p1", "c1") .toAutoInstallsLayout() .loadLayout(db) assertThat(callback.items.size).isEqualTo(1) assertThat(callback.items[0][ITEM_TYPE]).isEqualTo(ITEM_TYPE_APPLICATION) assertThat(callback.items[0][CONTAINER]).isEqualTo(CONTAINER_HOTSEAT) } @Test fun widget_added_to_home() { LauncherLayoutBuilder() .atWorkspace(1, 1, 0) .putWidget("p1", "c1", 2, 3) .toAutoInstallsLayout() .loadLayout(db) assertThat(callback.items.size).isEqualTo(1) assertThat(callback.items[0][ITEM_TYPE]).isEqualTo(ITEM_TYPE_APPWIDGET) assertThat(callback.items[0][CONTAINER]).isEqualTo(CONTAINER_DESKTOP) assertThat(callback.items[0][APPWIDGET_PROVIDER]) .isEqualTo(ComponentName("p1", "c1").flattenToString()) assertThat(callback.items[0][SPANX]).isEqualTo(2.toString()) assertThat(callback.items[0][SPANY]).isEqualTo(3.toString()) } @Test fun items_added_to_folder() { LauncherLayoutBuilder() .atHotseat(1) .putFolder("Test") .addApp("p1", "c") .addApp("p2", "c") .addApp("p3", "c") .build() .toAutoInstallsLayout() .loadLayout(db) assertThat(callback.items.size).isEqualTo(4) assertThat(callback.items[0][ITEM_TYPE]).isEqualTo(ITEM_TYPE_FOLDER) assertThat(callback.items[0][CONTAINER]).isEqualTo(CONTAINER_HOTSEAT) val folderId = callback.items[0][_ID] assertThat(callback.items[1][CONTAINER]).isEqualTo(folderId) assertThat(callback.items[2][CONTAINER]).isEqualTo(folderId) assertThat(callback.items[3][CONTAINER]).isEqualTo(folderId) } @MockUser(userType = TYPE_MAIN) @MockUser(userType = TYPE_WORK) @Test fun work_item_added_to_home() { val cache = UserCache.getInstance(targetContext) TestUtil.runOnExecutorSync(Executors.MODEL_EXECUTOR) { assertThat(cache.userProfiles.size).isEqualTo(2) } LauncherLayoutBuilder() .atWorkspace(1, 1, 0) .putApp("p1", "c1", USER_TYPE_WORK) .toAutoInstallsLayout() .loadLayout(db) assertThat(callback.items.size).isEqualTo(1) assertThat(callback.items[0][ITEM_TYPE]).isEqualTo(ITEM_TYPE_APPLICATION) assertThat(callback.items[0][INTENT]) .isEqualTo(AppInfo.makeLaunchIntent(ComponentName("p1", "c1")).toUri(0)) assertThat(callback.items[0][CONTAINER]).isEqualTo(CONTAINER_DESKTOP) assertThat(callback.items[0][PROFILE_ID]) .isEqualTo(mockUsersRule.findUser { it.isWork }.hashCode()) } private fun LauncherLayoutBuilder.toAutoInstallsLayout() = AutoInstallsLayout( targetContext, widgetHolder, callback, SourceResources.wrap(targetContext.resources), { Xml.newPullParser().also { it.setInput(StringReader(build())) } }, TAG_WORKSPACE, ) class MyCallback : LayoutParserCallback { val items = ArrayList() override fun generateNewItemId() = items.size override fun insertAndCheck(db: SQLiteDatabase?, values: ContentValues): Int { val id = values[_ID] items.add(ContentValues(values)) return if (id is Int) id else 0 } } }