Merge "Initialize the archiving compat options during launcher3 startup." into main
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarEduTooltipController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarEduTooltipController.kt
index eea543e..7eed955 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarEduTooltipController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarEduTooltipController.kt
@@ -171,6 +171,7 @@
         // for the original 2 edu steps) as a proxy to needing to show the separate pinning edu
         if (
             !enableTaskbarPinning() ||
+                !DisplayController.isTransientTaskbar(activityContext) ||
                 !isTooltipEnabled ||
                 tooltipStep > TOOLTIP_STEP_PINNING ||
                 tooltipStep < TOOLTIP_STEP_FEATURES
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java
index 3fb7247..5819bb3 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java
@@ -46,6 +46,8 @@
 import android.graphics.Color;
 import android.graphics.Matrix;
 import android.graphics.Path;
+import android.graphics.Point;
+import android.graphics.Rect;
 import android.graphics.drawable.AdaptiveIconDrawable;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
@@ -66,6 +68,7 @@
 import com.android.launcher3.icons.BubbleIconFactory;
 import com.android.launcher3.shortcuts.ShortcutRequest;
 import com.android.launcher3.taskbar.TaskbarControllers;
+import com.android.launcher3.util.DisplayController;
 import com.android.launcher3.util.Executors.SimpleThreadFactory;
 import com.android.quickstep.SystemUiProxy;
 import com.android.wm.shell.bubbles.IBubblesListener;
@@ -408,8 +411,7 @@
                         info.getFlags() | Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION);
                 mSelectedBubble.getView().updateDotVisibility(true /* animate */);
             }
-            mSystemUiProxy.showBubble(getSelectedBubbleKey(),
-                    getBubbleBarOffsetX(), getBubbleBarOffsetY());
+            mSystemUiProxy.showBubble(getSelectedBubbleKey(), getExpandedBubbleBarDisplayBounds());
         } else {
             Log.w(TAG, "Trying to show the selected bubble but it's null");
         }
@@ -577,12 +579,27 @@
         return mIconFactory.createBadgedIconBitmap(drawable).icon;
     }
 
-    private int getBubbleBarOffsetY() {
+    /**
+     * Get bounds of the bubble bar as if it would be expanded.
+     * Calculates the bounds instead of retrieving current view location as the view may be
+     * animating.
+     */
+    private Rect getExpandedBubbleBarDisplayBounds() {
+        Point displaySize = DisplayController.INSTANCE.get(mContext).getInfo().currentSize;
+        Rect currentBarBounds = mBarView.getBubbleBarBounds();
+        Rect location = new Rect();
+        // currentBarBounds is only useful for distance from left or right edge.
+        // It contains the current bounds, calculate the expanded bounds.
+        if (mBarView.isOnLeft()) {
+            location.left = currentBarBounds.left;
+            location.right = (int) (currentBarBounds.left + mBarView.expandedWidth());
+        } else {
+            location.left = (int) (currentBarBounds.right - mBarView.expandedWidth());
+            location.right = currentBarBounds.right;
+        }
         final int translation = (int) abs(mBubbleStashController.getBubbleBarTranslationY());
-        return translation + mBarView.getHeight();
-    }
-
-    private int getBubbleBarOffsetX() {
-        return mBarView.getWidth() + mBarView.getHorizontalMargin();
+        location.top = displaySize.y - mBarView.getHeight() - translation;
+        location.bottom = displaySize.y - translation;
+        return location;
     }
 }
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
index fbc7da1..8f693a6 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
@@ -205,7 +205,10 @@
         mRelativePivotX = onLeft ? 0f : 1f;
     }
 
-    private boolean isOnLeft() {
+    /**
+     * @return <code>true</code> when bar is pinned to the left edge of the screen
+     */
+    public boolean isOnLeft() {
         return getLayoutDirection() == LAYOUT_DIRECTION_RTL;
     }
 
@@ -509,7 +512,12 @@
         return mIsBarExpanded;
     }
 
-    private float expandedWidth() {
+    /**
+     * Get width of the bubble bar as if it would be expanded.
+     *
+     * @return width of the bubble bar in its expanded state, regardless of current width
+     */
+    public float expandedWidth() {
         final int childCount = getChildCount();
         final int horizontalPadding = getPaddingStart() + getPaddingEnd();
         return childCount * (mIconSize + mIconSpacing) + horizontalPadding;
diff --git a/quickstep/src/com/android/quickstep/SystemUiProxy.java b/quickstep/src/com/android/quickstep/SystemUiProxy.java
index 56a4024..52f9d8d 100644
--- a/quickstep/src/com/android/quickstep/SystemUiProxy.java
+++ b/quickstep/src/com/android/quickstep/SystemUiProxy.java
@@ -731,15 +731,12 @@
     /**
      * Tells SysUI to show the bubble with the provided key.
      * @param key the key of the bubble to show.
-     * @param bubbleBarOffsetX the offset of the bubble bar from the edge of the screen on the X
-     *                         axis.
-     * @param bubbleBarOffsetY the offset of the bubble bar from the edge of the screen on the Y
-     *                         axis.
+     * @param bubbleBarBounds bounds of the bubble bar in display coordinates
      */
-    public void showBubble(String key, int bubbleBarOffsetX, int bubbleBarOffsetY) {
+    public void showBubble(String key, Rect bubbleBarBounds) {
         if (mBubbles != null) {
             try {
-                mBubbles.showBubble(key, bubbleBarOffsetX, bubbleBarOffsetY);
+                mBubbles.showBubble(key, bubbleBarBounds);
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed call showBubble");
             }
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index e264182..496cb4e 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -99,7 +99,6 @@
 import static com.android.launcher3.util.SettingsCache.TOUCHPAD_NATURAL_SCROLLING;
 
 import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
 import android.animation.AnimatorSet;
 import android.animation.ValueAnimator;
 import android.annotation.TargetApi;
@@ -132,6 +131,7 @@
 import android.util.AttributeSet;
 import android.util.FloatProperty;
 import android.util.Log;
+import android.util.Pair;
 import android.util.SparseArray;
 import android.view.KeyEvent;
 import android.view.KeyboardShortcutGroup;
@@ -264,7 +264,6 @@
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.ArrayList;
-import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -2125,30 +2124,23 @@
      */
     @Override
     public void bindItems(final List<ItemInfo> items, final boolean forceAnimateIcons) {
-        bindItems(items, forceAnimateIcons, /* focusFirstItemForAccessibility= */ false);
+        bindItems(items.stream().map(i -> Pair.create(
+                i, getItemInflater().inflateItem(i, getModelWriter()))).toList(),
+                forceAnimateIcons ? new AnimatorSet() : null);
     }
 
-
     /**
-     * Bind the items start-end from the list.
+     * Bind all the items in the map, ignoring any null views
      *
-     * Implementation of the method from LauncherModel.Callbacks.
-     *
-     * @param focusFirstItemForAccessibility true iff the first item to be added to the workspace
-     *                                       should be focused for accessibility.
+     * @param boundAnim if non-null, uses it to create and play the bounce animation for added views
      */
-    public void bindItems(
-            final List<ItemInfo> items,
-            final boolean forceAnimateIcons,
-            final boolean focusFirstItemForAccessibility) {
+    public void bindItems(List<Pair<ItemInfo, View>> shortcuts, @Nullable AnimatorSet boundAnim) {
         // Get the list of added items and intersect them with the set of items here
-        final Collection<Animator> bounceAnims = new ArrayList<>();
         Workspace<?> workspace = mWorkspace;
         int newItemsScreenId = -1;
-        int end = items.size();
-        View newView = null;
-        for (int i = 0; i < end; i++) {
-            final ItemInfo item = items.get(i);
+        int index = 0;
+        for (Pair<ItemInfo, View> e : shortcuts) {
+            final ItemInfo item = e.first;
 
             // Remove colliding items.
             CellPos presenterPos = getCellPosMapper().mapModelToPresenter(item);
@@ -2167,42 +2159,26 @@
                 }
             }
 
-            final View view = mItemInflater.inflateItem(item, getModelWriter());
+            final View view = e.second;
             if (view == null) {
                 continue;
             }
             workspace.addInScreenFromBind(view, item);
-            if (forceAnimateIcons) {
+            if (boundAnim != null) {
                 // Animate all the applications up now
                 view.setAlpha(0f);
                 view.setScaleX(0f);
                 view.setScaleY(0f);
-                bounceAnims.add(createNewAppBounceAnimation(view, i));
+                boundAnim.play(createNewAppBounceAnimation(view, index++));
                 newItemsScreenId = presenterPos.screenId;
             }
-
-            if (newView == null) {
-                newView = view;
-            }
         }
 
-        View viewToFocus = newView;
         // Animate to the correct page
-        if (forceAnimateIcons && newItemsScreenId > -1) {
-            AnimatorSet anim = new AnimatorSet();
-            anim.playTogether(bounceAnims);
-            if (focusFirstItemForAccessibility && viewToFocus != null) {
-                anim.addListener(new AnimatorListenerAdapter() {
-                    @Override
-                    public void onAnimationEnd(Animator animation) {
-                        viewToFocus.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
-                    }
-                });
-            }
-
+        if (boundAnim != null && newItemsScreenId > -1) {
             int currentScreenId = mWorkspace.getScreenIdForPageIndex(mWorkspace.getNextPage());
             final int newScreenIndex = mWorkspace.getPageIndexForScreenId(newItemsScreenId);
-            final Runnable startBounceAnimRunnable = anim::start;
+            final Runnable startBounceAnimRunnable = boundAnim::start;
 
             if (canAnimatePageChange() && newItemsScreenId != currentScreenId) {
                 // We post the animation slightly delayed to prevent slowdowns
@@ -2215,8 +2191,6 @@
             } else {
                 mWorkspace.postDelayed(startBounceAnimRunnable, NEW_APPS_ANIMATION_DELAY);
             }
-        } else if (focusFirstItemForAccessibility && viewToFocus != null) {
-            viewToFocus.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
         }
         workspace.requestLayout();
     }
diff --git a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
index 0844275..e65e614 100644
--- a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
+++ b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
@@ -5,18 +5,22 @@
 import static android.view.accessibility.AccessibilityNodeInfo.ACTION_LONG_CLICK;
 
 import static com.android.launcher3.LauncherState.NORMAL;
+import static com.android.launcher3.anim.AnimatorListeners.forEndCallback;
 import static com.android.launcher3.anim.AnimatorListeners.forSuccessCallback;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.IGNORE;
 import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_NOT_PINNABLE;
 
+import android.animation.AnimatorSet;
 import android.appwidget.AppWidgetProviderInfo;
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.graphics.RectF;
 import android.os.Handler;
 import android.util.Log;
+import android.util.Pair;
 import android.view.KeyEvent;
 import android.view.View;
+import android.view.accessibility.AccessibilityEvent;
 
 import com.android.launcher3.BubbleTextView;
 import com.android.launcher3.ButtonDropTarget;
@@ -396,10 +400,7 @@
                         LauncherSettings.Favorites.CONTAINER_DESKTOP,
                         screenId, coordinates[0], coordinates[1]);
 
-                mContext.bindItems(
-                        Collections.singletonList(info),
-                        /* forceAnimateIcons= */ true,
-                        /* focusFirstItemForAccessibility= */ accessibility);
+                bindItem(item, accessibility);
                 announceConfirmation(R.string.item_added_to_workspace);
             } else if (item instanceof PendingAddItemInfo) {
                 PendingAddItemInfo info = (PendingAddItemInfo) item;
@@ -412,7 +413,7 @@
                 mContext.getModelWriter().addItemToDatabase(info,
                         LauncherSettings.Favorites.CONTAINER_DESKTOP,
                         screenId, coordinates[0], coordinates[1]);
-                mContext.bindItems(Collections.singletonList(info), true, accessibility);
+                bindItem(info, accessibility);
             } else if (item instanceof FolderInfo fi) {
                 mContext.getModelWriter().addItemToDatabase(fi,
                         LauncherSettings.Favorites.CONTAINER_DESKTOP, screenId, coordinates[0],
@@ -420,11 +421,26 @@
                 fi.contents.forEach(member -> {
                     mContext.getModelWriter().addItemToDatabase(member, fi.id, -1, -1, -1);
                 });
-                mContext.bindItems(Collections.singletonList(fi), true, accessibility);
+                bindItem(fi, accessibility);
             }
         }));
         return true;
     }
+
+    private void bindItem(ItemInfo item, boolean focusForAccessibility) {
+        View view = mContext.getItemInflater().inflateItem(item, mContext.getModelWriter());
+        if (view == null) {
+            return;
+        }
+        AnimatorSet anim = null;
+        if (focusForAccessibility) {
+            anim = new AnimatorSet();
+            anim.addListener(forEndCallback(
+                    () -> view.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED)));
+        }
+        mContext.bindItems(Collections.singletonList(Pair.create(item, view)), anim);
+    }
+
     /**
      * Functionality to move the item {@link ItemInfo} to the workspace
      * @param item item to be moved
diff --git a/tests/multivalentTests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/multivalentTests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
index 79d8c60..f0d2e20 100644
--- a/tests/multivalentTests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
+++ b/tests/multivalentTests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
@@ -370,7 +370,8 @@
         Assert.assertTrue("Setup wizard is still visible", wizardDismissed);
     }
 
-    private static void verifyKeyguardInvisible() {
+    /** Asserts that keyguard is not visible */
+    public static void verifyKeyguardInvisible() {
         final boolean keyguardAlreadyVisible = sSeenKeyguard;
 
         sSeenKeyguard = sSeenKeyguard
diff --git a/tests/multivalentTests/src/com/android/launcher3/ui/PortraitLandscapeRunner.java b/tests/multivalentTests/src/com/android/launcher3/ui/PortraitLandscapeRunner.java
index d94e4a5..3a54915 100644
--- a/tests/multivalentTests/src/com/android/launcher3/ui/PortraitLandscapeRunner.java
+++ b/tests/multivalentTests/src/com/android/launcher3/ui/PortraitLandscapeRunner.java
@@ -44,6 +44,7 @@
             @Override
             public void evaluate() throws Throwable {
                 try {
+                    AbstractLauncherUiTest.verifyKeyguardInvisible();
                     mTest.mDevice.pressHome();
                     mTest.waitForLauncherCondition("Launcher activity wasn't created",
                             launcher -> launcher != null);