Merge "Import translations. DO NOT MERGE ANYWHERE" into sc-v2-dev
diff --git a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
index 2ccec44..a83f51a 100644
--- a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
+++ b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
@@ -175,6 +175,7 @@
     public static final int RECENTS_LAUNCH_DURATION = 336;
     private static final int LAUNCHER_RESUME_START_DELAY = 100;
     private static final int CLOSING_TRANSITION_DURATION_MS = 250;
+    public static final int SPLIT_LAUNCH_DURATION = 370;
 
     public static final int CONTENT_ALPHA_DURATION = 217;
     protected static final int CONTENT_SCALE_DURATION = 350;
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index 7a510ac..a2e4c22 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -166,7 +166,8 @@
                 new StashedHandleViewController(this, stashedHandleView),
                 new TaskbarStashController(this),
                 new TaskbarEduController(this),
-                new TaskbarAutohideSuspendController(this));
+                new TaskbarAutohideSuspendController(this),
+                new TaskbarPopupController());
     }
 
     public void init(TaskbarSharedState sharedState) {
@@ -255,6 +256,11 @@
         return false;
     }
 
+    @Override
+    public View.OnClickListener getItemOnClickListener() {
+        return this::onTaskbarIconClicked;
+    }
+
     /**
      * Change from hotseat/predicted hotseat to taskbar container.
      */
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
index 08a79c0..56730db 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
@@ -38,6 +38,7 @@
     public final TaskbarStashController taskbarStashController;
     public final TaskbarEduController taskbarEduController;
     public final TaskbarAutohideSuspendController taskbarAutohideSuspendController;
+    public final TaskbarPopupController taskbarPopupController;
 
     /** Do not store this controller, as it may change at runtime. */
     @NonNull public TaskbarUIController uiController = TaskbarUIController.DEFAULT;
@@ -55,7 +56,8 @@
             StashedHandleViewController stashedHandleViewController,
             TaskbarStashController taskbarStashController,
             TaskbarEduController taskbarEduController,
-            TaskbarAutohideSuspendController taskbarAutoHideSuspendController) {
+            TaskbarAutohideSuspendController taskbarAutoHideSuspendController,
+            TaskbarPopupController taskbarPopupController) {
         this.taskbarActivityContext = taskbarActivityContext;
         this.taskbarDragController = taskbarDragController;
         this.navButtonController = navButtonController;
@@ -70,6 +72,7 @@
         this.taskbarStashController = taskbarStashController;
         this.taskbarEduController = taskbarEduController;
         this.taskbarAutohideSuspendController = taskbarAutoHideSuspendController;
+        this.taskbarPopupController = taskbarPopupController;
     }
 
     /**
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
index 3bcacb6..b3a9f8d 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
@@ -40,6 +40,7 @@
 import com.android.launcher3.LauncherSettings;
 import com.android.launcher3.R;
 import com.android.launcher3.accessibility.DragViewStateAnnouncer;
+import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.dragndrop.DragController;
 import com.android.launcher3.dragndrop.DragDriver;
 import com.android.launcher3.dragndrop.DragOptions;
@@ -49,6 +50,7 @@
 import com.android.launcher3.logging.StatsLogManager;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
+import com.android.launcher3.popup.PopupContainerWithArrow;
 import com.android.systemui.shared.recents.model.Task;
 import com.android.systemui.shared.system.ClipDescriptionCompat;
 import com.android.systemui.shared.system.LauncherAppsCompat;
@@ -139,11 +141,13 @@
                 mDragView = null;
             }
         };
-        // TODO: open popup/pre-drag
-        // PopupContainerWithArrow popupContainer = PopupContainerWithArrow.showForIcon(view);
-        // if (popupContainer != null) {
-        //     dragOptions.preDragCondition = popupContainer.createPreDragCondition();
-        // }
+        if (FeatureFlags.ENABLE_TASKBAR_POPUP_MENU.get()) {
+            PopupContainerWithArrow<TaskbarActivityContext> popupContainer =
+                    mControllers.taskbarPopupController.showForIcon(btv);
+            if (popupContainer != null) {
+                dragOptions.preDragCondition = popupContainer.createPreDragCondition();
+            }
+        }
 
         startDrag(
                 drawable,
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java
index 5e76b96..6dcfe56 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java
@@ -23,6 +23,7 @@
 import com.android.launcher3.model.BgDataModel.FixedContainerItems;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
+import com.android.launcher3.util.ComponentKey;
 import com.android.launcher3.util.IntArray;
 import com.android.launcher3.util.IntSet;
 import com.android.launcher3.util.ItemInfoMatcher;
@@ -30,6 +31,7 @@
 
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 
@@ -186,4 +188,9 @@
                 TaskbarStashController.FLAG_STASHED_IN_APP_EMPTY, isHotseatEmpty);
         mControllers.taskbarStashController.applyState();
     }
+
+    @Override
+    public void bindDeepShortcutMap(HashMap<ComponentKey, Integer> deepShortcutMapCopy) {
+        mControllers.taskbarPopupController.setDeepShortcutMap(deepShortcutMapCopy);
+    }
 }
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java
new file mode 100644
index 0000000..952f597
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2021 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.taskbar;
+
+import androidx.annotation.NonNull;
+
+import com.android.launcher3.BubbleTextView;
+import com.android.launcher3.R;
+import com.android.launcher3.model.data.ItemInfo;
+import com.android.launcher3.popup.PopupContainerWithArrow;
+import com.android.launcher3.popup.PopupDataProvider;
+import com.android.launcher3.popup.SystemShortcut;
+import com.android.launcher3.util.ComponentKey;
+import com.android.launcher3.views.ActivityContext;
+
+import java.util.HashMap;
+import java.util.Objects;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+/**
+ * Implements interfaces required to show and allow interacting with a PopupContainerWithArrow.
+ */
+public class TaskbarPopupController {
+
+    private static final SystemShortcut.Factory<TaskbarActivityContext>
+            APP_INFO = SystemShortcut.AppInfo::new;
+
+    private final PopupDataProvider mPopupDataProvider;
+
+    public TaskbarPopupController() {
+        // TODO (b/198438631): add notifications dots change listener
+        mPopupDataProvider = new PopupDataProvider(packageUserKey -> {});
+    }
+
+    @NonNull
+    public PopupDataProvider getPopupDataProvider() {
+        return mPopupDataProvider;
+    }
+
+    public void setDeepShortcutMap(HashMap<ComponentKey, Integer> deepShortcutMapCopy) {
+        mPopupDataProvider.setDeepShortcutMap(deepShortcutMapCopy);
+    }
+
+    /**
+     * Shows the notifications and deep shortcuts associated with a Taskbar {@param icon}.
+     * @return the container if shown or null.
+     */
+    public PopupContainerWithArrow<TaskbarActivityContext> showForIcon(BubbleTextView icon) {
+        TaskbarActivityContext context = ActivityContext.lookupContext(icon.getContext());
+        if (PopupContainerWithArrow.getOpen(context) != null) {
+            // There is already an items container open, so don't open this one.
+            icon.clearFocus();
+            return null;
+        }
+        ItemInfo item = (ItemInfo) icon.getTag();
+        if (!PopupContainerWithArrow.canShow(icon, item)) {
+            return null;
+        }
+
+        final PopupContainerWithArrow<TaskbarActivityContext> container =
+                (PopupContainerWithArrow) context.getLayoutInflater().inflate(
+                        R.layout.popup_container, context.getDragLayer(), false);
+        // TODO (b/198438631): configure for taskbar/context
+
+        container.populateAndShow(icon,
+                mPopupDataProvider.getShortcutCountForItem(item),
+                mPopupDataProvider.getNotificationKeysForItem(item),
+                // TODO (b/198438631): add support for INSTALL shortcut factory
+                Stream.of(APP_INFO)
+                        .map(s -> s.getShortcut(context, item))
+                        .filter(Objects::nonNull)
+                        .collect(Collectors.toList()));
+        container.requestFocus();
+        return container;
+    }
+}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
index 09197c3..c47bde9 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
@@ -261,7 +261,7 @@
         private boolean mCanceledStashHint;
 
         public View.OnClickListener getIconOnClickListener() {
-            return mActivity::onTaskbarIconClicked;
+            return mActivity.getItemOnClickListener();
         }
 
         public View.OnLongClickListener getIconOnLongClickListener() {
diff --git a/quickstep/src/com/android/quickstep/TaskViewUtils.java b/quickstep/src/com/android/quickstep/TaskViewUtils.java
index 12b071d..15729e1 100644
--- a/quickstep/src/com/android/quickstep/TaskViewUtils.java
+++ b/quickstep/src/com/android/quickstep/TaskViewUtils.java
@@ -28,6 +28,7 @@
 import static com.android.launcher3.QuickstepTransitionManager.NAV_FADE_IN_INTERPOLATOR;
 import static com.android.launcher3.QuickstepTransitionManager.NAV_FADE_OUT_INTERPOLATOR;
 import static com.android.launcher3.QuickstepTransitionManager.RECENTS_LAUNCH_DURATION;
+import static com.android.launcher3.QuickstepTransitionManager.SPLIT_LAUNCH_DURATION;
 import static com.android.launcher3.Utilities.getDescendantCoordRelativeToAncestor;
 import static com.android.launcher3.anim.Interpolators.LINEAR;
 import static com.android.launcher3.anim.Interpolators.TOUCH_RESPONSE_INTERPOLATOR;
@@ -459,6 +460,7 @@
 
         final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
         ValueAnimator animator = ValueAnimator.ofFloat(0f, 1f);
+        animator.setDuration(SPLIT_LAUNCH_DURATION);
         animator.addUpdateListener(valueAnimator -> {
             float progress = valueAnimator.getAnimatedFraction();
             for (SurfaceControl leash: openingTargets) {
@@ -559,7 +561,7 @@
         anim.addListener(windowAnimEndListener);
     }
 
-    static void setSplitAuxiliarySurfacesShown(RemoteAnimationTargetCompat[] nonApps,
+    public static void setSplitAuxiliarySurfacesShown(RemoteAnimationTargetCompat[] nonApps,
             boolean shown) {
         // TODO(b/182592057): make this part of the animations instead.
         if (nonApps != null && nonApps.length > 0) {
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index b5238c6..33ba7dd 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -4241,6 +4241,10 @@
         }
         mPendingAnimation.addEndListener(isSuccess -> {
             if (isSuccess) {
+                if (tv.getTaskIds()[1] != -1) {
+                    TaskViewUtils.setSplitAuxiliarySurfacesShown(mRemoteTargetHandles[0]
+                            .getTransformParams().getTargetSet().nonApps, true);
+                }
                 if (ENABLE_QUICKSTEP_LIVE_TILE.get() && tv.isRunningTask()) {
                     finishRecentsAnimation(false /* toRecents */, null);
                     onTaskLaunchAnimationEnd(true /* success */);
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index 1358387..d362994 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -204,6 +204,10 @@
     public static final BooleanFlag ENABLE_TASKBAR_EDU = getDebugFlag("ENABLE_TASKBAR_EDU", true,
             "Enables showing taskbar education the first time an app is opened.");
 
+    public static final BooleanFlag ENABLE_TASKBAR_POPUP_MENU = getDebugFlag(
+            "ENABLE_TASKBAR_POPUP_MENU", false, "Enables long pressing taskbar icons to show the"
+                    + " popup menu.");
+
     public static final BooleanFlag ENABLE_OVERVIEW_GRID = getDebugFlag(
             "ENABLE_OVERVIEW_GRID", true, "Uses grid overview layout. "
             + "Only applicable on large screen devices.");
diff --git a/src/com/android/launcher3/statemanager/StateManager.java b/src/com/android/launcher3/statemanager/StateManager.java
index b34af97..1767939 100644
--- a/src/com/android/launcher3/statemanager/StateManager.java
+++ b/src/com/android/launcher3/statemanager/StateManager.java
@@ -84,7 +84,7 @@
                 + ", mCurrentStableState:" + mCurrentStableState
                 + ", mState:" + mState
                 + ", mRestState:" + mRestState
-                + ", isInTransition:" + (mConfig.currentAnimation != null) + ")";
+                + ", isInTransition:" + isInTransition() + ")";
     }
 
     public void dump(String prefix, PrintWriter writer) {
@@ -93,7 +93,7 @@
         writer.println(prefix + "\tmCurrentStableState:" + mCurrentStableState);
         writer.println(prefix + "\tmState:" + mState);
         writer.println(prefix + "\tmRestState:" + mRestState);
-        writer.println(prefix + "\tisInTransition:" + (mConfig.currentAnimation != null));
+        writer.println(prefix + "\tisInTransition:" + isInTransition());
     }
 
     public StateHandler[] getStateHandlers() {
@@ -130,6 +130,13 @@
     }
 
     /**
+     * @return {@code true} If there is an active transition.
+     */
+    public boolean isInTransition() {
+        return mConfig.currentAnimation != null;
+    }
+
+    /**
      * @see #goToState(STATE_TYPE, boolean, AnimatorListener)
      */
     public void goToState(STATE_TYPE state) {
diff --git a/src/com/android/launcher3/testing/TestInformationHandler.java b/src/com/android/launcher3/testing/TestInformationHandler.java
index 17d925c..8ebfd62 100644
--- a/src/com/android/launcher3/testing/TestInformationHandler.java
+++ b/src/com/android/launcher3/testing/TestInformationHandler.java
@@ -157,6 +157,12 @@
                 return response;
             }
 
+            case TestProtocol.REQUEST_ENABLE_ROTATION:
+                MAIN_EXECUTOR.submit(() ->
+                        Launcher.ACTIVITY_TRACKER.getCreatedActivity().getRotationHelper()
+                                .forceAllowRotationForTesting(Boolean.parseBoolean(arg)));
+                return null;
+
             default:
                 return null;
         }
diff --git a/src/com/android/launcher3/testing/TestProtocol.java b/src/com/android/launcher3/testing/TestProtocol.java
index 91c7221..9a74fb1 100644
--- a/src/com/android/launcher3/testing/TestProtocol.java
+++ b/src/com/android/launcher3/testing/TestProtocol.java
@@ -108,6 +108,7 @@
             "get-focused-task-height-for-tablet";
     public static final String REQUEST_GET_GRID_TASK_SIZE_RECT_FOR_TABLET =
             "get-grid-task-size-rect-for-tablet";
+    public static final String REQUEST_ENABLE_ROTATION = "enable_rotation";
 
     public static Long sForcePauseTimeout;
     public static final String REQUEST_SET_FORCE_PAUSE_TIMEOUT = "set-force-pause-timeout";
diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
index b3457cd..44f2719 100644
--- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
+++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
@@ -354,9 +354,10 @@
 
     // Cannot be used in TaplTests between a Tapl call injecting a gesture and a tapl call
     // expecting the results of that gesture because the wait can hide flakeness.
-    protected void waitForStableState(String message, Supplier<LauncherState> state) {
+    protected void waitForStateTransitionToEnd(String message, Supplier<LauncherState> state) {
         waitForLauncherCondition(message,
-                launcher -> launcher.getStateManager().isInStableState(state.get()));
+                launcher -> launcher.getStateManager().isInStableState(state.get())
+                        && !launcher.getStateManager().isInTransition());
     }
 
     protected void waitForResumed(String message) {
diff --git a/tests/src/com/android/launcher3/ui/WorkProfileTest.java b/tests/src/com/android/launcher3/ui/WorkProfileTest.java
index 2087bfe..aca5951 100644
--- a/tests/src/com/android/launcher3/ui/WorkProfileTest.java
+++ b/tests/src/com/android/launcher3/ui/WorkProfileTest.java
@@ -91,9 +91,11 @@
     public void workTabExists() {
         mDevice.pressHome();
         waitForLauncherCondition("Launcher didn't start", Objects::nonNull);
-        waitForStableState("Launcher internal state didn't switch to Normal", () -> NORMAL);
+        waitForStateTransitionToEnd("Launcher internal state didn't switch to Normal",
+                () -> NORMAL);
         executeOnLauncher(launcher -> launcher.getStateManager().goToState(ALL_APPS));
-        waitForStableState("Launcher internal state didn't switch to All Apps", () -> ALL_APPS);
+        waitForStateTransitionToEnd("Launcher internal state didn't switch to All Apps",
+                () -> ALL_APPS);
         waitForLauncherCondition("Personal tab is missing",
                 launcher -> launcher.getAppsView().isPersonalTabVisible(),
                 LauncherInstrumentation.WAIT_TIME_MS);
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index e2d0238..5a807ca 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -350,6 +350,10 @@
         getTestInfo(TestProtocol.REQUEST_SET_FORCE_PAUSE_TIMEOUT, Long.toString(timeout));
     }
 
+    public void setEnableRotation(boolean on) {
+        getTestInfo(TestProtocol.REQUEST_ENABLE_ROTATION, Boolean.toString(on));
+    }
+
     public boolean hadNontestEvents() {
         return getTestInfo(TestProtocol.REQUEST_GET_HAD_NONTEST_EVENTS)
                 .getBoolean(TestProtocol.TEST_INFO_RESPONSE_FIELD);