Merge "App Pairs (behind flag): Add Overview menu item, icon, tests" into udc-dev
diff --git a/quickstep/res/drawable/ic_save_app_pair.xml b/quickstep/res/drawable/ic_save_app_pair.xml
new file mode 100644
index 0000000..4a7ee1a
--- /dev/null
+++ b/quickstep/res/drawable/ic_save_app_pair.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ Copyright (C) 2023 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.
+-->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path
+ android:pathData="M13.329,2.305H4.242C2.751,2.305 1.542,3.514 1.542,5.005V13.005C1.542,14.496 2.751,15.705 4.242,15.705H7.875V19.011C7.875,20.502 9.084,21.711 10.575,21.711H19.662C21.153,21.711 22.362,20.502 22.362,19.011V10.011C22.362,8.52 21.153,7.311 19.662,7.311H16.029V5.005C16.029,3.514 14.821,2.305 13.329,2.305ZM14.329,7.311V5.005C14.329,4.452 13.882,4.005 13.329,4.005H4.242C3.69,4.005 3.242,4.452 3.242,5.005V13.005C3.242,13.557 3.69,14.005 4.242,14.005H7.875V10.011C7.875,8.52 9.084,7.311 10.575,7.311H14.329ZM9.575,14.005V10.011C9.575,9.611 9.81,9.266 10.15,9.106C10.285,9.037 10.438,8.999 10.6,8.999H19.687C20.239,8.999 20.687,9.447 20.687,9.999V18.999C20.687,19.399 20.452,19.744 20.113,19.904C19.977,19.972 19.824,20.011 19.662,20.011H10.575C10.023,20.011 9.575,19.563 9.575,19.011V15.705H9.6V14.005H9.575ZM15.542,11.996V14H17.588V15H15.542V16.996H14.542V15H12.464V14H14.542V11.996H15.542Z"
+ android:fillColor="#000000"
+ android:fillType="evenOdd"/>
+</vector>
diff --git a/quickstep/src/com/android/quickstep/TaskOverlayFactory.java b/quickstep/src/com/android/quickstep/TaskOverlayFactory.java
index 6e47ff4..2aa0be6 100644
--- a/quickstep/src/com/android/quickstep/TaskOverlayFactory.java
+++ b/quickstep/src/com/android/quickstep/TaskOverlayFactory.java
@@ -129,7 +129,8 @@
TaskShortcutFactory.PIN,
TaskShortcutFactory.INSTALL,
TaskShortcutFactory.FREE_FORM,
- TaskShortcutFactory.WELLBEING
+ TaskShortcutFactory.WELLBEING,
+ TaskShortcutFactory.SAVE_APP_PAIR
};
/**
diff --git a/quickstep/src/com/android/quickstep/TaskShortcutFactory.java b/quickstep/src/com/android/quickstep/TaskShortcutFactory.java
index 255b910..fd7b343 100644
--- a/quickstep/src/com/android/quickstep/TaskShortcutFactory.java
+++ b/quickstep/src/com/android/quickstep/TaskShortcutFactory.java
@@ -40,6 +40,7 @@
import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.R;
+import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.logging.StatsLogManager.LauncherEvent;
import com.android.launcher3.model.WellbeingModel;
import com.android.launcher3.popup.SystemShortcut;
@@ -63,7 +64,8 @@
import java.util.stream.Collectors;
/**
- * Represents a system shortcut that can be shown for a recent task.
+ * Represents a system shortcut that can be shown for a recent task. Appears as a single entry in
+ * the dropdown menu that shows up when you tap an app icon in Overview.
*/
public interface TaskShortcutFactory {
@Nullable
@@ -122,6 +124,26 @@
}
}
+ /**
+ * A menu item, "Save app pair", that allows the user to preserve the current app combination as
+ * a single persistent icon on the Home screen, allowing for quick split screen initialization.
+ */
+ class SaveAppPairSystemShortcut extends SystemShortcut {
+
+ private final TaskView mTaskView;
+
+ public SaveAppPairSystemShortcut(BaseDraggingActivity target, TaskView taskView) {
+ super(R.drawable.ic_save_app_pair, R.string.save_app_pair, target,
+ taskView.getItemInfo(), taskView);
+ mTaskView = taskView;
+ }
+
+ @Override
+ public void onClick(View view) {
+ // TODO (b/274189428): Call "saveAppPair" function in new AppPairController class
+ }
+ }
+
class FreeformSystemShortcut extends SystemShortcut<BaseDraggingActivity> {
private static final String TAG = "FreeformSystemShortcut";
@@ -257,9 +279,6 @@
final PagedOrientationHandler orientationHandler =
recentsView.getPagedOrientationHandler();
- int[] taskViewTaskIds = taskView.getTaskIds();
- boolean taskViewHasMultipleTasks = taskViewTaskIds[0] != -1 &&
- taskViewTaskIds[1] != -1;
boolean notEnoughTasksToSplit = recentsView.getTaskViewCount() < 2;
boolean isFocusedTask = deviceProfile.isTablet && taskView.isFocusedTask();
boolean isTaskInExpectedScrollPosition =
@@ -267,11 +286,11 @@
boolean isTaskSplitNotSupported = !task.isDockable;
boolean hideForExistingMultiWindow = activity.getDeviceProfile().isMultiWindowMode;
- if (taskViewHasMultipleTasks ||
- notEnoughTasksToSplit ||
- isTaskSplitNotSupported ||
- hideForExistingMultiWindow ||
- (isFocusedTask && isTaskInExpectedScrollPosition)) {
+ if (taskView.containsMultipleTasks()
+ || notEnoughTasksToSplit
+ || isTaskSplitNotSupported
+ || hideForExistingMultiWindow
+ || (isFocusedTask && isTaskInExpectedScrollPosition)) {
return null;
}
@@ -283,6 +302,26 @@
}
};
+ TaskShortcutFactory SAVE_APP_PAIR = new TaskShortcutFactory() {
+ @Nullable
+ @Override
+ public List<SystemShortcut> getShortcuts(BaseDraggingActivity activity,
+ TaskIdAttributeContainer taskContainer) {
+ final TaskView taskView = taskContainer.getTaskView();
+
+ if (!FeatureFlags.ENABLE_APP_PAIRS.get() || !taskView.containsMultipleTasks()) {
+ return null;
+ }
+
+ return Collections.singletonList(new SaveAppPairSystemShortcut(activity, taskView));
+ }
+
+ @Override
+ public boolean showForSplitscreen() {
+ return true;
+ }
+ };
+
TaskShortcutFactory FREE_FORM = new TaskShortcutFactory() {
@Override
public List<SystemShortcut> getShortcuts(BaseDraggingActivity activity,
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
index 9a65b4f..c39d095 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
@@ -186,35 +186,6 @@
actionsView.clickAndDismissScreenshot();
}
- @Test
- @PortraitLandscape
- public void testSplitFromOverview() {
- assumeTrue(!mLauncher.isTablet());
-
- startTestActivity(2);
- startTestActivity(3);
-
- mLauncher.goHome().switchToOverview().getCurrentTask()
- .tapMenu()
- .tapSplitMenuItem()
- .getCurrentTask()
- .open();
- }
-
- @Test
- @PortraitLandscape
- public void testSplitFromOverviewForTablet() {
- assumeTrue(mLauncher.isTablet());
-
- startTestActivity(2);
- startTestActivity(3);
-
- mLauncher.goHome().switchToOverview().getOverviewActions()
- .clickSplit()
- .getTestActivityTask(2)
- .open();
- }
-
private int getCurrentOverviewPage(Launcher launcher) {
return launcher.<RecentsView>getOverviewPanel().getCurrentPage();
}
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsSplitscreen.java b/quickstep/tests/src/com/android/quickstep/TaplTestsSplitscreen.java
index d3fbe93..2ae512a 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsSplitscreen.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsSplitscreen.java
@@ -15,14 +15,18 @@
*/
package com.android.quickstep;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeTrue;
+
import android.content.Intent;
+import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.ui.TaplTestsLauncher3;
import com.android.launcher3.util.rule.TestStabilityRule;
import com.android.quickstep.TaskbarModeSwitchRule.TaskbarModeSwitch;
import org.junit.After;
-import org.junit.Assume;
import org.junit.Before;
import org.junit.Test;
@@ -37,13 +41,6 @@
super.setUp();
TaplTestsLauncher3.initialize(this);
- mLauncher.getWorkspace()
- .deleteAppIcon(mLauncher.getWorkspace().getHotseatAppIcon(0))
- .switchToAllApps()
- .getAppIcon(CALCULATOR_APP_NAME)
- .dragToHotseat(0);
-
- startAppFast(CALCULATOR_APP_PACKAGE);
if (mLauncher.isTablet()) {
mLauncher.enableBlockTimeout(true);
mLauncher.showTaskbarIfHidden();
@@ -58,14 +55,29 @@
}
@Test
+ @PortraitLandscape
+ public void testSplitFromOverview() {
+ createAndLaunchASplitPair();
+ }
+
+ @Test
// TODO (b/270201357): When this test is proven stable, remove this TestStabilityRule and
- // introduce into presubmit as well.
+ // introduce into presubmit as well.
@TestStabilityRule.Stability(
flavors = TestStabilityRule.LOCAL | TestStabilityRule.PLATFORM_POSTSUBMIT)
@PortraitLandscape
@TaskbarModeSwitch
public void testSplitAppFromHomeWithItself() throws Exception {
- Assume.assumeTrue(mLauncher.isTablet());
+ // Currently only tablets have Taskbar in Overview, so test is only active on tablets
+ assumeTrue(mLauncher.isTablet());
+
+ mLauncher.getWorkspace()
+ .deleteAppIcon(mLauncher.getWorkspace().getHotseatAppIcon(0))
+ .switchToAllApps()
+ .getAppIcon(CALCULATOR_APP_NAME)
+ .dragToHotseat(0);
+
+ startAppFast(CALCULATOR_APP_PACKAGE);
mLauncher.goHome()
.switchToAllApps()
@@ -79,4 +91,50 @@
.getAppIcon(CALCULATOR_APP_NAME)
.launchIntoSplitScreen();
}
+
+ @Test
+ public void testSaveAppPairMenuItemExistsOnSplitPair() throws Exception {
+ assumeTrue(FeatureFlags.ENABLE_APP_PAIRS.get());
+
+ createAndLaunchASplitPair();
+
+ assertTrue("Save app pair menu item is missing",
+ mLauncher.goHome()
+ .switchToOverview()
+ .getCurrentTask()
+ .tapMenu()
+ .hasMenuItem("Save app pair"));
+ }
+
+ @Test
+ public void testSaveAppPairMenuItemDoesNotExistOnSingleTask() throws Exception {
+ assumeTrue(FeatureFlags.ENABLE_APP_PAIRS.get());
+
+ startAppFast(CALCULATOR_APP_PACKAGE);
+
+ assertFalse("Save app pair menu item is erroneously appearing on single task",
+ mLauncher.goHome()
+ .switchToOverview()
+ .getCurrentTask()
+ .tapMenu()
+ .hasMenuItem("Save app pair"));
+ }
+
+ private void createAndLaunchASplitPair() {
+ startTestActivity(2);
+ startTestActivity(3);
+
+ if (mLauncher.isTablet()) {
+ mLauncher.goHome().switchToOverview().getOverviewActions()
+ .clickSplit()
+ .getTestActivityTask(2)
+ .open();
+ } else {
+ mLauncher.goHome().switchToOverview().getCurrentTask()
+ .tapMenu()
+ .tapSplitMenuItem()
+ .getCurrentTask()
+ .open();
+ }
+ }
}
diff --git a/res/values/strings.xml b/res/values/strings.xml
index f2fb8f5..7552b22 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -42,6 +42,9 @@
<string name="recent_task_option_split_screen">Split screen</string>
<string name="split_app_info_accessibility">App info for %1$s</string>
+ <!-- App pairs -->
+ <string name="save_app_pair">Save app pair</string>
+
<!-- Widgets -->
<!-- Message to tell the user to press and hold on a widget to add it [CHAR_LIMIT=50] -->
<string name="long_press_widget_to_add">Touch & hold to move a widget.</string>
diff --git a/tests/tapl/com/android/launcher3/tapl/OverviewTaskMenu.java b/tests/tapl/com/android/launcher3/tapl/OverviewTaskMenu.java
index 8cdc8a0..54be3c3 100644
--- a/tests/tapl/com/android/launcher3/tapl/OverviewTaskMenu.java
+++ b/tests/tapl/com/android/launcher3/tapl/OverviewTaskMenu.java
@@ -49,4 +49,10 @@
}
}
}
+
+ /** Returns true if an item matching the given string is present in the menu. */
+ public boolean hasMenuItem(String expectedMenuItemText) {
+ UiObject2 menuItem = mLauncher.findObjectInContainer(mMenu, By.text(expectedMenuItemText));
+ return menuItem != null;
+ }
}