1 /* 2 * Copyright (C) 2019 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 * use this file except in compliance with the License. You may obtain a copy of 6 * 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, WITHOUT 12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 * License for the specific language governing permissions and limitations under 14 * the License. 15 */ 16 package com.android.launcher3.compat; 17 18 import static com.android.launcher3.Flags.FLAG_ENABLE_SUPPORT_FOR_ARCHIVING; 19 20 import static com.google.common.truth.Truth.assertThat; 21 22 import android.content.pm.PackageInstaller.SessionParams; 23 import android.content.pm.PackageManager; 24 import android.graphics.Bitmap; 25 import android.platform.test.annotations.RequiresFlagsEnabled; 26 import android.platform.test.flag.junit.CheckFlagsRule; 27 import android.platform.test.flag.junit.DeviceFlagsValueProvider; 28 import android.text.TextUtils; 29 30 import androidx.test.filters.LargeTest; 31 import androidx.test.runner.AndroidJUnit4; 32 33 import com.android.launcher3.Launcher; 34 import com.android.launcher3.LauncherState; 35 import com.android.launcher3.tapl.AllApps; 36 import com.android.launcher3.ui.AbstractLauncherUiTest; 37 import com.android.launcher3.util.LauncherBindableItemsContainer.ItemOperator; 38 import com.android.launcher3.util.TestUtil; 39 import com.android.launcher3.util.rule.ViewCaptureRule; 40 41 import org.junit.After; 42 import org.junit.Rule; 43 import org.junit.Test; 44 import org.junit.runner.RunWith; 45 46 import java.io.IOException; 47 import java.util.UUID; 48 49 50 /** 51 * Test to verify promise icon flow. 52 */ 53 @LargeTest 54 @RunWith(AndroidJUnit4.class) 55 public class TaplPromiseIconUiTest extends AbstractLauncherUiTest<Launcher> { 56 57 @Rule 58 public final CheckFlagsRule mCheckFlagsRule = 59 DeviceFlagsValueProvider.createCheckFlagsRule(); 60 61 public static final String PACKAGE_NAME = "test.promise.app"; 62 public static final String DUMMY_PACKAGE = "com.example.android.aardwolf"; 63 public static final String DUMMY_LABEL = "Aardwolf"; 64 65 private int mSessionId = -1; 66 67 @Override setUp()68 public void setUp() throws Exception { 69 super.setUp(); 70 mDevice.pressHome(); 71 waitForLauncherCondition("Launcher didn't start", launcher -> launcher != null); 72 waitForState("Launcher internal state didn't switch to Home", () -> LauncherState.NORMAL); 73 mSessionId = -1; 74 } 75 76 @After tearDown()77 public void tearDown() throws IOException { 78 if (mSessionId > -1) { 79 mTargetContext.getPackageManager().getPackageInstaller().abandonSession(mSessionId); 80 } 81 TestUtil.uninstallDummyApp(); 82 } 83 84 /** 85 * Create a session and return the id. 86 */ createSession(String packageName, String label, Bitmap icon)87 private int createSession(String packageName, String label, Bitmap icon) throws Throwable { 88 SessionParams params = new SessionParams(SessionParams.MODE_FULL_INSTALL); 89 params.setAppPackageName(packageName); 90 params.setAppLabel(label); 91 params.setAppIcon(icon); 92 params.setInstallReason(PackageManager.INSTALL_REASON_USER); 93 return mTargetContext.getPackageManager().getPackageInstaller().createSession(params); 94 } 95 96 @Test testPromiseIcon_addedFromEligibleSession()97 public void testPromiseIcon_addedFromEligibleSession() throws Throwable { 98 final String appLabel = "Test Promise App " + UUID.randomUUID().toString(); 99 final ItemOperator findPromiseApp = (info, view) -> 100 info != null && TextUtils.equals(info.title, appLabel); 101 102 // Create and add test session 103 mSessionId = createSession(PACKAGE_NAME, appLabel, 104 Bitmap.createBitmap(100, 100, Bitmap.Config.ALPHA_8)); 105 106 // Verify promise icon is added 107 waitForLauncherCondition("Test Promise App not found on workspace", launcher -> 108 launcher.getWorkspace().getFirstMatch(findPromiseApp) != null); 109 110 // Remove session 111 mTargetContext.getPackageManager().getPackageInstaller().abandonSession(mSessionId); 112 mSessionId = -1; 113 114 // Verify promise icon is removed 115 waitForLauncherCondition("Test Promise App not removed from workspace", launcher -> 116 launcher.getWorkspace().getFirstMatch(findPromiseApp) == null); 117 } 118 119 @Test 120 @ViewCaptureRule.MayProduceNoFrames testPromiseIcon_notAddedFromIneligibleSession()121 public void testPromiseIcon_notAddedFromIneligibleSession() throws Throwable { 122 final String appLabel = "Test Promise App " + UUID.randomUUID().toString(); 123 final ItemOperator findPromiseApp = (info, view) -> 124 info != null && TextUtils.equals(info.title, appLabel); 125 126 // Create and add test session without icon or label 127 mSessionId = createSession(PACKAGE_NAME, null, null); 128 129 // Sleep for duration of animation if a view was to be added + some buffer time. 130 Thread.sleep(Launcher.NEW_APPS_PAGE_MOVE_DELAY + Launcher.NEW_APPS_ANIMATION_DELAY + 500); 131 132 // Verify promise icon is not added 133 waitForLauncherCondition("Test Promise App not found on workspace", launcher -> 134 launcher.getWorkspace().getFirstMatch(findPromiseApp) == null); 135 } 136 137 @Test 138 @RequiresFlagsEnabled(FLAG_ENABLE_SUPPORT_FOR_ARCHIVING) testPromiseIcon_addedArchivedApp()139 public void testPromiseIcon_addedArchivedApp() throws Throwable { 140 installDummyAppAndWaitForUIUpdate(); 141 assertThat(mDevice.executeShellCommand(String.format("pm archive %s", DUMMY_PACKAGE))) 142 .isEqualTo("Success\n"); 143 144 // Create and add test session 145 mSessionId = createSession(DUMMY_PACKAGE, /* label= */ "", 146 Bitmap.createBitmap(100, 100, Bitmap.Config.ALPHA_8)); 147 148 // Verify promise icon is added to all apps view. The icon may not be added to the 149 // workspace even if there might be no icon present for archived app. But icon will 150 // always be in all apps view. In case an icon is not added, an exception would be thrown. 151 final AllApps allApps = mLauncher.getWorkspace().switchToAllApps(); 152 153 // Wait for the promise icon to be added. 154 waitForLauncherCondition( 155 DUMMY_PACKAGE + " app was not found on all apps after being archived", 156 launcher -> { 157 try { 158 allApps.getAppIcon(DUMMY_LABEL); 159 } catch (Throwable t) { 160 return false; 161 } 162 return true; 163 }); 164 165 // Remove session 166 mTargetContext.getPackageManager().getPackageInstaller().abandonSession(mSessionId); 167 mSessionId = -1; 168 } 169 installDummyAppAndWaitForUIUpdate()170 private void installDummyAppAndWaitForUIUpdate() throws IOException { 171 TestUtil.installDummyApp(); 172 mLauncher.waitForModelQueueCleared(); 173 mLauncher.waitForLauncherInitialized(); 174 } 175 } 176