2018-12-06 13:21:16 -08:00
|
|
|
/*
|
2019-01-23 18:44:27 -08:00
|
|
|
* Copyright (C) 2019 The Android Open Source Project
|
2018-12-06 13:21:16 -08:00
|
|
|
*
|
|
|
|
|
* 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.
|
|
|
|
|
*/
|
|
|
|
|
|
2019-01-23 18:44:27 -08:00
|
|
|
package com.android.launcher3.ui;
|
2018-12-06 13:21:16 -08:00
|
|
|
|
|
|
|
|
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.content.Intent;
|
|
|
|
|
import android.util.Log;
|
|
|
|
|
|
|
|
|
|
import androidx.test.filters.LargeTest;
|
|
|
|
|
import androidx.test.runner.AndroidJUnit4;
|
2019-01-23 18:44:27 -08:00
|
|
|
import androidx.test.uiautomator.UiDevice;
|
2018-12-06 13:21:16 -08:00
|
|
|
|
|
|
|
|
import com.android.launcher3.Launcher;
|
|
|
|
|
import com.android.launcher3.LauncherState;
|
2019-03-27 16:56:29 -07:00
|
|
|
import com.android.launcher3.TestProtocol;
|
2019-02-14 13:40:07 -08:00
|
|
|
import com.android.launcher3.popup.ArrowPopup;
|
2018-12-06 13:21:16 -08:00
|
|
|
import com.android.launcher3.tapl.AllApps;
|
|
|
|
|
import com.android.launcher3.tapl.AppIcon;
|
2019-02-14 13:40:07 -08:00
|
|
|
import com.android.launcher3.tapl.AppIconMenu;
|
|
|
|
|
import com.android.launcher3.tapl.AppIconMenuItem;
|
2019-02-15 13:37:48 -08:00
|
|
|
import com.android.launcher3.tapl.TestHelpers;
|
2018-12-06 13:21:16 -08:00
|
|
|
import com.android.launcher3.tapl.Widgets;
|
|
|
|
|
import com.android.launcher3.tapl.Workspace;
|
|
|
|
|
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.Rule;
|
|
|
|
|
import org.junit.Test;
|
|
|
|
|
import org.junit.rules.TestWatcher;
|
|
|
|
|
import org.junit.runner.Description;
|
|
|
|
|
import org.junit.runner.RunWith;
|
|
|
|
|
|
|
|
|
|
import java.io.ByteArrayOutputStream;
|
|
|
|
|
import java.io.File;
|
|
|
|
|
import java.io.IOException;
|
|
|
|
|
|
|
|
|
|
@LargeTest
|
|
|
|
|
@RunWith(AndroidJUnit4.class)
|
2019-01-23 18:44:27 -08:00
|
|
|
public class TaplTestsLauncher3 extends AbstractLauncherUiTest {
|
|
|
|
|
private static final String TAG = "TaplTestsAosp";
|
2019-04-05 18:35:29 -07:00
|
|
|
private static final String APP_NAME = "LauncherTestApp";
|
2018-12-06 13:21:16 -08:00
|
|
|
|
|
|
|
|
private static int sScreenshotCount = 0;
|
|
|
|
|
|
2019-01-23 18:44:27 -08:00
|
|
|
public static class FailureWatcher extends TestWatcher {
|
|
|
|
|
private UiDevice mDevice;
|
|
|
|
|
|
|
|
|
|
public FailureWatcher(UiDevice device) {
|
|
|
|
|
this.mDevice = device;
|
|
|
|
|
}
|
|
|
|
|
|
2018-12-06 13:21:16 -08:00
|
|
|
private void dumpViewHierarchy() {
|
|
|
|
|
final ByteArrayOutputStream stream = new ByteArrayOutputStream();
|
|
|
|
|
try {
|
|
|
|
|
mDevice.dumpWindowHierarchy(stream);
|
|
|
|
|
stream.flush();
|
|
|
|
|
stream.close();
|
|
|
|
|
for (String line : stream.toString().split("\\r?\\n")) {
|
2019-01-23 18:44:27 -08:00
|
|
|
Log.e(TAG, line.trim());
|
2018-12-06 13:21:16 -08:00
|
|
|
}
|
|
|
|
|
} catch (IOException e) {
|
2019-01-23 18:44:27 -08:00
|
|
|
Log.e(TAG, "error dumping XML to logcat", e);
|
2018-12-06 13:21:16 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
protected void failed(Throwable e, Description description) {
|
|
|
|
|
if (mDevice == null) return;
|
|
|
|
|
final String pathname = getInstrumentation().getTargetContext().
|
|
|
|
|
getFilesDir().getPath() + "/TaplTestScreenshot" + sScreenshotCount++ + ".png";
|
2019-01-23 18:44:27 -08:00
|
|
|
Log.e(TAG, "Failed test " + description.getMethodName() +
|
2018-12-06 13:21:16 -08:00
|
|
|
", screenshot will be saved to " + pathname +
|
|
|
|
|
", track trace is below, UI object dump is further below:\n" +
|
|
|
|
|
Log.getStackTraceString(e));
|
|
|
|
|
dumpViewHierarchy();
|
|
|
|
|
mDevice.takeScreenshot(new File(pathname));
|
|
|
|
|
}
|
2019-01-23 18:44:27 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Rule
|
|
|
|
|
public TestWatcher mFailureWatcher = new FailureWatcher(mDevice);
|
2018-12-06 13:21:16 -08:00
|
|
|
|
|
|
|
|
@Before
|
|
|
|
|
public void setUp() throws Exception {
|
|
|
|
|
super.setUp();
|
2019-02-15 12:08:19 -08:00
|
|
|
initialize(this);
|
|
|
|
|
}
|
2018-12-06 13:21:16 -08:00
|
|
|
|
2019-02-15 12:08:19 -08:00
|
|
|
public static void initialize(AbstractLauncherUiTest test) throws Exception {
|
|
|
|
|
test.clearLauncherData();
|
2019-02-22 14:31:24 -08:00
|
|
|
if (TestHelpers.isInLauncherProcess()) {
|
|
|
|
|
test.mActivityMonitor.returnToHome();
|
|
|
|
|
} else {
|
|
|
|
|
test.mDevice.pressHome();
|
|
|
|
|
}
|
2019-02-15 12:08:19 -08:00
|
|
|
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");
|
2019-04-22 14:07:23 -07:00
|
|
|
// Check that we switched to home.
|
|
|
|
|
test.mLauncher.getWorkspace();
|
2018-12-06 13:21:16 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Please don't add negative test cases for methods that fail only after a long wait.
|
2019-01-23 18:44:27 -08:00
|
|
|
public static void expectFail(String message, Runnable action) {
|
2018-12-06 13:21:16 -08:00
|
|
|
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));
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-23 18:44:27 -08:00
|
|
|
public static void runAllAppsTest(AbstractLauncherUiTest test, AllApps allApps) {
|
2018-12-06 13:21:16 -08:00
|
|
|
assertNotNull("allApps parameter is null", allApps);
|
|
|
|
|
|
2019-01-23 18:44:27 -08:00
|
|
|
assertTrue(
|
|
|
|
|
"Launcher internal state is not All Apps", test.isInState(LauncherState.ALL_APPS));
|
2018-12-06 13:21:16 -08:00
|
|
|
|
|
|
|
|
// Test flinging forward and backward.
|
2019-01-23 18:44:27 -08:00
|
|
|
test.executeOnLauncher(launcher -> assertEquals(
|
|
|
|
|
"All Apps started in already scrolled state", 0, test.getAllAppsScroll(launcher)));
|
2018-12-06 13:21:16 -08:00
|
|
|
|
|
|
|
|
allApps.flingForward();
|
2019-01-23 18:44:27 -08:00
|
|
|
assertTrue("Launcher internal state is not All Apps",
|
|
|
|
|
test.isInState(LauncherState.ALL_APPS));
|
|
|
|
|
final Integer flingForwardY = test.getFromLauncher(
|
|
|
|
|
launcher -> test.getAllAppsScroll(launcher));
|
|
|
|
|
test.executeOnLauncher(
|
2018-12-06 13:21:16 -08:00
|
|
|
launcher -> assertTrue("flingForward() didn't scroll App Apps", flingForwardY > 0));
|
|
|
|
|
|
|
|
|
|
allApps.flingBackward();
|
2019-01-23 18:44:27 -08:00
|
|
|
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",
|
2018-12-06 13:21:16 -08:00
|
|
|
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"));
|
|
|
|
|
|
2019-01-23 18:44:27 -08:00
|
|
|
assertTrue(
|
|
|
|
|
"Launcher internal state is not All Apps", test.isInState(LauncherState.ALL_APPS));
|
2018-12-06 13:21:16 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@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)));
|
2019-04-03 18:31:43 -07:00
|
|
|
assertNull("Chrome app was found on empty workspace",
|
|
|
|
|
workspace.tryGetWorkspaceAppIcon("Chrome"));
|
2018-12-06 13:21:16 -08:00
|
|
|
|
|
|
|
|
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)));
|
2019-04-03 18:31:43 -07:00
|
|
|
assertNotNull("ensureScrollable didn't add Chrome app",
|
|
|
|
|
workspace.tryGetWorkspaceAppIcon("Chrome"));
|
2018-12-06 13:21:16 -08:00
|
|
|
|
|
|
|
|
// 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.
|
2019-04-03 18:31:43 -07:00
|
|
|
final AppIcon app = workspace.tryGetWorkspaceAppIcon("Chrome");
|
|
|
|
|
assertNotNull("No Chrome app in workspace", app);
|
2018-12-06 13:21:16 -08:00
|
|
|
}
|
|
|
|
|
|
2019-01-23 18:44:27 -08:00
|
|
|
public static void runIconLaunchFromAllAppsTest(AbstractLauncherUiTest test, AllApps allApps) {
|
2018-12-06 13:21:16 -08:00
|
|
|
final AppIcon app = allApps.getAppIcon("Calculator");
|
|
|
|
|
assertNotNull("AppIcon.launch returned null", app.launch(
|
2019-01-23 18:44:27 -08:00
|
|
|
test.resolveSystemApp(Intent.CATEGORY_APP_CALCULATOR)));
|
|
|
|
|
test.executeOnLauncher(launcher -> assertTrue(
|
2018-12-06 13:21:16 -08:00
|
|
|
"Launcher activity is the top activity; expecting another activity to be the top "
|
|
|
|
|
+ "one",
|
2019-01-23 18:44:27 -08:00
|
|
|
test.isInBackground(launcher)));
|
2018-12-06 13:21:16 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@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));
|
|
|
|
|
|
2019-01-23 18:44:27 -08:00
|
|
|
runIconLaunchFromAllAppsTest(this, allApps);
|
2018-12-06 13:21:16 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@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));
|
|
|
|
|
|
2019-01-11 16:56:44 -08:00
|
|
|
mLauncher.pressHome();
|
2018-12-06 13:21:16 -08:00
|
|
|
waitForLauncherCondition("Widgets were not closed",
|
|
|
|
|
launcher -> getWidgetsView(launcher) == null);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private int getWidgetsScroll(Launcher launcher) {
|
|
|
|
|
return getWidgetsView(launcher).getCurrentScrollY();
|
|
|
|
|
}
|
2019-02-14 13:40:07 -08:00
|
|
|
|
|
|
|
|
private boolean isOptionsPopupVisible(Launcher launcher) {
|
|
|
|
|
final ArrowPopup popup = OptionsPopupView.getOptionsPopup(launcher);
|
|
|
|
|
return popup != null && popup.isShown();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
@PortraitLandscape
|
|
|
|
|
public void testLaunchMenuItem() throws Exception {
|
2019-02-15 13:37:48 -08:00
|
|
|
if (!TestHelpers.isInLauncherProcess()) return;
|
2019-02-14 13:40:07 -08:00
|
|
|
|
|
|
|
|
final AppIconMenu menu = mLauncher.
|
|
|
|
|
getWorkspace().
|
|
|
|
|
switchToAllApps().
|
2019-04-05 18:35:29 -07:00
|
|
|
getAppIcon(APP_NAME).
|
2019-02-14 13:40:07 -08:00
|
|
|
openMenu();
|
|
|
|
|
|
|
|
|
|
executeOnLauncher(
|
|
|
|
|
launcher -> assertTrue("Launcher internal state didn't switch to Showing Menu",
|
|
|
|
|
isOptionsPopupVisible(launcher)));
|
|
|
|
|
|
|
|
|
|
final AppIconMenuItem menuItem = menu.getMenuItem(1);
|
|
|
|
|
final String itemName = menuItem.getText();
|
|
|
|
|
|
2019-04-11 13:50:14 -07:00
|
|
|
menuItem.launch(getAppPackageName());
|
2019-02-14 13:40:07 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
@PortraitLandscape
|
|
|
|
|
public void testDragAppIcon() throws Throwable {
|
2019-03-27 16:56:29 -07:00
|
|
|
try {
|
|
|
|
|
TestProtocol.sDebugTracing = true;
|
|
|
|
|
// 1. Open all apps and wait for load complete.
|
|
|
|
|
// 2. Drag icon to homescreen.
|
|
|
|
|
// 3. Verify that the icon works on homescreen.
|
|
|
|
|
mLauncher.getWorkspace().
|
|
|
|
|
switchToAllApps().
|
2019-04-05 18:35:29 -07:00
|
|
|
getAppIcon(APP_NAME).
|
2019-03-27 16:56:29 -07:00
|
|
|
dragToWorkspace().
|
2019-04-05 18:35:29 -07:00
|
|
|
getWorkspaceAppIcon(APP_NAME).
|
2019-04-11 13:50:14 -07:00
|
|
|
launch(getAppPackageName());
|
2019-04-26 14:38:21 -07:00
|
|
|
executeOnLauncher(launcher -> assertTrue(
|
|
|
|
|
"Launcher activity is the top activity; expecting another activity to be the "
|
|
|
|
|
+ "top one",
|
|
|
|
|
isInBackground(launcher)));
|
2019-03-27 16:56:29 -07:00
|
|
|
} finally {
|
|
|
|
|
TestProtocol.sDebugTracing = false;
|
|
|
|
|
}
|
2019-02-14 13:40:07 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
@PortraitLandscape
|
|
|
|
|
public void testDragShortcut() throws Throwable {
|
2019-02-15 13:37:48 -08:00
|
|
|
if (!TestHelpers.isInLauncherProcess()) return;
|
2019-02-14 13:40:07 -08:00
|
|
|
|
|
|
|
|
// 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 AppIconMenuItem menuItem = mLauncher.
|
|
|
|
|
getWorkspace().
|
|
|
|
|
switchToAllApps().
|
2019-04-05 18:35:29 -07:00
|
|
|
getAppIcon(APP_NAME).
|
2019-02-14 13:40:07 -08:00
|
|
|
openMenu().
|
|
|
|
|
getMenuItem(0);
|
|
|
|
|
final String shortcutName = menuItem.getText();
|
|
|
|
|
|
|
|
|
|
// 4. Drag the first shortcut to the home screen.
|
|
|
|
|
// 5. Verify that the shortcut works on home screen
|
|
|
|
|
// (the app opens and has the same text as the shortcut).
|
|
|
|
|
menuItem.
|
|
|
|
|
dragToWorkspace().
|
|
|
|
|
getWorkspaceAppIcon(shortcutName).
|
2019-04-11 13:50:14 -07:00
|
|
|
launch(getAppPackageName());
|
2019-04-05 18:35:29 -07:00
|
|
|
}
|
|
|
|
|
|
2019-04-22 15:36:18 -07:00
|
|
|
public static String getAppPackageName() {
|
2019-04-05 18:35:29 -07:00
|
|
|
return getInstrumentation().getContext().getPackageName();
|
2019-02-14 13:40:07 -08:00
|
|
|
}
|
2018-12-06 13:21:16 -08:00
|
|
|
}
|