/* * Copyright (C) 2019 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.ui; import static androidx.test.InstrumentationRegistry.getInstrumentation; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import android.util.Log; import androidx.test.filters.LargeTest; import androidx.test.runner.AndroidJUnit4; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherState; import com.android.launcher3.popup.ArrowPopup; import com.android.launcher3.tapl.AllApps; import com.android.launcher3.tapl.AppIcon; import com.android.launcher3.tapl.AppIconMenu; import com.android.launcher3.tapl.AppIconMenuItem; import com.android.launcher3.tapl.Widgets; import com.android.launcher3.tapl.Workspace; import com.android.launcher3.util.rule.TestStabilityRule.Stability; import com.android.launcher3.views.OptionsPopupView; import com.android.launcher3.widget.WidgetsFullSheet; import com.android.launcher3.widget.WidgetsRecyclerView; import org.junit.Before; import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; @LargeTest @RunWith(AndroidJUnit4.class) public class TaplTestsLauncher3 extends AbstractLauncherUiTest { private static final String APP_NAME = "LauncherTestApp"; @Before public void setUp() throws Exception { super.setUp(); initialize(this); } public static void initialize(AbstractLauncherUiTest test) throws Exception { test.clearLauncherData(); test.mDevice.pressHome(); test.waitForLauncherCondition("Launcher didn't start", launcher -> launcher != null); test.waitForState("Launcher internal state didn't switch to Home", LauncherState.NORMAL); test.waitForResumed("Launcher internal state is still Background"); // Check that we switched to home. test.mLauncher.getWorkspace(); } // Please don't add negative test cases for methods that fail only after a long wait. public static void expectFail(String message, Runnable action) { boolean failed = false; try { action.run(); } catch (AssertionError e) { failed = true; } assertTrue(message, failed); } private boolean isWorkspaceScrollable(Launcher launcher) { return launcher.getWorkspace().getPageCount() > 1; } private int getCurrentWorkspacePage(Launcher launcher) { return launcher.getWorkspace().getCurrentPage(); } private WidgetsRecyclerView getWidgetsView(Launcher launcher) { return WidgetsFullSheet.getWidgetsView(launcher); } @Test public void testDevicePressMenu() throws Exception { mDevice.pressMenu(); mDevice.waitForIdle(); executeOnLauncher( launcher -> assertTrue("Launcher internal state didn't switch to Showing Menu", OptionsPopupView.getOptionsPopup(launcher) != null)); // Check that pressHome works when the menu is shown. mLauncher.pressHome(); } @Test @Ignore public void testPressHomeOnAllAppsContextMenu() throws Exception { final AllApps allApps = mLauncher.getWorkspace().switchToAllApps(); allApps.freeze(); try { allApps.getAppIcon("TestActivity7").openMenu(); } finally { allApps.unfreeze(); } mLauncher.pressHome(); } public static void runAllAppsTest(AbstractLauncherUiTest test, AllApps allApps) { allApps.freeze(); try { assertNotNull("allApps parameter is null", allApps); assertTrue( "Launcher internal state is not All Apps", test.isInState(LauncherState.ALL_APPS)); // Test flinging forward and backward. test.executeOnLauncher(launcher -> assertEquals( "All Apps started in already scrolled state", 0, test.getAllAppsScroll(launcher))); allApps.flingForward(); assertTrue("Launcher internal state is not All Apps", test.isInState(LauncherState.ALL_APPS)); final Integer flingForwardY = test.getFromLauncher( launcher -> test.getAllAppsScroll(launcher)); test.executeOnLauncher( launcher -> assertTrue("flingForward() didn't scroll App Apps", flingForwardY > 0)); allApps.flingBackward(); assertTrue( "Launcher internal state is not All Apps", test.isInState(LauncherState.ALL_APPS)); final Integer flingBackwardY = test.getFromLauncher( launcher -> test.getAllAppsScroll(launcher)); test.executeOnLauncher(launcher -> assertTrue("flingBackward() didn't scroll App Apps", flingBackwardY < flingForwardY)); // Test scrolling down to YouTube. assertNotNull("All apps: can't fine YouTube", allApps.getAppIcon("YouTube")); // Test scrolling up to Camera. assertNotNull("All apps: can't fine Camera", allApps.getAppIcon("Camera")); // Test failing to find a non-existing app. final AllApps allAppsFinal = allApps; expectFail("All apps: could find a non-existing app", () -> allAppsFinal.getAppIcon("NO APP")); assertTrue( "Launcher internal state is not All Apps", test.isInState(LauncherState.ALL_APPS)); } finally { allApps.unfreeze(); } } @Test @PortraitLandscape public void testWorkspaceSwitchToAllApps() { assertNotNull("switchToAllApps() returned null", mLauncher.getWorkspace().switchToAllApps()); assertTrue("Launcher internal state is not All Apps", isInState(LauncherState.ALL_APPS)); } @Test public void testWorkspace() throws Exception { final Workspace workspace = mLauncher.getWorkspace(); // Test that ensureWorkspaceIsScrollable adds a page by dragging an icon there. executeOnLauncher(launcher -> assertFalse("Initial workspace state is scrollable", isWorkspaceScrollable(launcher))); assertNull("Chrome app was found on empty workspace", workspace.tryGetWorkspaceAppIcon("Chrome")); workspace.ensureWorkspaceIsScrollable(); executeOnLauncher( launcher -> assertEquals("Ensuring workspace scrollable didn't switch to page #1", 1, getCurrentWorkspacePage(launcher))); executeOnLauncher( launcher -> assertTrue("ensureScrollable didn't make workspace scrollable", isWorkspaceScrollable(launcher))); assertNotNull("ensureScrollable didn't add Chrome app", workspace.getWorkspaceAppIcon("Chrome")); // Test flinging workspace. workspace.flingBackward(); assertTrue("Launcher internal state is not Home", isInState(LauncherState.NORMAL)); executeOnLauncher( launcher -> assertEquals("Flinging back didn't switch workspace to page #0", 0, getCurrentWorkspacePage(launcher))); workspace.flingForward(); executeOnLauncher( launcher -> assertEquals("Flinging forward didn't switch workspace to page #1", 1, getCurrentWorkspacePage(launcher))); assertTrue("Launcher internal state is not Home", isInState(LauncherState.NORMAL)); // Test starting a workspace app. final AppIcon app = workspace.getWorkspaceAppIcon("Chrome"); assertNotNull("No Chrome app in workspace", app); } public static void runIconLaunchFromAllAppsTest(AbstractLauncherUiTest test, AllApps allApps) { allApps.freeze(); try { final AppIcon app = allApps.getAppIcon("TestActivity7"); assertNotNull("AppIcon.launch returned null", app.launch(getAppPackageName())); test.executeOnLauncher(launcher -> assertTrue( "Launcher activity is the top activity; expecting another activity to be the " + "top " + "one", test.isInBackground(launcher))); } finally { allApps.unfreeze(); } } @Test @PortraitLandscape public void testAppIconLaunchFromAllAppsFromHome() throws Exception { final AllApps allApps = mLauncher.getWorkspace().switchToAllApps(); assertTrue("Launcher internal state is not All Apps", isInState(LauncherState.ALL_APPS)); runIconLaunchFromAllAppsTest(this, allApps); } @Test @PortraitLandscape public void testWidgets() throws Exception { // Test opening widgets. executeOnLauncher(launcher -> assertTrue("Widgets is initially opened", getWidgetsView(launcher) == null)); Widgets widgets = mLauncher.getWorkspace().openAllWidgets(); assertNotNull("openAllWidgets() returned null", widgets); widgets = mLauncher.getAllWidgets(); assertNotNull("getAllWidgets() returned null", widgets); executeOnLauncher(launcher -> assertTrue("Widgets is not shown", getWidgetsView(launcher).isShown())); executeOnLauncher(launcher -> assertEquals("Widgets is scrolled upon opening", 0, getWidgetsScroll(launcher))); // Test flinging widgets. widgets.flingForward(); Integer flingForwardY = getFromLauncher(launcher -> getWidgetsScroll(launcher)); executeOnLauncher(launcher -> assertTrue("Flinging forward didn't scroll widgets", flingForwardY > 0)); widgets.flingBackward(); executeOnLauncher(launcher -> assertTrue("Flinging backward didn't scroll widgets", getWidgetsScroll(launcher) < flingForwardY)); mLauncher.pressHome(); waitForLauncherCondition("Widgets were not closed", launcher -> getWidgetsView(launcher) == null); } private int getWidgetsScroll(Launcher launcher) { return getWidgetsView(launcher).getCurrentScrollY(); } private boolean isOptionsPopupVisible(Launcher launcher) { final ArrowPopup popup = OptionsPopupView.getOptionsPopup(launcher); return popup != null && popup.isShown(); } @Test @PortraitLandscape public void testLaunchMenuItem() throws Exception { final AllApps allApps = mLauncher. getWorkspace(). switchToAllApps(); allApps.freeze(); try { final AppIconMenu menu = allApps. getAppIcon(APP_NAME). openMenu(); executeOnLauncher( launcher -> assertTrue("Launcher internal state didn't switch to Showing Menu", isOptionsPopupVisible(launcher))); menu.getMenuItem(1).launch(getAppPackageName()); } finally { allApps.unfreeze(); } } @Test @PortraitLandscape public void testDragAppIcon() throws Throwable { // 1. Open all apps and wait for load complete. // 2. Drag icon to homescreen. // 3. Verify that the icon works on homescreen. final AllApps allApps = mLauncher.getWorkspace(). switchToAllApps(); allApps.freeze(); try { allApps.getAppIcon(APP_NAME).dragToWorkspace(); mLauncher.getWorkspace().getWorkspaceAppIcon(APP_NAME).launch(getAppPackageName()); } finally { allApps.unfreeze(); } executeOnLauncher(launcher -> assertTrue( "Launcher activity is the top activity; expecting another activity to be the top " + "one", isInBackground(launcher))); } @Test @PortraitLandscape public void testDragShortcut() throws Throwable { // 1. Open all apps and wait for load complete. // 2. Find the app and long press it to show shortcuts. // 3. Press icon center until shortcuts appear final AllApps allApps = mLauncher. getWorkspace(). switchToAllApps(); allApps.freeze(); try { final AppIconMenuItem menuItem = allApps. getAppIcon(APP_NAME). openMenu(). getMenuItem(0); final String shortcutName = menuItem.getText(); menuItem.dragToWorkspace(); mLauncher.getWorkspace().getWorkspaceAppIcon(shortcutName).launch(getAppPackageName()); } finally { allApps.unfreeze(); } } /** * Test dragging a custom shortcut to the workspace and launch it. * * A custom shortcut is a 1x1 widget that launches a specific intent when user tap on it. * Custom shortcuts are replaced by deep shortcuts after api 25. */ @Test @Ignore // b/143725213 @PortraitLandscape public void testDragCustomShortcut() { mLauncher.getWorkspace().openAllWidgets() .getWidget("com.android.launcher3.testcomponent.CustomShortcutConfigActivity") .dragToWorkspace(); mLauncher.getWorkspace().getWorkspaceAppIcon("Shortcut") .launch(getAppPackageName()); } public static String getAppPackageName() { return getInstrumentation().getContext().getPackageName(); } @Test @Stability public void testTestStabilityAttribute() { Log.d("TestStabilityRule", "Hello world!"); } }