Merge "Handle page offset for grid overview" into sc-dev
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepInteractionHandler.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepInteractionHandler.java
new file mode 100644
index 0000000..66e4f4c
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepInteractionHandler.java
@@ -0,0 +1,63 @@
+/*
+ * 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.uioverrides;
+
+import android.app.ActivityOptions;
+import android.app.PendingIntent;
+import android.content.Intent;
+import android.util.Log;
+import android.util.Pair;
+import android.view.View;
+import android.widget.RemoteViews;
+
+import com.android.launcher3.util.ActivityOptionsWrapper;
+import com.android.launcher3.widget.LauncherAppWidgetHostView;
+
+/** Provides a Quickstep specific animation when launching an activity from an app widget. */
+class QuickstepInteractionHandler implements RemoteViews.InteractionHandler {
+
+    private static final String TAG = "QuickstepInteractionHandler";
+
+    private final QuickstepLauncher mLauncher;
+
+    QuickstepInteractionHandler(QuickstepLauncher launcher) {
+        mLauncher = launcher;
+    }
+
+    @Override
+    public boolean onInteraction(View view, PendingIntent pendingIntent,
+            RemoteViews.RemoteResponse remoteResponse) {
+        LauncherAppWidgetHostView hostView = findHostViewAncestor(view);
+        if (hostView == null) {
+            Log.e(TAG, "View did not have a LauncherAppWidgetHostView ancestor.");
+            return RemoteViews.startPendingIntent(hostView, pendingIntent,
+                    remoteResponse.getLaunchOptions(view));
+        }
+        Pair<Intent, ActivityOptions> options = remoteResponse.getLaunchOptions(hostView);
+        ActivityOptionsWrapper activityOptions = mLauncher.getAppTransitionManager()
+                .getActivityLaunchOptions(mLauncher, hostView);
+        options = Pair.create(options.first, activityOptions.options);
+        return RemoteViews.startPendingIntent(hostView, pendingIntent, options);
+    }
+
+    private LauncherAppWidgetHostView findHostViewAncestor(View v) {
+        while (v != null) {
+            if (v instanceof LauncherAppWidgetHostView) return (LauncherAppWidgetHostView) v;
+            v = (View) v.getParent();
+        }
+        return null;
+    }
+}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
index 0ceb8c7..f09d9e0 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
@@ -36,6 +36,7 @@
 import android.content.Intent;
 import android.content.SharedPreferences;
 import android.content.res.Configuration;
+import android.os.SystemProperties;
 import android.view.HapticFeedbackConstants;
 import android.view.View;
 
@@ -71,6 +72,7 @@
 import com.android.launcher3.util.TouchController;
 import com.android.launcher3.util.UiThreadHelper;
 import com.android.launcher3.util.UiThreadHelper.AsyncCommand;
+import com.android.launcher3.widget.LauncherAppWidgetHost;
 import com.android.quickstep.SysUINavigationMode;
 import com.android.quickstep.SysUINavigationMode.Mode;
 import com.android.quickstep.SystemUiProxy;
@@ -88,6 +90,9 @@
 
 public class QuickstepLauncher extends BaseQuickstepLauncher {
 
+    private static final boolean ENABLE_APP_WIDGET_LAUNCH_ANIMATION =
+            SystemProperties.getBoolean("persist.debug.quickstep_app_widget_launch", false);
+
     public static final boolean GO_LOW_RAM_RECENTS_ENABLED = false;
     /**
      * Reusable command for applying the shelf height on the background thread.
@@ -320,6 +325,14 @@
         return new QuickstepAtomicAnimationFactory(this);
     }
 
+    protected LauncherAppWidgetHost createAppWidgetHost() {
+        LauncherAppWidgetHost appWidgetHost = super.createAppWidgetHost();
+        if (ENABLE_APP_WIDGET_LAUNCH_ANIMATION) {
+            appWidgetHost.setInteractionHandler(new QuickstepInteractionHandler(this));
+        }
+        return appWidgetHost;
+    }
+
     private static final class LauncherTaskViewController extends
             TaskViewTouchController<Launcher> {
 
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 5091543..3236f5d 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -436,8 +436,7 @@
         mOnboardingPrefs = createOnboardingPrefs(mSharedPrefs);
 
         mAppWidgetManager = new WidgetManagerHelper(this);
-        mAppWidgetHost = new LauncherAppWidgetHost(this,
-                appWidgetId -> getWorkspace().removeWidget(appWidgetId));
+        mAppWidgetHost = createAppWidgetHost();
         mAppWidgetHost.startListening();
 
         inflateRootView(R.layout.launcher);
@@ -1428,6 +1427,11 @@
         return mAppWidgetHost;
     }
 
+    protected LauncherAppWidgetHost createAppWidgetHost() {
+        return new LauncherAppWidgetHost(this,
+                appWidgetId -> getWorkspace().removeWidget(appWidgetId));
+    }
+
     public LauncherModel getModel() {
         return mModel;
     }
diff --git a/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java b/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java
index 687318f..0d53f20 100644
--- a/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java
+++ b/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java
@@ -325,9 +325,12 @@
         float relativeScreenWidth = 1f / numScreens;
         float absoluteTop = widgetLocation.top;
         float absoluteBottom = widgetLocation.bottom;
-        for (View v = (View) getParent();
-                v != null && v.getId() != R.id.launcher;
-                v = (View) v.getParent()) {
+        View v = this;
+        while (v.getParent() instanceof View) {
+            v = (View) v.getParent();
+            if (v.getId() != R.id.launcher) {
+                break;
+            }
             absoluteBottom += v.getTop();
             absoluteTop += v.getTop();
         }
diff --git a/src/com/android/launcher3/widget/WidgetCell.java b/src/com/android/launcher3/widget/WidgetCell.java
index 5e7c961..c08160b 100644
--- a/src/com/android/launcher3/widget/WidgetCell.java
+++ b/src/com/android/launcher3/widget/WidgetCell.java
@@ -21,14 +21,15 @@
 import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
+import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.os.CancellationSignal;
 import android.util.AttributeSet;
 import android.util.Log;
+import android.view.Gravity;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.View.OnLayoutChangeListener;
-import android.view.ViewGroup;
 import android.view.ViewPropertyAnimator;
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.widget.FrameLayout;
@@ -96,7 +97,6 @@
     private Drawable mDeferredDrawable;
 
     protected final BaseActivity mActivity;
-    protected final DeviceProfile mDeviceProfile;
     private final CheckLongPressHelper mLongPressHelper;
     private final float mEnforcedCornerRadius;
 
@@ -115,7 +115,6 @@
         super(context, attrs, defStyle);
 
         mActivity = BaseActivity.fromContext(context);
-        mDeviceProfile = mActivity.getDeviceProfile();
         mLongPressHelper = new CheckLongPressHelper(this);
 
         mLongPressHelper.setLongPressTimeoutFactor(1);
@@ -127,7 +126,7 @@
     }
 
     private void setContainerWidth() {
-        mCellSize = (int) (mDeviceProfile.allAppsIconSizePx * WIDTH_SCALE);
+        mCellSize = (int) (mActivity.getDeviceProfile().allAppsIconSizePx * WIDTH_SCALE);
         mPresetPreviewSize = (int) (mCellSize * PREVIEW_SCALE);
         mPreviewWidth = mPreviewHeight = mPresetPreviewSize;
     }
@@ -222,16 +221,11 @@
             launcherAppWidgetProviderInfo.initialLayout = item.widgetInfo.previewLayout;
             mAppWidgetHostViewPreview.setAppWidget(/* appWidgetId= */ -1,
                     launcherAppWidgetProviderInfo);
-            mAppWidgetHostViewPreview.setPadding(/* left= */ 0, /* top= */0, /* right= */
-                    0, /* bottom= */ 0);
+            Rect padding = new Rect();
+            mAppWidgetHostViewPreview.getWidgetInset(mActivity.getDeviceProfile(), padding);
+            mAppWidgetHostViewPreview.setPadding(padding.left, padding.top, padding.right,
+                    padding.bottom);
             mAppWidgetHostViewPreview.updateAppWidget(/* remoteViews= */ null);
-            // Gravity 77 = "fill"
-            FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
-                    ViewGroup.LayoutParams.MATCH_PARENT,
-                    ViewGroup.LayoutParams.MATCH_PARENT, /* gravity= */ 77);
-            mAppWidgetHostViewPreview.setLayoutParams(params);
-            mWidgetImageContainer.addView(mAppWidgetHostViewPreview, /* index= */ 0);
-            mWidgetImage.setVisibility(View.GONE);
         }
     }
 
@@ -284,7 +278,8 @@
             }
         }
         Drawable badge = mWidgetPreviewLoader.getBadgeForUser(mItem.user,
-                BaseIconFactory.getBadgeSizeForIconSize(mDeviceProfile.allAppsIconSizePx));
+                BaseIconFactory.getBadgeSizeForIconSize(
+                        mActivity.getDeviceProfile().allAppsIconSizePx));
         if (badge == null) {
             mWidgetBadge.setVisibility(View.GONE);
         } else {
@@ -318,11 +313,12 @@
         }
 
         if (mAppWidgetHostViewPreview != null) {
-            DeviceProfile dp = mActivity.getDeviceProfile();
-            int viewWidth = dp.cellWidthPx * mItem.spanX;
-            int viewHeight = dp.cellHeightPx * mItem.spanY;
-
-            setContainerSize(viewWidth, viewHeight);
+            setContainerSize(mPreviewWidth, mPreviewHeight);
+            FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
+                    mPreviewWidth, mPreviewHeight, Gravity.FILL);
+            mAppWidgetHostViewPreview.setLayoutParams(params);
+            mWidgetImageContainer.addView(mAppWidgetHostViewPreview, /* index= */ 0);
+            mWidgetImage.setVisibility(View.GONE);
             applyPreview((Drawable) null);
             return;
         }
@@ -342,8 +338,9 @@
     public void setPreviewSize(int spanX, int spanY, float previewScale) {
         int padding = 2 * getResources()
                 .getDimensionPixelSize(R.dimen.widget_preview_shortcut_padding);
-        mPreviewWidth = mDeviceProfile.cellWidthPx * spanX + padding;
-        mPreviewHeight = mDeviceProfile.cellHeightPx * spanY + padding;
+        DeviceProfile deviceProfile = mActivity.getDeviceProfile();
+        mPreviewWidth = deviceProfile.cellWidthPx * spanX + padding;
+        mPreviewHeight = deviceProfile.cellHeightPx * spanY + padding;
         mPreviewScale = previewScale;
     }
 
diff --git a/src/com/android/launcher3/widget/WidgetCellPreview.java b/src/com/android/launcher3/widget/WidgetCellPreview.java
index ad3a61a..9f45d71 100644
--- a/src/com/android/launcher3/widget/WidgetCellPreview.java
+++ b/src/com/android/launcher3/widget/WidgetCellPreview.java
@@ -20,6 +20,8 @@
 import android.view.MotionEvent;
 import android.widget.FrameLayout;
 
+import androidx.annotation.Nullable;
+
 /**
  * View group managing the widget preview: either using a {@link WidgetImageView} or an actual
  * {@link LauncherAppWidgetHostView}.
@@ -43,4 +45,27 @@
         return true;
     }
 
+    /** Returns {@code true} if this container has a preview layout. */
+    public boolean hasPreviewLayout() {
+        for (int i = 0; i < getChildCount(); i++) {
+            if (getChildAt(i) instanceof LauncherAppWidgetHostView) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Returns {@link LauncherAppWidgetHostView} if this container has a preview layout. Otherwise,
+     * returns null.
+     */
+    @Nullable
+    public LauncherAppWidgetHostView getPreviewLayout() {
+        for (int i = 0; i < getChildCount(); i++) {
+            if (getChildAt(i) instanceof LauncherAppWidgetHostView) {
+                return (LauncherAppWidgetHostView) getChildAt(i);
+            }
+        }
+        return null;
+    }
 }