Merge "Update calls to go through the feature interface instead of sysui proxy" into sc-dev
diff --git a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
index 9ac2c72..64b22d4 100644
--- a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
+++ b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
@@ -309,9 +309,11 @@
         // before our internal listeners.
         mLauncher.getStateManager().setCurrentAnimation(anim);
 
-        Rect windowTargetBounds = getWindowTargetBounds(appTargets);
+        final int rotationChange = getRotationChange(appTargets);
+        // Note: the targetBounds are relative to the launcher
+        Rect windowTargetBounds = getWindowTargetBounds(appTargets, rotationChange);
         anim.play(getOpeningWindowAnimators(v, appTargets, wallpaperTargets, windowTargetBounds,
-                areAllTargetsTranslucent(appTargets)));
+                areAllTargetsTranslucent(appTargets), rotationChange));
         if (launcherClosing) {
             Pair<AnimatorSet, Runnable> launcherContentAnimator =
                     getLauncherContentAnimator(true /* isAppOpening */,
@@ -340,19 +342,29 @@
      * In multiwindow mode, we need to get the final size of the opening app window target to help
      * figure out where the floating view should animate to.
      */
-    private Rect getWindowTargetBounds(RemoteAnimationTargetCompat[] appTargets) {
-        Rect bounds = new Rect(0, 0, mDeviceProfile.widthPx, mDeviceProfile.heightPx);
-        if (mLauncher.isInMultiWindowMode()) {
-            for (RemoteAnimationTargetCompat target : appTargets) {
-                if (target.mode == MODE_OPENING) {
-                    bounds.set(target.screenSpaceBounds);
-                    if (target.localBounds != null) {
-                        bounds.set(target.localBounds);
-                    } else {
-                        bounds.offsetTo(target.position.x, target.position.y);
-                    }
-                    return bounds;
-                }
+    private Rect getWindowTargetBounds(@NonNull RemoteAnimationTargetCompat[] appTargets,
+            int rotationChange) {
+        RemoteAnimationTargetCompat target = null;
+        for (RemoteAnimationTargetCompat t : appTargets) {
+            if (t.mode != MODE_OPENING) continue;
+            target = t;
+            break;
+        }
+        if (target == null) return new Rect(0, 0, mDeviceProfile.widthPx, mDeviceProfile.heightPx);
+        final Rect bounds = new Rect(target.screenSpaceBounds);
+        if (target.localBounds != null) {
+            bounds.set(target.localBounds);
+        } else {
+            bounds.offsetTo(target.position.x, target.position.y);
+        }
+        if (rotationChange != 0) {
+            if ((rotationChange % 2) == 1) {
+                // undoing rotation, so our "original" parent size is actually flipped
+                Utilities.rotateBounds(bounds, mDeviceProfile.heightPx, mDeviceProfile.widthPx,
+                        4 - rotationChange);
+            } else {
+                Utilities.rotateBounds(bounds, mDeviceProfile.widthPx, mDeviceProfile.heightPx,
+                        4 - rotationChange);
             }
         }
         return bounds;
@@ -502,7 +514,7 @@
     private Animator getOpeningWindowAnimators(View v,
             RemoteAnimationTargetCompat[] appTargets,
             RemoteAnimationTargetCompat[] wallpaperTargets,
-            Rect windowTargetBounds, boolean appTargetsAreTranslucent) {
+            Rect windowTargetBounds, boolean appTargetsAreTranslucent, int rotationChange) {
         RectF launcherIconBounds = new RectF();
         FloatingIconView floatingView = FloatingIconView.getFloatingIconView(mLauncher, v,
                 !appTargetsAreTranslucent, launcherIconBounds, true /* isOpening */);
@@ -602,6 +614,10 @@
 
                 final int windowCropWidth = crop.width();
                 final int windowCropHeight = crop.height();
+                if (rotationChange != 0) {
+                    Utilities.rotateBounds(crop, mDeviceProfile.widthPx,
+                            mDeviceProfile.heightPx, rotationChange);
+                }
 
                 // Scale the size of the icon to match the size of the window crop.
                 float scaleX = iconWidth / windowCropWidth;
@@ -641,7 +657,20 @@
 
                     if (target.mode == MODE_OPENING) {
                         matrix.setScale(scale, scale);
-                        matrix.postTranslate(windowTransX0, windowTransY0);
+                        if (rotationChange == 1) {
+                            matrix.postTranslate(windowTransY0,
+                                    mDeviceProfile.widthPx - (windowTransX0 + scaledCropWidth));
+                        } else if (rotationChange == 2) {
+                            matrix.postTranslate(
+                                    mDeviceProfile.widthPx - (windowTransX0 + scaledCropWidth),
+                                    mDeviceProfile.heightPx - (windowTransY0 + scaledCropHeight));
+                        } else if (rotationChange == 3) {
+                            matrix.postTranslate(
+                                    mDeviceProfile.heightPx - (windowTransY0 + scaledCropHeight),
+                                    windowTransX0);
+                        } else {
+                            matrix.postTranslate(windowTransX0, windowTransY0);
+                        }
 
                         floatingView.update(floatingIconBounds, mIconAlpha.value, percent, 0f,
                                 mWindowRadius.value * scale, true /* isOpening */);
@@ -650,17 +679,25 @@
                                 .withAlpha(1f - mIconAlpha.value)
                                 .withCornerRadius(mWindowRadius.value)
                                 .withShadowRadius(mShadowRadius.value);
-                    } else {
+                    } else if (target.mode == MODE_CLOSING) {
                         if (target.localBounds != null) {
                             final Rect localBounds = target.localBounds;
                             tmpPos.set(target.localBounds.left, target.localBounds.top);
                         } else {
                             tmpPos.set(target.position.x, target.position.y);
                         }
-
-                        matrix.setTranslate(tmpPos.x, tmpPos.y);
                         final Rect crop = new Rect(target.screenSpaceBounds);
                         crop.offsetTo(0, 0);
+
+                        if ((rotationChange % 2) == 1) {
+                            int tmp = crop.right;
+                            crop.right = crop.bottom;
+                            crop.bottom = tmp;
+                            tmp = tmpPos.x;
+                            tmpPos.x = tmpPos.y;
+                            tmpPos.y = tmp;
+                        }
+                        matrix.setTranslate(tmpPos.x, tmpPos.y);
                         builder.withMatrix(matrix)
                                 .withWindowCrop(crop)
                                 .withAlpha(1f);
@@ -817,14 +854,26 @@
         return unlockAnimator;
     }
 
+    private static int getRotationChange(RemoteAnimationTargetCompat[] appTargets) {
+        int rotationChange = 0;
+        for (RemoteAnimationTargetCompat target : appTargets) {
+            if (Math.abs(target.rotationChange) > Math.abs(rotationChange)) {
+                rotationChange = target.rotationChange;
+            }
+        }
+        return rotationChange;
+    }
+
     /**
      * Animator that controls the transformations of the windows the targets that are closing.
      */
     private Animator getClosingWindowAnimators(RemoteAnimationTargetCompat[] appTargets,
             RemoteAnimationTargetCompat[] wallpaperTargets) {
+        final int rotationChange = getRotationChange(appTargets);
         SurfaceTransactionApplier surfaceApplier = new SurfaceTransactionApplier(mDragLayer);
         Matrix matrix = new Matrix();
         Point tmpPos = new Point();
+        Rect tmpRect = new Rect();
         ValueAnimator closingAnimator = ValueAnimator.ofFloat(0, 1);
         int duration = CLOSING_TRANSITION_DURATION_MS;
         float windowCornerRadius = mDeviceProfile.isMultiWindowMode
@@ -851,26 +900,32 @@
                         tmpPos.set(target.position.x, target.position.y);
                     }
 
+                    final Rect crop = new Rect(target.screenSpaceBounds);
+                    crop.offsetTo(0, 0);
                     if (target.mode == MODE_CLOSING) {
+                        tmpRect.set(target.screenSpaceBounds);
+                        if ((rotationChange % 2) != 0) {
+                            final int right = crop.right;
+                            crop.right = crop.bottom;
+                            crop.bottom = right;
+                        }
                         matrix.setScale(mScale.value, mScale.value,
-                                target.screenSpaceBounds.centerX(),
-                                target.screenSpaceBounds.centerY());
+                                tmpRect.centerX(),
+                                tmpRect.centerY());
                         matrix.postTranslate(0, mDy.value);
                         matrix.postTranslate(tmpPos.x, tmpPos.y);
                         builder.withMatrix(matrix)
+                                .withWindowCrop(crop)
                                 .withAlpha(mAlpha.value)
                                 .withCornerRadius(windowCornerRadius)
                                 .withShadowRadius(mShadowRadius.value);
-                    } else {
+                    } else if (target.mode == MODE_OPENING) {
                         matrix.setTranslate(tmpPos.x, tmpPos.y);
                         builder.withMatrix(matrix)
+                                .withWindowCrop(crop)
                                 .withAlpha(1f);
                     }
-                    final Rect crop = new Rect(target.screenSpaceBounds);
-                    crop.offsetTo(0, 0);
-                    params[i] = builder
-                            .withWindowCrop(crop)
-                            .build();
+                    params[i] = builder.build();
                 }
                 surfaceApplier.scheduleApply(params);
             }
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
index 0fe5432..5ffe315 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
@@ -120,6 +120,7 @@
                 getCurrentOverviewPage(launcher) < currentTaskAfterFlingForward));
 
         // Test opening a task.
+        startTestActivity(2);
         OverviewTask task = mLauncher.pressHome().switchToOverview().getCurrentTask();
         assertNotNull("overview.getCurrentTask() returned null (1)", task);
         assertNotNull("OverviewTask.open returned null", task.open());
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index 94c6574..e57844d 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -700,6 +700,37 @@
         return (Math.abs(first - second) / Math.abs((first + second) / 2.0f)) > bound;
     }
 
+    /**
+     * Rotates `inOutBounds` by `delta` 90-degree increments. Rotation is visually CCW. Parent
+     * sizes represent the "space" that will rotate carrying inOutBounds along with it to determine
+     * the final bounds.
+     */
+    public static void rotateBounds(Rect inOutBounds, int parentWidth, int parentHeight,
+            int delta) {
+        int rdelta = ((delta % 4) + 4) % 4;
+        int origLeft = inOutBounds.left;
+        switch (rdelta) {
+            case 0:
+                return;
+            case 1:
+                inOutBounds.left = inOutBounds.top;
+                inOutBounds.top = parentWidth - inOutBounds.right;
+                inOutBounds.right = inOutBounds.bottom;
+                inOutBounds.bottom = parentWidth - origLeft;
+                return;
+            case 2:
+                inOutBounds.left = parentWidth - inOutBounds.right;
+                inOutBounds.right = parentWidth - origLeft;
+                return;
+            case 3:
+                inOutBounds.left = parentHeight - inOutBounds.bottom;
+                inOutBounds.bottom = inOutBounds.right;
+                inOutBounds.right = parentHeight - inOutBounds.top;
+                inOutBounds.top = origLeft;
+                return;
+        }
+    }
+
     private static class FixedSizeEmptyDrawable extends ColorDrawable {
 
         private final int mSize;
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index 637bf60..96251f0 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -85,7 +85,7 @@
             "ADAPTIVE_ICON_WINDOW_ANIM", true, "Use adaptive icons for window animations.");
 
     public static final BooleanFlag ENABLE_QUICKSTEP_LIVE_TILE = getDebugFlag(
-            "ENABLE_QUICKSTEP_LIVE_TILE", true, "Enable live tile in Quickstep overview");
+            "ENABLE_QUICKSTEP_LIVE_TILE", false, "Enable live tile in Quickstep overview");
 
     // Keep as DeviceFlag to allow remote disable in emergency.
     public static final BooleanFlag ENABLE_SUGGESTED_ACTIONS_OVERVIEW = new DeviceFlag(
diff --git a/src_shortcuts_overrides/com/android/launcher3/model/WidgetsModel.java b/src_shortcuts_overrides/com/android/launcher3/model/WidgetsModel.java
index 3ea4766..f82f2cc 100644
--- a/src_shortcuts_overrides/com/android/launcher3/model/WidgetsModel.java
+++ b/src_shortcuts_overrides/com/android/launcher3/model/WidgetsModel.java
@@ -132,7 +132,7 @@
                 widgetsAndShortcuts.add(new WidgetItem(info, app.getIconCache(), pm));
                 updatedItems.add(info);
             }
-            setWidgetsAndShortcuts(widgetsAndShortcuts, app);
+            setWidgetsAndShortcuts(widgetsAndShortcuts, app, packageUser);
         } catch (Exception e) {
             if (!FeatureFlags.IS_STUDIO_BUILD && Utilities.isBinderSizeError(e)) {
                 // the returned value may be incomplete and will not be refreshed until the next
@@ -149,7 +149,7 @@
     }
 
     private synchronized void setWidgetsAndShortcuts(ArrayList<WidgetItem> rawWidgetsShortcuts,
-            LauncherAppState app) {
+            LauncherAppState app, @Nullable PackageUserKey packageUser) {
         if (DEBUG) {
             Log.d(TAG, "addWidgetsAndShortcuts, widgetsShortcuts#=" + rawWidgetsShortcuts.size());
         }
@@ -158,8 +158,12 @@
         // {@link mPackageItemInfos} to locate the key to be used for {@link #mWidgetsList}
         HashMap<PackageUserKey, PackageItemInfo> tmpPackageItemInfos = new HashMap<>();
 
-        // clear the lists.
-        mWidgetsList.clear();
+        // Clear the lists only if this is an update on all widgets and shortcuts. If packageUser
+        // isn't null, only updates the shortcuts and widgets for the app represented in
+        // packageUser.
+        if (packageUser == null) {
+            mWidgetsList.clear();
+        }
         // add and update.
         mWidgetsList.putAll(rawWidgetsShortcuts.stream()
                 .filter(new WidgetValidityCheck(app))
diff --git a/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java b/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
index 4c9a8e7..6f47df0 100644
--- a/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
+++ b/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
@@ -334,20 +334,31 @@
         // 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 AllApps allApps = mLauncher.
-                getWorkspace().
-                switchToAllApps();
+        final AllApps allApps = mLauncher
+                .getWorkspace()
+                .switchToAllApps();
         allApps.freeze();
         try {
-            final AppIconMenuItem menuItem = allApps.
-                    getAppIcon(APP_NAME).
-                    openMenu().
-                    getMenuItem(0);
-            final String shortcutName = menuItem.getText();
-            assertEquals("Wrong menu item", "Shortcut 3", shortcutName);
+            final AppIconMenu menu = allApps
+                    .getAppIcon(APP_NAME)
+                    .openMenu();
+            final AppIconMenuItem menuItem0 = menu.getMenuItem(0);
+            final AppIconMenuItem menuItem2 = menu.getMenuItem(2);
+
+            final AppIconMenuItem menuItem;
+
+            final String expectedShortcutName = "Shortcut 3";
+            if (menuItem0.getText().equals(expectedShortcutName)) {
+                menuItem = menuItem0;
+            } else {
+                final String shortcutName2 = menuItem2.getText();
+                assertEquals("Wrong menu item", expectedShortcutName, shortcutName2);
+                menuItem = menuItem2;
+            }
 
             menuItem.dragToWorkspace(false, false);
-            mLauncher.getWorkspace().getWorkspaceAppIcon(shortcutName).launch(getAppPackageName());
+            mLauncher.getWorkspace().getWorkspaceAppIcon(expectedShortcutName)
+                    .launch(getAppPackageName());
         } finally {
             allApps.unfreeze();
         }