Merge "App Pairs (behind flag): Add Overview menu item, icon, tests" into udc-dev
This commit is contained in:
@@ -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>
|
||||||
@@ -129,7 +129,8 @@ public class TaskOverlayFactory implements ResourceBasedOverride {
|
|||||||
TaskShortcutFactory.PIN,
|
TaskShortcutFactory.PIN,
|
||||||
TaskShortcutFactory.INSTALL,
|
TaskShortcutFactory.INSTALL,
|
||||||
TaskShortcutFactory.FREE_FORM,
|
TaskShortcutFactory.FREE_FORM,
|
||||||
TaskShortcutFactory.WELLBEING
|
TaskShortcutFactory.WELLBEING,
|
||||||
|
TaskShortcutFactory.SAVE_APP_PAIR
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ import androidx.annotation.Nullable;
|
|||||||
import com.android.launcher3.BaseDraggingActivity;
|
import com.android.launcher3.BaseDraggingActivity;
|
||||||
import com.android.launcher3.DeviceProfile;
|
import com.android.launcher3.DeviceProfile;
|
||||||
import com.android.launcher3.R;
|
import com.android.launcher3.R;
|
||||||
|
import com.android.launcher3.config.FeatureFlags;
|
||||||
import com.android.launcher3.logging.StatsLogManager.LauncherEvent;
|
import com.android.launcher3.logging.StatsLogManager.LauncherEvent;
|
||||||
import com.android.launcher3.model.WellbeingModel;
|
import com.android.launcher3.model.WellbeingModel;
|
||||||
import com.android.launcher3.popup.SystemShortcut;
|
import com.android.launcher3.popup.SystemShortcut;
|
||||||
@@ -63,7 +64,8 @@ import java.util.function.Function;
|
|||||||
import java.util.stream.Collectors;
|
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 {
|
public interface TaskShortcutFactory {
|
||||||
@Nullable
|
@Nullable
|
||||||
@@ -122,6 +124,26 @@ public interface TaskShortcutFactory {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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> {
|
class FreeformSystemShortcut extends SystemShortcut<BaseDraggingActivity> {
|
||||||
private static final String TAG = "FreeformSystemShortcut";
|
private static final String TAG = "FreeformSystemShortcut";
|
||||||
|
|
||||||
@@ -257,9 +279,6 @@ public interface TaskShortcutFactory {
|
|||||||
final PagedOrientationHandler orientationHandler =
|
final PagedOrientationHandler orientationHandler =
|
||||||
recentsView.getPagedOrientationHandler();
|
recentsView.getPagedOrientationHandler();
|
||||||
|
|
||||||
int[] taskViewTaskIds = taskView.getTaskIds();
|
|
||||||
boolean taskViewHasMultipleTasks = taskViewTaskIds[0] != -1 &&
|
|
||||||
taskViewTaskIds[1] != -1;
|
|
||||||
boolean notEnoughTasksToSplit = recentsView.getTaskViewCount() < 2;
|
boolean notEnoughTasksToSplit = recentsView.getTaskViewCount() < 2;
|
||||||
boolean isFocusedTask = deviceProfile.isTablet && taskView.isFocusedTask();
|
boolean isFocusedTask = deviceProfile.isTablet && taskView.isFocusedTask();
|
||||||
boolean isTaskInExpectedScrollPosition =
|
boolean isTaskInExpectedScrollPosition =
|
||||||
@@ -267,11 +286,11 @@ public interface TaskShortcutFactory {
|
|||||||
boolean isTaskSplitNotSupported = !task.isDockable;
|
boolean isTaskSplitNotSupported = !task.isDockable;
|
||||||
boolean hideForExistingMultiWindow = activity.getDeviceProfile().isMultiWindowMode;
|
boolean hideForExistingMultiWindow = activity.getDeviceProfile().isMultiWindowMode;
|
||||||
|
|
||||||
if (taskViewHasMultipleTasks ||
|
if (taskView.containsMultipleTasks()
|
||||||
notEnoughTasksToSplit ||
|
|| notEnoughTasksToSplit
|
||||||
isTaskSplitNotSupported ||
|
|| isTaskSplitNotSupported
|
||||||
hideForExistingMultiWindow ||
|
|| hideForExistingMultiWindow
|
||||||
(isFocusedTask && isTaskInExpectedScrollPosition)) {
|
|| (isFocusedTask && isTaskInExpectedScrollPosition)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -283,6 +302,26 @@ public interface TaskShortcutFactory {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
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() {
|
TaskShortcutFactory FREE_FORM = new TaskShortcutFactory() {
|
||||||
@Override
|
@Override
|
||||||
public List<SystemShortcut> getShortcuts(BaseDraggingActivity activity,
|
public List<SystemShortcut> getShortcuts(BaseDraggingActivity activity,
|
||||||
|
|||||||
@@ -186,35 +186,6 @@ public class TaplTestsQuickstep extends AbstractQuickStepTest {
|
|||||||
actionsView.clickAndDismissScreenshot();
|
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) {
|
private int getCurrentOverviewPage(Launcher launcher) {
|
||||||
return launcher.<RecentsView>getOverviewPanel().getCurrentPage();
|
return launcher.<RecentsView>getOverviewPanel().getCurrentPage();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,14 +15,18 @@
|
|||||||
*/
|
*/
|
||||||
package com.android.quickstep;
|
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 android.content.Intent;
|
||||||
|
|
||||||
|
import com.android.launcher3.config.FeatureFlags;
|
||||||
import com.android.launcher3.ui.TaplTestsLauncher3;
|
import com.android.launcher3.ui.TaplTestsLauncher3;
|
||||||
import com.android.launcher3.util.rule.TestStabilityRule;
|
import com.android.launcher3.util.rule.TestStabilityRule;
|
||||||
import com.android.quickstep.TaskbarModeSwitchRule.TaskbarModeSwitch;
|
import com.android.quickstep.TaskbarModeSwitchRule.TaskbarModeSwitch;
|
||||||
|
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Assume;
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
@@ -37,13 +41,6 @@ public class TaplTestsSplitscreen extends AbstractQuickStepTest {
|
|||||||
super.setUp();
|
super.setUp();
|
||||||
TaplTestsLauncher3.initialize(this);
|
TaplTestsLauncher3.initialize(this);
|
||||||
|
|
||||||
mLauncher.getWorkspace()
|
|
||||||
.deleteAppIcon(mLauncher.getWorkspace().getHotseatAppIcon(0))
|
|
||||||
.switchToAllApps()
|
|
||||||
.getAppIcon(CALCULATOR_APP_NAME)
|
|
||||||
.dragToHotseat(0);
|
|
||||||
|
|
||||||
startAppFast(CALCULATOR_APP_PACKAGE);
|
|
||||||
if (mLauncher.isTablet()) {
|
if (mLauncher.isTablet()) {
|
||||||
mLauncher.enableBlockTimeout(true);
|
mLauncher.enableBlockTimeout(true);
|
||||||
mLauncher.showTaskbarIfHidden();
|
mLauncher.showTaskbarIfHidden();
|
||||||
@@ -57,15 +54,30 @@ public class TaplTestsSplitscreen extends AbstractQuickStepTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@PortraitLandscape
|
||||||
|
public void testSplitFromOverview() {
|
||||||
|
createAndLaunchASplitPair();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
// TODO (b/270201357): When this test is proven stable, remove this TestStabilityRule and
|
// 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(
|
@TestStabilityRule.Stability(
|
||||||
flavors = TestStabilityRule.LOCAL | TestStabilityRule.PLATFORM_POSTSUBMIT)
|
flavors = TestStabilityRule.LOCAL | TestStabilityRule.PLATFORM_POSTSUBMIT)
|
||||||
@PortraitLandscape
|
@PortraitLandscape
|
||||||
@TaskbarModeSwitch
|
@TaskbarModeSwitch
|
||||||
public void testSplitAppFromHomeWithItself() throws Exception {
|
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()
|
mLauncher.goHome()
|
||||||
.switchToAllApps()
|
.switchToAllApps()
|
||||||
@@ -79,4 +91,50 @@ public class TaplTestsSplitscreen extends AbstractQuickStepTest {
|
|||||||
.getAppIcon(CALCULATOR_APP_NAME)
|
.getAppIcon(CALCULATOR_APP_NAME)
|
||||||
.launchIntoSplitScreen();
|
.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();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,6 +42,9 @@
|
|||||||
<string name="recent_task_option_split_screen">Split screen</string>
|
<string name="recent_task_option_split_screen">Split screen</string>
|
||||||
<string name="split_app_info_accessibility">App info for %1$s</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 -->
|
<!-- Widgets -->
|
||||||
<!-- Message to tell the user to press and hold on a widget to add it [CHAR_LIMIT=50] -->
|
<!-- 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>
|
<string name="long_press_widget_to_add">Touch & hold to move a widget.</string>
|
||||||
|
|||||||
@@ -49,4 +49,10 @@ public class OverviewTaskMenu {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user