From e72dd4a859f726fcd2c6a25574608b293e7418a2 Mon Sep 17 00:00:00 2001 From: Hyunyoung Song Date: Sun, 2 May 2021 23:20:55 -0700 Subject: [PATCH 01/19] Call windowInsetController.hide method when hiding keyboard Bug: 186608200 Test: manual Change-Id: I9a819aec217a91e8b6de58d074dbdb134dacaeb8 --- src/com/android/launcher3/util/UiThreadHelper.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/com/android/launcher3/util/UiThreadHelper.java b/src/com/android/launcher3/util/UiThreadHelper.java index be14e01f0d..f5e1234a28 100644 --- a/src/com/android/launcher3/util/UiThreadHelper.java +++ b/src/com/android/launcher3/util/UiThreadHelper.java @@ -48,7 +48,13 @@ public class UiThreadHelper { WindowInsets rootInsets = launcher.getRootView().getRootWindowInsets(); boolean isImeShown = rootInsets != null && rootInsets.isVisible( WindowInsets.Type.ime()); - if (!isImeShown) return; + if (isImeShown) { + // this call is already asynchronous + launcher.getAppsView().getWindowInsetsController().hide( + WindowInsets.Type.ime() + ); + } + return; } Message.obtain(HANDLER.get(launcher), MSG_HIDE_KEYBOARD, token).sendToTarget(); From 7e6e1693efb64d57a9ae4e62d398a6d0b6da7d9e Mon Sep 17 00:00:00 2001 From: Santiago Etchebehere Date: Mon, 3 May 2021 20:12:50 -0700 Subject: [PATCH 02/19] Update the label of Wallpapers button Use the updated name Bug: 179129352 Test: manual Change-Id: Ia4878ce924b7d7f3ba1d8d661c8ac00c7310ee20 --- res/values/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/values/strings.xml b/res/values/strings.xml index d6936ab69d..eae32b79f5 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -221,7 +221,7 @@ Wallpapers - Styles & wallpapers + Wallpaper & style Home settings From 7fbc9619333d7f6727a70f7151e42ea035427554 Mon Sep 17 00:00:00 2001 From: Winson Chung Date: Mon, 3 May 2021 22:26:52 -0700 Subject: [PATCH 03/19] Allow binder calls from creating recents orientated state for now - Should probably remove if possible since this is on a hot path Bug: 187074722 Test: Presubmit Change-Id: I104e1175acba7b90cd9824b905ffe68089beed9e --- .../src/com/android/quickstep/util/TaskViewSimulator.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java index e63f8bbea8..f578ad1741 100644 --- a/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java +++ b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java @@ -36,6 +36,7 @@ import androidx.annotation.NonNull; import com.android.launcher3.DeviceProfile; import com.android.launcher3.Utilities; import com.android.launcher3.anim.PendingAnimation; +import com.android.launcher3.util.TraceHelper; import com.android.quickstep.AnimatedFloat; import com.android.quickstep.BaseActivityInterface; import com.android.quickstep.views.TaskThumbnailView.PreviewPositionHelper; @@ -95,7 +96,9 @@ public class TaskViewSimulator implements TransformParams.BuilderProxy { mContext = context; mSizeStrategy = sizeStrategy; - mOrientationState = new RecentsOrientedState(context, sizeStrategy, i -> { }); + // TODO(b/187074722): Don't create this per-TaskViewSimulator + mOrientationState = TraceHelper.allowIpcs("", + () -> new RecentsOrientedState(context, sizeStrategy, i -> { })); mOrientationState.setGestureActive(true); mCurrentFullscreenParams = new FullscreenDrawParams(context); mOrientationStateId = mOrientationState.getStateId(); From 21930da9a2bfad861449347567f2fc6b5d4cc71d Mon Sep 17 00:00:00 2001 From: Jonathan Miranda Date: Mon, 3 May 2021 18:44:13 +0000 Subject: [PATCH 04/19] Revert "Revert "Use color extraction for arrow popup."" This reverts commit 17fda29bf35bc4f21ede07319ffe26c88fea1b81. Reason for revert: Fixing the memory leak Leak was detected in caused launcher tapl tests to fail. For instructions on how to debug leaks, see go/launcher-testing. Using AS memory profiler, the color extractor class is holding onto a reference to launcher that has already been destroyed. The fix is to set the listener to null when view is closed. Bug: 175329686 Test: run profiler in AS, open and close popups, and verify no leaks Change-Id: I2d4a87f0481cbc88f3587dce91278e85ca113545 --- src/com/android/launcher3/CellLayout.java | 11 +- src/com/android/launcher3/Utilities.java | 50 ++++++++ .../graphics/PreloadIconDrawable.java | 6 +- .../android/launcher3/popup/ArrowPopup.java | 106 ++++++++++++++++- .../launcher3/util/ColorExtractionUtils.java | 110 ++++++++++++++++++ src/com/android/launcher3/util/Themes.java | 7 +- .../launcher3/views/FloatingIconView.java | 11 +- .../widget/LauncherAppWidgetHostView.java | 80 ++++--------- 8 files changed, 296 insertions(+), 85 deletions(-) create mode 100644 src/com/android/launcher3/util/ColorExtractionUtils.java diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java index 2f755e11e0..af625a51be 100644 --- a/src/com/android/launcher3/CellLayout.java +++ b/src/com/android/launcher3/CellLayout.java @@ -18,6 +18,7 @@ package com.android.launcher3; import static android.animation.ValueAnimator.areAnimatorsEnabled; +import static com.android.launcher3.Utilities.getBoundsForViewInDragLayer; import static com.android.launcher3.anim.Interpolators.DEACCEL_1_5; import android.animation.Animator; @@ -193,6 +194,7 @@ public class CellLayout extends ViewGroup { private static final int INVALID_DIRECTION = -100; private final Rect mTempRect = new Rect(); + private final RectF mTempRectF = new RectF(); private static final Paint sPaint = new Paint(); @@ -1070,11 +1072,16 @@ public class CellLayout extends ViewGroup { // Apply local extracted color if the DragView is an AppWidgetHostViewDrawable. View view = dragObject.dragView.getContentView(); if (view instanceof LauncherAppWidgetHostView) { - Workspace workspace = - Launcher.getLauncher(dragObject.dragView.getContext()).getWorkspace(); + Launcher launcher = Launcher.getLauncher(dragObject.dragView.getContext()); + Workspace workspace = launcher.getWorkspace(); int screenId = workspace.getIdForScreen(this); int pageId = workspace.getPageIndexForScreenId(screenId); cellToRect(targetCell[0], targetCell[1], spanX, spanY, mTempRect); + + // Now get the rect in drag layer coordinates. + getBoundsForViewInDragLayer(launcher.getDragLayer(), workspace, mTempRect, false, + mTempRectF); + Utilities.setRect(mTempRectF, mTempRect); ((LauncherAppWidgetHostView) view).handleDrag(mTempRect, pageId); } } diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java index be5463ec2c..bff3cabe22 100644 --- a/src/com/android/launcher3/Utilities.java +++ b/src/com/android/launcher3/Utilities.java @@ -33,6 +33,7 @@ import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.pm.ShortcutInfo; +import android.content.res.Configuration; import android.content.res.Resources; import android.database.ContentObserver; import android.graphics.Bitmap; @@ -84,6 +85,7 @@ import com.android.launcher3.shortcuts.ShortcutKey; import com.android.launcher3.shortcuts.ShortcutRequest; import com.android.launcher3.util.IntArray; import com.android.launcher3.util.PackageManagerHelper; +import com.android.launcher3.views.BaseDragLayer; import com.android.launcher3.widget.PendingAddShortcutInfo; import java.lang.reflect.Method; @@ -104,6 +106,8 @@ public final class Utilities { private static final Pattern sTrimPattern = Pattern.compile("^[\\s|\\p{javaSpaceChar}]*(.*)[\\s|\\p{javaSpaceChar}]*$"); + private static final float[] sTmpFloatArray = new float[4]; + private static final int[] sLoc0 = new int[2]; private static final int[] sLoc1 = new int[2]; private static final Matrix sMatrix = new Matrix(); @@ -133,6 +137,15 @@ public final class Utilities { Build.TYPE.toLowerCase(Locale.ROOT).contains("debug") || Build.TYPE.toLowerCase(Locale.ROOT).equals("eng"); + /** + * Returns true if theme is dark. + */ + public static boolean isDarkTheme(Context context) { + Configuration configuration = context.getResources().getConfiguration(); + int nightMode = configuration.uiMode & Configuration.UI_MODE_NIGHT_MASK; + return nightMode == Configuration.UI_MODE_NIGHT_YES; + } + public static boolean isDevelopersOptionsEnabled(Context context) { return Settings.Global.getInt(context.getApplicationContext().getContentResolver(), Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 0) != 0; @@ -218,6 +231,33 @@ public final class Utilities { return scale; } + /** + * Returns bounds for a child view of DragLayer, in drag layer coordinates. + * + * see {@link com.android.launcher3.dragndrop.DragLayer}. + * + * @param viewBounds Bounds of the view wanted in drag layer coordinates, relative to the view + * itself. eg. (0, 0, view.getWidth, view.getHeight) + * @param ignoreTransform If true, view transform is ignored + * @param outRect The out rect where we return the bounds of {@param view} in drag layer coords. + */ + public static void getBoundsForViewInDragLayer(BaseDragLayer dragLayer, View view, + Rect viewBounds, boolean ignoreTransform, RectF outRect) { + float[] points = sTmpFloatArray; + points[0] = viewBounds.left; + points[1] = viewBounds.top; + points[2] = viewBounds.right; + points[3] = viewBounds.bottom; + + Utilities.getDescendantCoordRelativeToAncestor(view, dragLayer, points, + false, ignoreTransform); + outRect.set( + Math.min(points[0], points[2]), + Math.min(points[1], points[3]), + Math.max(points[0], points[2]), + Math.max(points[1], points[3])); + } + /** * Inverse of {@link #getDescendantCoordRelativeToAncestor(View, View, float[], boolean)}. */ @@ -273,6 +313,16 @@ public final class Utilities { return new int[] {sLoc1[0] - sLoc0[0], sLoc1[1] - sLoc0[1]}; } + /** + * Helper method to set rectOut with rectFSrc. + */ + public static void setRect(RectF rectFSrc, Rect rectOut) { + rectOut.left = (int) rectFSrc.left; + rectOut.top = (int) rectFSrc.top; + rectOut.right = (int) rectFSrc.right; + rectOut.bottom = (int) rectFSrc.bottom; + } + public static void scaleRectFAboutCenter(RectF r, float scale) { if (scale != 1.0f) { float cx = r.centerX(); diff --git a/src/com/android/launcher3/graphics/PreloadIconDrawable.java b/src/com/android/launcher3/graphics/PreloadIconDrawable.java index 13ae866efb..e45b8f7918 100644 --- a/src/com/android/launcher3/graphics/PreloadIconDrawable.java +++ b/src/com/android/launcher3/graphics/PreloadIconDrawable.java @@ -21,7 +21,6 @@ import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ObjectAnimator; import android.content.Context; -import android.content.res.Configuration; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Matrix; @@ -34,6 +33,7 @@ import android.util.Property; import android.util.SparseArray; import android.view.ContextThemeWrapper; +import com.android.launcher3.Utilities; import com.android.launcher3.anim.Interpolators; import com.android.launcher3.icons.FastBitmapDrawable; import com.android.launcher3.icons.GraphicsUtils; @@ -119,9 +119,7 @@ public class PreloadIconDrawable extends FastBitmapDrawable { info, IconPalette.getPreloadProgressColor(context, info.bitmap.color), getPreloadColors(context), - (context.getResources().getConfiguration().uiMode - & Configuration.UI_MODE_NIGHT_MASK - & Configuration.UI_MODE_NIGHT_YES) != 0) /* isDarkMode */; + Utilities.isDarkTheme(context)); } public PreloadIconDrawable( diff --git a/src/com/android/launcher3/popup/ArrowPopup.java b/src/com/android/launcher3/popup/ArrowPopup.java index c19dfe9300..5684c5a1cc 100644 --- a/src/com/android/launcher3/popup/ArrowPopup.java +++ b/src/com/android/launcher3/popup/ArrowPopup.java @@ -16,9 +16,9 @@ package com.android.launcher3.popup; -import static com.android.launcher3.AbstractFloatingView.getTopOpenViewWithType; import static com.android.launcher3.anim.Interpolators.ACCEL_DEACCEL; import static com.android.launcher3.popup.PopupPopulator.MAX_SHORTCUTS; +import static com.android.launcher3.util.ColorExtractionUtils.getColorExtractionRect; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; @@ -31,6 +31,7 @@ import android.content.Context; import android.content.res.Resources; import android.graphics.Outline; import android.graphics.Rect; +import android.graphics.RectF; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.GradientDrawable; @@ -41,17 +42,21 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.ViewOutlineProvider; +import android.view.ViewTreeObserver; import android.widget.FrameLayout; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import com.android.launcher3.AbstractFloatingView; import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.InsettableFrameLayout; +import com.android.launcher3.Launcher; import com.android.launcher3.LauncherAnimUtils; import com.android.launcher3.LauncherState; import com.android.launcher3.R; import com.android.launcher3.Utilities; +import com.android.launcher3.Workspace; import com.android.launcher3.anim.RevealOutlineAnimation; import com.android.launcher3.anim.RoundedRectRevealOutlineProvider; import com.android.launcher3.dragndrop.DragLayer; @@ -59,9 +64,11 @@ import com.android.launcher3.shortcuts.DeepShortcutView; import com.android.launcher3.statemanager.StatefulActivity; import com.android.launcher3.util.Themes; import com.android.launcher3.views.BaseDragLayer; +import com.android.launcher3.widget.LocalColorExtractor; import java.util.ArrayList; import java.util.Collections; +import java.util.HashMap; /** * A container for shortcuts to deep links and notifications associated with an app. @@ -73,6 +80,9 @@ public abstract class ArrowPopup> // +1 for system shortcut view private static final int MAX_NUM_CHILDREN = MAX_SHORTCUTS + 1; + // Index used to get background color when using local wallpaper color extraction, + private static final int LIGHT_COLOR_EXTRACTION_INDEX = android.R.color.system_accent2_50; + private static final int DARK_COLOR_EXTRACTION_INDEX = android.R.color.system_accent2_800; private final Rect mTempRect = new Rect(); @@ -104,8 +114,14 @@ public abstract class ArrowPopup> private Runnable mOnCloseCallback = () -> { }; + // The rect string of the view that the arrow is attached to, in screen reference frame. + private String mArrowColorRectString; private int mArrowColor; private final int[] mColors; + private final HashMap mViewForRect = new HashMap<>(); + + private final int mColorExtractionIndex; + @Nullable private LocalColorExtractor mColorExtractor; public ArrowPopup(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); @@ -113,7 +129,9 @@ public abstract class ArrowPopup> mOutlineRadius = Themes.getDialogCornerRadius(context); mLauncher = BaseDraggingActivity.fromContext(context); mIsRtl = Utilities.isRtl(getResources()); - + mColorExtractionIndex = Utilities.isDarkTheme(context) + ? DARK_COLOR_EXTRACTION_INDEX + : LIGHT_COLOR_EXTRACTION_INDEX; setClipToOutline(true); setOutlineProvider(new ViewOutlineProvider() { @Override @@ -158,6 +176,10 @@ public abstract class ArrowPopup> mColors[i] = (int) argb.evaluate((i + 1) * step, primaryColor, secondaryColor); } + + if (Utilities.ATLEAST_S) { + setupColorExtraction(); + } } } @@ -342,6 +364,15 @@ public abstract class ArrowPopup> // so we centered it instead. In that case we don't want to showDefaultOptions the arrow. mArrow.setVisibility(INVISIBLE); } else { + updateArrowColor(); + } + + mArrow.setPivotX(mArrowWidth / 2.0f); + mArrow.setPivotY(mIsAboveIcon ? mArrowHeight : 0); + } + + private void updateArrowColor() { + if (!Gravity.isVertical(mGravity)) { mArrow.setBackground(new RoundedArrowDrawable( mArrowWidth, mArrowHeight, mArrowPointRadius, mOutlineRadius, getMeasuredWidth(), getMeasuredHeight(), @@ -350,9 +381,6 @@ public abstract class ArrowPopup> mArrowColor)); mArrow.setElevation(getElevation()); } - - mArrow.setPivotX(mArrowWidth / 2.0f); - mArrow.setPivotY(mIsAboveIcon ? mArrowHeight : 0); } /** @@ -671,6 +699,12 @@ public abstract class ArrowPopup> getPopupContainer().removeView(this); getPopupContainer().removeView(mArrow); mOnCloseCallback.run(); + mArrowColorRectString = null; + mViewForRect.clear(); + if (mColorExtractor != null) { + mColorExtractor.removeLocations(); + mColorExtractor.setListener(null); + } } /** @@ -680,6 +714,68 @@ public abstract class ArrowPopup> mOnCloseCallback = callback; } + private void setupColorExtraction() { + Workspace workspace = mLauncher.findViewById(R.id.workspace); + if (workspace == null) { + return; + } + + mColorExtractor = LocalColorExtractor.newInstance(mLauncher); + mColorExtractor.setListener((rect, extractedColors) -> { + String rectString = rect.toShortString(); + View v = mViewForRect.get(rectString); + if (v != null) { + int newColor = extractedColors.get(mColorExtractionIndex); + setChildColor(v, newColor); + if (rectString.equals(mArrowColorRectString)) { + mArrowColor = newColor; + updateArrowColor(); + } + } + }); + + getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { + @Override + public boolean onPreDraw() { + getViewTreeObserver().removeOnPreDrawListener(this); + + ArrayList locations = new ArrayList<>(); + Rect r = new Rect(); + + int count = getChildCount(); + int numVisibleChild = 0; + for (int i = 0; i < count; i++) { + View view = getChildAt(i); + if (view.getVisibility() == VISIBLE) { + RectF rf = new RectF(); + getColorExtractionRect(Launcher.getLauncher(getContext()), + workspace.getCurrentPage(), view, rf); + if (rf.isEmpty()) { + numVisibleChild++; + continue; + } + + locations.add(rf); + String rectString = rf.toShortString(); + mViewForRect.put(rectString, view); + + // Arrow color matches the first child or the last child. + if (!mIsAboveIcon && numVisibleChild == 0) { + mArrowColorRectString = rectString; + } else if (mIsAboveIcon) { + mArrowColorRectString = rectString; + } + + numVisibleChild++; + } + } + + mColorExtractor.addLocation(locations); + return false; + } + }); + } + protected BaseDragLayer getPopupContainer() { return mLauncher.getDragLayer(); } diff --git a/src/com/android/launcher3/util/ColorExtractionUtils.java b/src/com/android/launcher3/util/ColorExtractionUtils.java new file mode 100644 index 0000000000..b377ded44a --- /dev/null +++ b/src/com/android/launcher3/util/ColorExtractionUtils.java @@ -0,0 +1,110 @@ +/* + * 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.util; + +import android.content.res.Resources; +import android.graphics.Rect; +import android.graphics.RectF; +import android.view.View; + +import com.android.launcher3.DeviceProfile; +import com.android.launcher3.Launcher; +import com.android.launcher3.Utilities; + +/** + * Utility class used to map launcher views to wallpaper rect. + */ +public class ColorExtractionUtils { + + public static final String TAG = "ColorExtractionUtils"; + + private static final Rect sTempRect = new Rect(); + private static final RectF sTempRectF = new RectF(); + + /** + * Takes a view and returns its rect that can be used by the wallpaper local color extractor. + * + * @param launcher Launcher class class. + * @param pageId The page the workspace item is on. + * @param v The view. + * @param colorExtractionRectOut The location rect, but converted to a format expected by the + * wallpaper local color extractor. + */ + public static void getColorExtractionRect(Launcher launcher, int pageId, View v, + RectF colorExtractionRectOut) { + Rect viewRect = sTempRect; + viewRect.set(0, 0, v.getWidth(), v.getHeight()); + Utilities.getBoundsForViewInDragLayer(launcher.getDragLayer(), v, viewRect, false, + sTempRectF); + Utilities.setRect(sTempRectF, viewRect); + getColorExtractionRect(launcher, pageId, viewRect, colorExtractionRectOut); + } + + /** + * Takes a rect in drag layer coordinates and returns the rect that can be used by the wallpaper + * local color extractor. + * + * @param launcher Launcher class. + * @param pageId The page the workspace item is on. + * @param rectInDragLayer The relevant bounds of the view in drag layer coordinates. + * @param colorExtractionRectOut The location rect, but converted to a format expected by the + * wallpaper local color extractor. + */ + public static void getColorExtractionRect(Launcher launcher, int pageId, Rect rectInDragLayer, + RectF colorExtractionRectOut) { + // If the view hasn't been measured and laid out, we cannot do this. + if (rectInDragLayer.isEmpty()) { + colorExtractionRectOut.setEmpty(); + return; + } + + Resources res = launcher.getResources(); + DeviceProfile dp = launcher.getDeviceProfile().inv.getDeviceProfile(launcher); + float screenWidth = dp.widthPx; + float screenHeight = dp.heightPx; + int numScreens = launcher.getWorkspace().getNumPagesForWallpaperParallax(); + pageId = Utilities.isRtl(res) ? numScreens - pageId - 1 : pageId; + float relativeScreenWidth = 1f / numScreens; + + int[] dragLayerBounds = new int[2]; + launcher.getDragLayer().getLocationOnScreen(dragLayerBounds); + // Translate from drag layer coordinates to screen coordinates. + int screenLeft = rectInDragLayer.left + dragLayerBounds[0]; + int screenTop = rectInDragLayer.top + dragLayerBounds[1]; + int screenRight = rectInDragLayer.right + dragLayerBounds[0]; + int screenBottom = rectInDragLayer.bottom + dragLayerBounds[1]; + + // This is the position of the view relative to the wallpaper, as expected by the + // local color extraction of the WallpaperManager. + // The coordinate system is such that, on the horizontal axis, each screen has a + // distinct range on the [0,1] segment. So if there are 3 screens, they will have the + // ranges [0, 1/3], [1/3, 2/3] and [2/3, 1]. The position on the subrange should be + // the position of the view relative to the screen. For the vertical axis, this is + // simply the location of the view relative to the screen. + // Translate from drag layer coordinates to screen coordinates + colorExtractionRectOut.left = (screenLeft / screenWidth + pageId) * relativeScreenWidth; + colorExtractionRectOut.right = (screenRight / screenWidth + pageId) * relativeScreenWidth; + colorExtractionRectOut.top = screenTop / screenHeight; + colorExtractionRectOut.bottom = screenBottom / screenHeight; + + if (colorExtractionRectOut.left < 0 + || colorExtractionRectOut.right > 1 + || colorExtractionRectOut.top < 0 + || colorExtractionRectOut.bottom > 1) { + colorExtractionRectOut.setEmpty(); + } + } +} diff --git a/src/com/android/launcher3/util/Themes.java b/src/com/android/launcher3/util/Themes.java index 99942aa56d..06cac08aec 100644 --- a/src/com/android/launcher3/util/Themes.java +++ b/src/com/android/launcher3/util/Themes.java @@ -22,7 +22,6 @@ import static android.app.WallpaperColors.HINT_SUPPORTS_DARK_THEME; import android.app.WallpaperColors; import android.app.WallpaperManager; import android.content.Context; -import android.content.res.Configuration; import android.content.res.TypedArray; import android.graphics.Color; import android.graphics.ColorMatrix; @@ -54,16 +53,12 @@ public class Themes { } public static int getActivityThemeRes(Context context, int wallpaperColorHints) { - Configuration configuration = context.getResources().getConfiguration(); - int nightMode = configuration.uiMode & Configuration.UI_MODE_NIGHT_MASK; - boolean darkTheme = nightMode == Configuration.UI_MODE_NIGHT_YES; - boolean supportsDarkText = Utilities.ATLEAST_S && (wallpaperColorHints & HINT_SUPPORTS_DARK_TEXT) != 0; boolean isMainColorDark = Utilities.ATLEAST_S && (wallpaperColorHints & HINT_SUPPORTS_DARK_THEME) != 0; - if (darkTheme) { + if (Utilities.isDarkTheme(context)) { return supportsDarkText ? R.style.AppTheme_Dark_DarkText : isMainColorDark ? R.style.AppTheme_Dark_DarkMainColor : R.style.AppTheme_Dark; } else { diff --git a/src/com/android/launcher3/views/FloatingIconView.java b/src/com/android/launcher3/views/FloatingIconView.java index d49320b073..1ddd1ba89f 100644 --- a/src/com/android/launcher3/views/FloatingIconView.java +++ b/src/com/android/launcher3/views/FloatingIconView.java @@ -233,15 +233,8 @@ public class FloatingIconView extends FrameLayout implements outViewBounds.set(0, 0, v.getWidth(), v.getHeight()); } - float[] points = new float[] {outViewBounds.left, outViewBounds.top, outViewBounds.right, - outViewBounds.bottom}; - Utilities.getDescendantCoordRelativeToAncestor(v, launcher.getDragLayer(), points, - false, ignoreTransform); - outRect.set( - Math.min(points[0], points[2]), - Math.min(points[1], points[3]), - Math.max(points[0], points[2]), - Math.max(points[1], points[3])); + Utilities.getBoundsForViewInDragLayer(launcher.getDragLayer(), v, outViewBounds, + ignoreTransform, outRect); } /** diff --git a/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java b/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java index 620604a4d1..697c4531c2 100644 --- a/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java +++ b/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java @@ -16,6 +16,10 @@ package com.android.launcher3.widget; +import static com.android.launcher3.Utilities.getBoundsForViewInDragLayer; +import static com.android.launcher3.Utilities.setRect; +import static com.android.launcher3.util.ColorExtractionUtils.getColorExtractionRect; + import android.appwidget.AppWidgetProviderInfo; import android.content.Context; import android.content.res.Configuration; @@ -25,7 +29,6 @@ import android.graphics.Rect; import android.graphics.RectF; import android.os.Handler; import android.os.SystemClock; -import android.util.Log; import android.util.SparseBooleanArray; import android.util.SparseIntArray; import android.view.LayoutInflater; @@ -95,11 +98,11 @@ public class LauncherAppWidgetHostView extends NavigableAppWidgetHostView private RectF mLastLocationRegistered = null; @Nullable private AppWidgetHostViewDragListener mDragListener; - // Used to store the widget size during onLayout. + // Used to store the widget sizes in drag layer coordinates. private final Rect mCurrentWidgetSize = new Rect(); private final Rect mWidgetSizeAtDrag = new Rect(); + private final RectF mTempRectF = new RectF(); - private final boolean mIsRtl; private final Rect mEnforcedRectangle = new Rect(); private final float mEnforcedCornerRadius; private final ViewOutlineProvider mCornerRadiusEnforcementOutline = new ViewOutlineProvider() { @@ -129,7 +132,6 @@ public class LauncherAppWidgetHostView extends NavigableAppWidgetHostView if (Utilities.ATLEAST_Q && Themes.getAttrBoolean(mLauncher, R.attr.isWorkspaceDarkText)) { setOnLightBackground(true); } - mIsRtl = Utilities.isRtl(context.getResources()); mColorExtractor = LocalColorExtractor.newInstance(getContext()); mColorExtractor.setListener(this); @@ -319,13 +321,12 @@ public class LauncherAppWidgetHostView extends NavigableAppWidgetHostView mIsScrollable = checkScrollableRecursively(this); if (!mIsInDragMode && getTag() instanceof LauncherAppWidgetInfo) { - mCurrentWidgetSize.left = left; - mCurrentWidgetSize.top = top; - mCurrentWidgetSize.right = right; - mCurrentWidgetSize.bottom = bottom; LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) getTag(); - int pageId = mWorkspace.getPageIndexForScreenId(info.screenId); - updateColorExtraction(mCurrentWidgetSize, pageId); + getBoundsForViewInDragLayer(mLauncher.getDragLayer(), this, mCurrentWidgetSize, true, + mTempRectF); + setRect(mTempRectF, mCurrentWidgetSize); + updateColorExtraction(mCurrentWidgetSize, + mWorkspace.getPageIndexForScreenId(info.screenId)); } enforceRoundedCorners(); @@ -338,8 +339,8 @@ public class LauncherAppWidgetHostView extends NavigableAppWidgetHostView } /** Handles a drag event occurred on a workspace page, {@code pageId}. */ - public void handleDrag(Rect rect, int pageId) { - mWidgetSizeAtDrag.set(rect); + public void handleDrag(Rect rectInDragLayer, int pageId) { + mWidgetSizeAtDrag.set(rectInDragLayer); updateColorExtraction(mWidgetSizeAtDrag, pageId); } @@ -351,53 +352,14 @@ public class LauncherAppWidgetHostView extends NavigableAppWidgetHostView requestLayout(); } - private void updateColorExtraction(Rect widgetLocation, int pageId) { - // If the widget hasn't been measured and laid out, we cannot do this. - if (widgetLocation.isEmpty()) { - return; - } - int screenWidth = mLauncher.getDeviceProfile().widthPx; - int screenHeight = mLauncher.getDeviceProfile().heightPx; - int numScreens = mWorkspace.getNumPagesForWallpaperParallax(); - pageId = mIsRtl ? numScreens - pageId - 1 : pageId; - float relativeScreenWidth = 1f / numScreens; - float absoluteTop = widgetLocation.top; - float absoluteBottom = widgetLocation.bottom; - 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(); - } - float xOffset = 0; - View parentView = (View) getParent(); - // The layout depends on the orientation. - if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) { - int parentViewWidth = parentView == null ? 0 : parentView.getWidth(); - xOffset = screenWidth - mWorkspace.getPaddingRight() - parentViewWidth; - } else { - int parentViewPaddingLeft = parentView == null ? 0 : parentView.getPaddingLeft(); - xOffset = mWorkspace.getPaddingLeft() + parentViewPaddingLeft; - } - // This is the position of the widget relative to the wallpaper, as expected by the - // local color extraction of the WallpaperManager. - // The coordinate system is such that, on the horizontal axis, each screen has a - // distinct range on the [0,1] segment. So if there are 3 screens, they will have the - // ranges [0, 1/3], [1/3, 2/3] and [2/3, 1]. The position on the subrange should be - // the position of the widget relative to the screen. For the vertical axis, this is - // simply the location of the widget relative to the screen. - mTempRectF.left = ((widgetLocation.left + xOffset) / screenWidth + pageId) - * relativeScreenWidth; - mTempRectF.right = ((widgetLocation.right + xOffset) / screenWidth + pageId) - * relativeScreenWidth; - mTempRectF.top = absoluteTop / screenHeight; - mTempRectF.bottom = absoluteBottom / screenHeight; - if (mTempRectF.left < 0 || mTempRectF.right > 1 || mTempRectF.top < 0 - || mTempRectF.bottom > 1) { - Log.e(LOG_TAG, " Error, invalid relative position"); + /** + * @param rectInDragLayer Rect of widget in drag layer coordinates. + * @param pageId The workspace page the widget is on. + */ + private void updateColorExtraction(Rect rectInDragLayer, int pageId) { + getColorExtractionRect(mLauncher, pageId, rectInDragLayer, mTempRectF); + + if (mTempRectF.isEmpty()) { return; } if (!mTempRectF.equals(mLastLocationRegistered)) { From 88b7f6a0d57e0643a6ce2f3534c184ca56b0c30b Mon Sep 17 00:00:00 2001 From: Jon Miranda Date: Mon, 3 May 2021 16:49:53 -0700 Subject: [PATCH 05/19] Move color extraction utils to extractor class so each instance can have its own set of temp variables. - Pass in float[] param to not create new obj in each frame for dragging widget case. Bug: 175329686 Bug: 187019711 Test: manual, verify Change-Id: I4350fb7e66a80c73def5659fb41abc14d357e667 --- src/com/android/launcher3/CellLayout.java | 3 +- src/com/android/launcher3/Utilities.java | 4 +- .../android/launcher3/popup/ArrowPopup.java | 3 +- .../launcher3/util/ColorExtractionUtils.java | 110 ------------------ .../launcher3/views/FloatingIconView.java | 2 +- .../widget/LauncherAppWidgetHostView.java | 6 +- .../launcher3/widget/LocalColorExtractor.java | 32 +++++ 7 files changed, 41 insertions(+), 119 deletions(-) delete mode 100644 src/com/android/launcher3/util/ColorExtractionUtils.java diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java index af625a51be..1df9df6763 100644 --- a/src/com/android/launcher3/CellLayout.java +++ b/src/com/android/launcher3/CellLayout.java @@ -195,6 +195,7 @@ public class CellLayout extends ViewGroup { private final Rect mTempRect = new Rect(); private final RectF mTempRectF = new RectF(); + private final float[] mTmpFloatArray = new float[4]; private static final Paint sPaint = new Paint(); @@ -1080,7 +1081,7 @@ public class CellLayout extends ViewGroup { // Now get the rect in drag layer coordinates. getBoundsForViewInDragLayer(launcher.getDragLayer(), workspace, mTempRect, false, - mTempRectF); + mTmpFloatArray, mTempRectF); Utilities.setRect(mTempRectF, mTempRect); ((LauncherAppWidgetHostView) view).handleDrag(mTempRect, pageId); } diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java index bff3cabe22..972a6e84f5 100644 --- a/src/com/android/launcher3/Utilities.java +++ b/src/com/android/launcher3/Utilities.java @@ -242,8 +242,8 @@ public final class Utilities { * @param outRect The out rect where we return the bounds of {@param view} in drag layer coords. */ public static void getBoundsForViewInDragLayer(BaseDragLayer dragLayer, View view, - Rect viewBounds, boolean ignoreTransform, RectF outRect) { - float[] points = sTmpFloatArray; + Rect viewBounds, boolean ignoreTransform, float[] recycle, RectF outRect) { + float[] points = recycle == null ? new float[4] : recycle; points[0] = viewBounds.left; points[1] = viewBounds.top; points[2] = viewBounds.right; diff --git a/src/com/android/launcher3/popup/ArrowPopup.java b/src/com/android/launcher3/popup/ArrowPopup.java index 5684c5a1cc..c63d69dfd3 100644 --- a/src/com/android/launcher3/popup/ArrowPopup.java +++ b/src/com/android/launcher3/popup/ArrowPopup.java @@ -18,7 +18,6 @@ package com.android.launcher3.popup; import static com.android.launcher3.anim.Interpolators.ACCEL_DEACCEL; import static com.android.launcher3.popup.PopupPopulator.MAX_SHORTCUTS; -import static com.android.launcher3.util.ColorExtractionUtils.getColorExtractionRect; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; @@ -748,7 +747,7 @@ public abstract class ArrowPopup> View view = getChildAt(i); if (view.getVisibility() == VISIBLE) { RectF rf = new RectF(); - getColorExtractionRect(Launcher.getLauncher(getContext()), + mColorExtractor.getExtractedRectForView(Launcher.getLauncher(getContext()), workspace.getCurrentPage(), view, rf); if (rf.isEmpty()) { numVisibleChild++; diff --git a/src/com/android/launcher3/util/ColorExtractionUtils.java b/src/com/android/launcher3/util/ColorExtractionUtils.java deleted file mode 100644 index b377ded44a..0000000000 --- a/src/com/android/launcher3/util/ColorExtractionUtils.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * 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.util; - -import android.content.res.Resources; -import android.graphics.Rect; -import android.graphics.RectF; -import android.view.View; - -import com.android.launcher3.DeviceProfile; -import com.android.launcher3.Launcher; -import com.android.launcher3.Utilities; - -/** - * Utility class used to map launcher views to wallpaper rect. - */ -public class ColorExtractionUtils { - - public static final String TAG = "ColorExtractionUtils"; - - private static final Rect sTempRect = new Rect(); - private static final RectF sTempRectF = new RectF(); - - /** - * Takes a view and returns its rect that can be used by the wallpaper local color extractor. - * - * @param launcher Launcher class class. - * @param pageId The page the workspace item is on. - * @param v The view. - * @param colorExtractionRectOut The location rect, but converted to a format expected by the - * wallpaper local color extractor. - */ - public static void getColorExtractionRect(Launcher launcher, int pageId, View v, - RectF colorExtractionRectOut) { - Rect viewRect = sTempRect; - viewRect.set(0, 0, v.getWidth(), v.getHeight()); - Utilities.getBoundsForViewInDragLayer(launcher.getDragLayer(), v, viewRect, false, - sTempRectF); - Utilities.setRect(sTempRectF, viewRect); - getColorExtractionRect(launcher, pageId, viewRect, colorExtractionRectOut); - } - - /** - * Takes a rect in drag layer coordinates and returns the rect that can be used by the wallpaper - * local color extractor. - * - * @param launcher Launcher class. - * @param pageId The page the workspace item is on. - * @param rectInDragLayer The relevant bounds of the view in drag layer coordinates. - * @param colorExtractionRectOut The location rect, but converted to a format expected by the - * wallpaper local color extractor. - */ - public static void getColorExtractionRect(Launcher launcher, int pageId, Rect rectInDragLayer, - RectF colorExtractionRectOut) { - // If the view hasn't been measured and laid out, we cannot do this. - if (rectInDragLayer.isEmpty()) { - colorExtractionRectOut.setEmpty(); - return; - } - - Resources res = launcher.getResources(); - DeviceProfile dp = launcher.getDeviceProfile().inv.getDeviceProfile(launcher); - float screenWidth = dp.widthPx; - float screenHeight = dp.heightPx; - int numScreens = launcher.getWorkspace().getNumPagesForWallpaperParallax(); - pageId = Utilities.isRtl(res) ? numScreens - pageId - 1 : pageId; - float relativeScreenWidth = 1f / numScreens; - - int[] dragLayerBounds = new int[2]; - launcher.getDragLayer().getLocationOnScreen(dragLayerBounds); - // Translate from drag layer coordinates to screen coordinates. - int screenLeft = rectInDragLayer.left + dragLayerBounds[0]; - int screenTop = rectInDragLayer.top + dragLayerBounds[1]; - int screenRight = rectInDragLayer.right + dragLayerBounds[0]; - int screenBottom = rectInDragLayer.bottom + dragLayerBounds[1]; - - // This is the position of the view relative to the wallpaper, as expected by the - // local color extraction of the WallpaperManager. - // The coordinate system is such that, on the horizontal axis, each screen has a - // distinct range on the [0,1] segment. So if there are 3 screens, they will have the - // ranges [0, 1/3], [1/3, 2/3] and [2/3, 1]. The position on the subrange should be - // the position of the view relative to the screen. For the vertical axis, this is - // simply the location of the view relative to the screen. - // Translate from drag layer coordinates to screen coordinates - colorExtractionRectOut.left = (screenLeft / screenWidth + pageId) * relativeScreenWidth; - colorExtractionRectOut.right = (screenRight / screenWidth + pageId) * relativeScreenWidth; - colorExtractionRectOut.top = screenTop / screenHeight; - colorExtractionRectOut.bottom = screenBottom / screenHeight; - - if (colorExtractionRectOut.left < 0 - || colorExtractionRectOut.right > 1 - || colorExtractionRectOut.top < 0 - || colorExtractionRectOut.bottom > 1) { - colorExtractionRectOut.setEmpty(); - } - } -} diff --git a/src/com/android/launcher3/views/FloatingIconView.java b/src/com/android/launcher3/views/FloatingIconView.java index 1ddd1ba89f..81581fa80a 100644 --- a/src/com/android/launcher3/views/FloatingIconView.java +++ b/src/com/android/launcher3/views/FloatingIconView.java @@ -234,7 +234,7 @@ public class FloatingIconView extends FrameLayout implements } Utilities.getBoundsForViewInDragLayer(launcher.getDragLayer(), v, outViewBounds, - ignoreTransform, outRect); + ignoreTransform, null /** recycle */, outRect); } /** diff --git a/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java b/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java index 697c4531c2..5deecd4c8a 100644 --- a/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java +++ b/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java @@ -18,7 +18,6 @@ package com.android.launcher3.widget; import static com.android.launcher3.Utilities.getBoundsForViewInDragLayer; import static com.android.launcher3.Utilities.setRect; -import static com.android.launcher3.util.ColorExtractionUtils.getColorExtractionRect; import android.appwidget.AppWidgetProviderInfo; import android.content.Context; @@ -102,6 +101,7 @@ public class LauncherAppWidgetHostView extends NavigableAppWidgetHostView private final Rect mCurrentWidgetSize = new Rect(); private final Rect mWidgetSizeAtDrag = new Rect(); + private final float[] mTmpFloatArray = new float[4]; private final RectF mTempRectF = new RectF(); private final Rect mEnforcedRectangle = new Rect(); private final float mEnforcedCornerRadius; @@ -323,7 +323,7 @@ public class LauncherAppWidgetHostView extends NavigableAppWidgetHostView if (!mIsInDragMode && getTag() instanceof LauncherAppWidgetInfo) { LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) getTag(); getBoundsForViewInDragLayer(mLauncher.getDragLayer(), this, mCurrentWidgetSize, true, - mTempRectF); + mTmpFloatArray, mTempRectF); setRect(mTempRectF, mCurrentWidgetSize); updateColorExtraction(mCurrentWidgetSize, mWorkspace.getPageIndexForScreenId(info.screenId)); @@ -357,7 +357,7 @@ public class LauncherAppWidgetHostView extends NavigableAppWidgetHostView * @param pageId The workspace page the widget is on. */ private void updateColorExtraction(Rect rectInDragLayer, int pageId) { - getColorExtractionRect(mLauncher, pageId, rectInDragLayer, mTempRectF); + mColorExtractor.getExtractedRectForViewRect(mLauncher, pageId, rectInDragLayer, mTempRectF); if (mTempRectF.isEmpty()) { return; diff --git a/src/com/android/launcher3/widget/LocalColorExtractor.java b/src/com/android/launcher3/widget/LocalColorExtractor.java index be4faea68f..8ae6b2e435 100644 --- a/src/com/android/launcher3/widget/LocalColorExtractor.java +++ b/src/com/android/launcher3/widget/LocalColorExtractor.java @@ -19,11 +19,14 @@ package com.android.launcher3.widget; import android.app.WallpaperColors; import android.appwidget.AppWidgetHostView; import android.content.Context; +import android.graphics.Rect; import android.graphics.RectF; import android.util.SparseIntArray; +import android.view.View; import androidx.annotation.Nullable; +import com.android.launcher3.Launcher; import com.android.launcher3.R; import com.android.launcher3.util.ResourceBasedOverride; @@ -71,4 +74,33 @@ public class LocalColorExtractor implements ResourceBasedOverride { * Updates the base context to contain the colors override */ public void applyColorsOverride(Context base, WallpaperColors colors) { } + + /** + * Takes a view and returns its rect that can be used by the wallpaper local color extractor. + * + * @param launcher Launcher class class. + * @param pageId The page the workspace item is on. + * @param v The view. + * @param colorExtractionRectOut The location rect, but converted to a format expected by the + * wallpaper local color extractor. + */ + public void getExtractedRectForView(Launcher launcher, int pageId, View v, + RectF colorExtractionRectOut) { + // no-op + } + + /** + * Takes a rect in drag layer coordinates and returns the rect that can be used by the wallpaper + * local color extractor. + * + * @param launcher Launcher class. + * @param pageId The page the workspace item is on. + * @param rectInDragLayer The relevant bounds of the view in drag layer coordinates. + * @param colorExtractionRectOut The location rect, but converted to a format expected by the + * wallpaper local color extractor. + */ + public void getExtractedRectForViewRect(Launcher launcher, int pageId, Rect rectInDragLayer, + RectF colorExtractionRectOut) { + // no-op + } } From 79d76b5041e0ac328e5c7d94f7ee326b630729f2 Mon Sep 17 00:00:00 2001 From: Steven Ng Date: Wed, 28 Apr 2021 23:16:22 +0100 Subject: [PATCH 06/19] Fix LayoutParams cast exception in drag-n-drop Test: Pick up a widget from home screen. Then drop it and immediately pick it up again before the resize frame is dismissed. No crash is observed. Bug: 186663184 Change-Id: Ia40676fbbf5d6dc2e2043aa7acd6ae00f1fa4179 --- .../launcher3/AppWidgetResizeFrame.java | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/com/android/launcher3/AppWidgetResizeFrame.java b/src/com/android/launcher3/AppWidgetResizeFrame.java index 5d41bb5c3e..401b58b2d5 100644 --- a/src/com/android/launcher3/AppWidgetResizeFrame.java +++ b/src/com/android/launcher3/AppWidgetResizeFrame.java @@ -71,6 +71,22 @@ public class AppWidgetResizeFrame extends AbstractFloatingView implements View.O private final View[] mDragHandles = new View[HANDLE_COUNT]; private final List mSystemGestureExclusionRects = new ArrayList<>(HANDLE_COUNT); + private final OnAttachStateChangeListener mWidgetViewAttachStateChangeListener = + new OnAttachStateChangeListener() { + @Override + public void onViewAttachedToWindow(View view) { + // Do nothing + } + + @Override + public void onViewDetachedFromWindow(View view) { + // When the app widget view is detached, we should close the resize frame. + // An example is when the dragging starts, the widget view is detached from + // CellLayout and then reattached to DragLayout. + close(false); + } + }; + private LauncherAppWidgetHostView mWidgetView; private CellLayout mCellLayout; @@ -191,7 +207,11 @@ public class AppWidgetResizeFrame extends AbstractFloatingView implements View.O private void setupForWidget(LauncherAppWidgetHostView widgetView, CellLayout cellLayout, DragLayer dragLayer) { mCellLayout = cellLayout; + if (mWidgetView != null) { + mWidgetView.removeOnAttachStateChangeListener(mWidgetViewAttachStateChangeListener); + } mWidgetView = widgetView; + mWidgetView.addOnAttachStateChangeListener(mWidgetViewAttachStateChangeListener); LauncherAppWidgetProviderInfo info = (LauncherAppWidgetProviderInfo) widgetView.getAppWidgetInfo(); mResizeMode = info.resizeMode; @@ -641,6 +661,9 @@ public class AppWidgetResizeFrame extends AbstractFloatingView implements View.O @Override protected void handleClose(boolean animate) { mDragLayer.removeView(this); + if (mWidgetView != null) { + mWidgetView.removeOnAttachStateChangeListener(mWidgetViewAttachStateChangeListener); + } } @Override From 7167c3f3c962f328b477736e089f167263fe5298 Mon Sep 17 00:00:00 2001 From: zakcohen Date: Tue, 4 May 2021 13:56:34 -0700 Subject: [PATCH 07/19] Make overview color tinting work properly. Bug: 179922117 Test: Local Change-Id: I0b6620be8184bab836ed91d087739df57817eb37 --- quickstep/src/com/android/quickstep/views/TaskView.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java index 45bcdc314b..08f5879301 100644 --- a/quickstep/src/com/android/quickstep/views/TaskView.java +++ b/quickstep/src/com/android/quickstep/views/TaskView.java @@ -1417,9 +1417,10 @@ public class TaskView extends FrameLayout implements Reusable { } private void setColorTint(float amount) { - mSnapshotView.setDimAlpha(amount); - mIconView.setIconColorTint(mTintingColor, amount); - mDigitalWellBeingToast.setBannerColorTint(mTintingColor, amount); + mTintAmount = amount; + mSnapshotView.setDimAlpha(mTintAmount); + mIconView.setIconColorTint(mTintingColor, mTintAmount); + mDigitalWellBeingToast.setBannerColorTint(mTintingColor, mTintAmount); } private float getColorTint() { From 96d4ec4544204b8f27dd96bd043cd13927ecb4aa Mon Sep 17 00:00:00 2001 From: Hyunyoung Song Date: Tue, 4 May 2021 09:08:09 -0700 Subject: [PATCH 08/19] All apps motion tuning [1/n] - reverse spring direction to enable overshoot - change master interpolators for swipe / fling Test: manual Bug: 183001675 Bug: 186121789 Change-Id: I5869d84daab99594cc2a261cb8f5d28e0293afe1 --- .../launcher3/allapps/AllAppsContainerView.java | 4 ++-- .../allapps/AllAppsTransitionController.java | 14 ++++++++------ 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java index 40f7ab167c..1d31caf745 100644 --- a/src/com/android/launcher3/allapps/AllAppsContainerView.java +++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java @@ -75,7 +75,7 @@ import com.android.launcher3.workprofile.PersonalWorkSlidingTabStrip.OnActivePag public class AllAppsContainerView extends SpringRelativeLayout implements DragSource, Insettable, OnDeviceProfileChangeListener, OnActivePageChangedListener { - private static final float FLING_VELOCITY_MULTIPLIER = 1800f; + private static final float FLING_VELOCITY_MULTIPLIER = 1000f; // Starts the springs after at least 25% of the animation has passed. private static final float FLING_ANIMATION_THRESHOLD = 0.25f; @@ -611,7 +611,7 @@ public class AllAppsContainerView extends SpringRelativeLayout implements DragSo public void onAnimationUpdate(ValueAnimator valueAnimator) { if (shouldSpring && valueAnimator.getAnimatedFraction() >= FLING_ANIMATION_THRESHOLD) { - absorbSwipeUpVelocity(-Math.abs( + absorbSwipeUpVelocity(Math.abs( Math.round(velocity * FLING_VELOCITY_MULTIPLIER))); shouldSpring = false; } diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java index c61c0d6d53..c4c7891d58 100644 --- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java +++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java @@ -15,13 +15,15 @@ */ package com.android.launcher3.allapps; +import static com.android.launcher3.LauncherState.ALL_APPS; import static com.android.launcher3.LauncherState.ALL_APPS_CONTENT; -import static com.android.launcher3.LauncherState.OVERVIEW; -import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN; +import static com.android.launcher3.anim.Interpolators.ACCEL_0_75; +import static com.android.launcher3.anim.Interpolators.ACCEL_2; +import static com.android.launcher3.anim.Interpolators.DEACCEL; +import static com.android.launcher3.anim.Interpolators.DEACCEL_2; import static com.android.launcher3.anim.Interpolators.LINEAR; import static com.android.launcher3.anim.PropertySetter.NO_ANIM_PROPERTY_SETTER; import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_APPS_FADE; -import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_SCALE; import static com.android.launcher3.states.StateAnimationConfig.ANIM_VERTICAL_PROGRESS; import static com.android.launcher3.util.SystemUiController.UI_STATE_ALLAPPS; @@ -154,9 +156,9 @@ public class AllAppsTransitionController return; } - Interpolator interpolator = config.userControlled ? LINEAR : toState == OVERVIEW - ? config.getInterpolator(ANIM_OVERVIEW_SCALE, FAST_OUT_SLOW_IN) - : FAST_OUT_SLOW_IN; + Interpolator interpolator = toState.equals(ALL_APPS) + ? (config.userControlled ? ACCEL_2 : ACCEL_0_75) : + (config.userControlled ? DEACCEL_2 : DEACCEL); Animator anim = createSpringAnimation(mProgress, targetProgress); anim.setInterpolator(config.getInterpolator(ANIM_VERTICAL_PROGRESS, interpolator)); From 474c616e981c60bcfc05114b4823b9176178240d Mon Sep 17 00:00:00 2001 From: Andy Wickham Date: Mon, 3 May 2021 18:26:44 -0700 Subject: [PATCH 09/19] Adds AllSetActivity in Launcher. Mostly copied from its location in Tips. Some exceptions: - Accent color (used for the icon at the top and link text) is derived from intent extras to match the rest of SUW. If needed, we could also pass other colors this way; currently they just use default light/dark mode colors. - Currently there is no animation in the middle. Not sure if one is expected, but we can add it later if so. Bug: 184722307 Test: Manually passing arbitrary colors via adb: adb shell am start -a com.android.quickstep.action.GESTURE_ONBOARDING_ALL_SET --ei accent_color_dark_mode -2134901760 --ei accent_color_light_mode 2147418112 Change-Id: I1fb8b20b88b7485d28f06afd2b421999ad847266 --- quickstep/AndroidManifest.xml | 32 +++- quickstep/res/drawable/ic_all_set.xml | 24 +++ quickstep/res/layout/activity_allset.xml | 80 ++++++++++ quickstep/res/values/attrs.xml | 22 +++ quickstep/res/values/dimens.xml | 7 + quickstep/res/values/strings.xml | 9 ++ quickstep/res/values/styles.xml | 7 +- .../quickstep/interaction/AllSetActivity.java | 133 ++++++++++++++++ .../quickstep/interaction/AnnotationSpan.java | 143 ++++++++++++++++++ 9 files changed, 452 insertions(+), 5 deletions(-) create mode 100644 quickstep/res/drawable/ic_all_set.xml create mode 100644 quickstep/res/layout/activity_allset.xml create mode 100644 quickstep/res/values/attrs.xml create mode 100644 quickstep/src/com/android/quickstep/interaction/AllSetActivity.java create mode 100644 quickstep/src/com/android/quickstep/interaction/AnnotationSpan.java diff --git a/quickstep/AndroidManifest.xml b/quickstep/AndroidManifest.xml index 842abc399f..7ab09c5ce9 100644 --- a/quickstep/AndroidManifest.xml +++ b/quickstep/AndroidManifest.xml @@ -103,16 +103,40 @@ android:clearTaskOnLaunch="true" android:exported="false"/> + + android:autoRemoveFromRecents="true" + android:excludeFromRecents="true" + android:screenOrientation="portrait" + android:permission="android.permission.REBOOT" + android:exported="true"> + + + + + + + + + + + + diff --git a/quickstep/res/layout/activity_allset.xml b/quickstep/res/layout/activity_allset.xml new file mode 100644 index 0000000000..a6a17e5ebc --- /dev/null +++ b/quickstep/res/layout/activity_allset.xml @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + diff --git a/quickstep/res/values/attrs.xml b/quickstep/res/values/attrs.xml new file mode 100644 index 0000000000..336fb572d5 --- /dev/null +++ b/quickstep/res/values/attrs.xml @@ -0,0 +1,22 @@ + + + + + + + + diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml index 9c0a083084..4f9b3ebe59 100644 --- a/quickstep/res/values/dimens.xml +++ b/quickstep/res/values/dimens.xml @@ -99,6 +99,13 @@ 24dp 18dp + + 40dp + 28dp + 80dp + 52dp + 24dp + 8dp 64dp diff --git a/quickstep/res/values/strings.xml b/quickstep/res/values/strings.xml index a0f1638c8a..7ada496c40 100644 --- a/quickstep/res/values/strings.xml +++ b/quickstep/res/values/strings.xml @@ -177,6 +177,15 @@ Tutorial %1$d/%2$d + + All set! + + Swipe up to go home + + You\u2019re ready to start using your phone + + Navigation settings for accessibility + Share diff --git a/quickstep/res/values/styles.xml b/quickstep/res/values/styles.xml index 7c7d20a20a..0a8ecb8bde 100644 --- a/quickstep/res/values/styles.xml +++ b/quickstep/res/values/styles.xml @@ -59,7 +59,7 @@ parent="TextAppearance.GestureTutorial"> start ?android:attr/textColorPrimary - google-sans + google-sans-text 0.03 18sp 24sp @@ -99,6 +99,11 @@ @color/gesture_tutorial_primary_color + + - + + diff --git a/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java b/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java index 01616d45ec..b3374f33b9 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java +++ b/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java @@ -22,12 +22,12 @@ import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_FA import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_MODAL; import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_SCALE; import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_TRANSLATE_X; -import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_TRANSLATE_Y; import static com.android.launcher3.states.StateAnimationConfig.SKIP_OVERVIEW; import static com.android.quickstep.views.RecentsView.ADJACENT_PAGE_OFFSET; import static com.android.quickstep.views.RecentsView.RECENTS_GRID_PROGRESS; import static com.android.quickstep.views.RecentsView.RECENTS_SCALE_PROPERTY; -import static com.android.quickstep.views.RecentsView.TASK_PRIMARY_TRANSLATION; +import static com.android.quickstep.views.RecentsView.TASK_PRIMARY_SPLIT_TRANSLATION; +import static com.android.quickstep.views.RecentsView.TASK_SECONDARY_SPLIT_TRANSLATION; import static com.android.quickstep.views.RecentsView.TASK_SECONDARY_TRANSLATION; import android.util.FloatProperty; @@ -97,10 +97,10 @@ public abstract class BaseRecentsViewStateController PagedOrientationHandler orientationHandler = ((RecentsView) mLauncher.getOverviewPanel()).getPagedOrientationHandler(); FloatProperty taskViewsFloat = orientationHandler.getSplitSelectTaskOffset( - TASK_PRIMARY_TRANSLATION, TASK_SECONDARY_TRANSLATION, mLauncher.getDeviceProfile()); + TASK_PRIMARY_SPLIT_TRANSLATION, TASK_SECONDARY_SPLIT_TRANSLATION, + mLauncher.getDeviceProfile()); setter.setFloat(mRecentsView, taskViewsFloat, - toState.getOverviewSecondaryTranslation(mLauncher), - config.getInterpolator(ANIM_OVERVIEW_TRANSLATE_Y, LINEAR)); + toState.getOverviewSecondaryTranslation(mLauncher), LINEAR); setter.setFloat(mRecentsView, getContentAlphaProperty(), toState.overviewUi ? 1 : 0, config.getInterpolator(ANIM_OVERVIEW_FADE, AGGRESSIVE_EASE_IN_OUT)); diff --git a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java index 01d51f82cb..3d33e57a36 100644 --- a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java +++ b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java @@ -25,6 +25,7 @@ import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITIO import android.animation.AnimatorSet; import android.app.ActivityOptions; import android.content.res.Resources; +import android.graphics.Rect; import android.os.Handler; import android.os.IBinder; import android.os.Looper; @@ -64,6 +65,7 @@ public class SplitSelectStateController { private final SystemUiProxy mSystemUiProxy; private TaskView mInitialTaskView; private SplitPositionOption mInitialPosition; + private Rect mInitialBounds; private final Handler mHandler; public SplitSelectStateController(Handler handler, SystemUiProxy systemUiProxy) { @@ -74,9 +76,11 @@ public class SplitSelectStateController { /** * To be called after first task selected */ - public void setInitialTaskSelect(TaskView taskView, SplitPositionOption positionOption) { + public void setInitialTaskSelect(TaskView taskView, SplitPositionOption positionOption, + Rect initialBounds) { mInitialTaskView = taskView; mInitialPosition = positionOption; + mInitialBounds = initialBounds; } /** @@ -220,9 +224,14 @@ public class SplitSelectStateController { public void resetState() { mInitialTaskView = null; mInitialPosition = null; + mInitialBounds = null; } public boolean isSplitSelectActive() { return mInitialTaskView != null; } + + public Rect getInitialBounds() { + return mInitialBounds; + } } diff --git a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java index f5a8ff8170..2c5f66170b 100644 --- a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java +++ b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java @@ -245,8 +245,8 @@ public class LauncherRecentsView extends RecentsView TASK_PRIMARY_TRANSLATION = - new FloatProperty("taskPrimaryTranslation") { + public static final FloatProperty TASK_PRIMARY_SPLIT_TRANSLATION = + new FloatProperty("taskPrimarySplitTranslation") { @Override public void setValue(RecentsView recentsView, float v) { - recentsView.setTaskViewsPrimaryTranslation(v); + recentsView.setTaskViewsPrimarySplitTranslation(v); } @Override public Float get(RecentsView recentsView) { - return recentsView.mTaskViewsPrimaryTranslation; + return recentsView.mTaskViewsPrimarySplitTranslation; + } + }; + + public static final FloatProperty TASK_SECONDARY_SPLIT_TRANSLATION = + new FloatProperty("taskSecondarySplitTranslation") { + @Override + public void setValue(RecentsView recentsView, float v) { + recentsView.setTaskViewsSecondarySplitTranslation(v); + } + + @Override + public Float get(RecentsView recentsView) { + return recentsView.mTaskViewsSecondarySplitTranslation; } }; @@ -279,7 +292,6 @@ public abstract class RecentsView secondaryViewTranslate = - taskView.getSecondaryDissmissTranslationProperty(); - int secondaryTaskDimension = mOrientationHandler.getSecondaryDimension(taskView); - int verticalFactor = mOrientationHandler.getSecondaryTranslationDirectionFactor(); + SplitSelectStateController splitController = mSplitPlaceholderView.getSplitController(); ResourceProvider rp = DynamicResource.provider(mActivity); SpringProperty sp = new SpringProperty(SpringProperty.FLAG_CAN_SPRING_ON_START) .setDampingRatio(rp.getFloat(R.dimen.dismiss_task_trans_y_damping_ratio)) .setStiffness(rp.getFloat(R.dimen.dismiss_task_trans_y_stiffness)); + FloatProperty dismissingTaskViewTranslate = + taskView.getSecondaryDissmissTranslationProperty();; + // TODO(b/186800707) translate entire grid size distance + int translateDistance = mOrientationHandler.getSecondaryDimension(taskView); + int positiveNegativeFactor = mOrientationHandler.getSecondaryTranslationDirectionFactor(); + if (splitController.isSplitSelectActive()) { + // Have the task translate towards whatever side was just pinned + int dir = mOrientationHandler.getSplitTaskViewDismissDirection(splitController + .getActiveSplitPositionOption(), mActivity.getDeviceProfile()); + switch (dir) { + case PagedOrientationHandler.SPLIT_TRANSLATE_SECONDARY_NEGATIVE: + dismissingTaskViewTranslate = taskView + .getSecondaryDissmissTranslationProperty(); + positiveNegativeFactor = -1; + break; - anim.add(ObjectAnimator.ofFloat(taskView, secondaryViewTranslate, - verticalFactor * secondaryTaskDimension).setDuration(duration), LINEAR, sp); + case PagedOrientationHandler.SPLIT_TRANSLATE_PRIMARY_POSITIVE: + dismissingTaskViewTranslate = taskView.getPrimaryDismissTranslationProperty(); + positiveNegativeFactor = 1; + break; + + case PagedOrientationHandler.SPLIT_TRANSLATE_PRIMARY_NEGATIVE: + dismissingTaskViewTranslate = taskView.getPrimaryDismissTranslationProperty(); + positiveNegativeFactor = -1; + break; + default: + throw new IllegalStateException("Invalid split task translation: " + dir); + } + } + anim.add(ObjectAnimator.ofFloat(taskView, dismissingTaskViewTranslate, + positiveNegativeFactor * translateDistance).setDuration(duration), LINEAR, sp); if (LIVE_TILE.get() && taskView.isRunningTask()) { anim.addOnFrameCallback(() -> { @@ -2206,18 +2255,6 @@ public abstract class RecentsView view.getVisibility() != GONE && view != mSplitHiddenTaskView); - // x is correct, y is before tasks move up - int[] locationOnScreen = mSplitHiddenTaskView.getLocationOnScreen(); int[] newScroll = new int[getChildCount()]; getPageScrolls(newScroll, false, SIMPLE_SCROLL_LOGIC); @@ -2842,20 +2888,42 @@ public abstract class RecentsView= 0; i--) { View child = getChildAt(i); if (child == mSplitHiddenTaskView) { + TaskView taskView = (TaskView) child; - int left = newScroll[i] + getPaddingStart(); - int topMargin = mActivity.getDeviceProfile().overviewTaskThumbnailTopMarginPx; - int top = -mSplitHiddenTaskView.getHeight() - locationOnScreen[1]; - mSplitHiddenTaskView.layout(left, top, - left + mSplitHiddenTaskView.getWidth(), - top + mSplitHiddenTaskView.getHeight()); - pendingAnim.add(ObjectAnimator.ofFloat(mSplitHiddenTaskView, TRANSLATION_Y, - -top + mSplitPlaceholderView.getHeight() - topMargin)); + int dir = mOrientationHandler.getSplitTaskViewDismissDirection(splitOption, + mActivity.getDeviceProfile()); + FloatProperty dismissingTaskViewTranslate; + Rect hiddenBounds = new Rect(taskView.getLeft(), taskView.getTop(), + taskView.getRight(), taskView.getBottom()); + int distanceDelta = 0; + if (dir == PagedOrientationHandler.SPLIT_TRANSLATE_SECONDARY_NEGATIVE) { + dismissingTaskViewTranslate = taskView + .getSecondaryDissmissTranslationProperty(); + distanceDelta = initialBounds.top - hiddenBounds.top; + taskView.layout(initialBounds.left, hiddenBounds.top, initialBounds.right, + hiddenBounds.bottom); + } else { + dismissingTaskViewTranslate = taskView + .getPrimaryDismissTranslationProperty(); + distanceDelta = initialBounds.left - hiddenBounds.left; + taskView.layout(hiddenBounds.left, initialBounds.top, hiddenBounds.right, + initialBounds.bottom); + if (dir == PagedOrientationHandler.SPLIT_TRANSLATE_PRIMARY_POSITIVE) { + distanceDelta *= -1; + } + } + pendingAnim.add(ObjectAnimator.ofFloat(mSplitHiddenTaskView, + dismissingTaskViewTranslate, + distanceDelta)); pendingAnim.add(ObjectAnimator.ofFloat(mSplitHiddenTaskView, ALPHA, 1)); } else { // If insertion is on last index (furthest from clear all), we directly add the view // else we translate all views to the right of insertion index further right, // ignore views to left + if (showAsGrid()) { + // TODO(b/186800707) handle more elegantly for grid + continue; + } int scrollDiff = newScroll[i] - oldScroll[i]; if (scrollDiff != 0) { FloatProperty translationProperty = child instanceof TaskView @@ -2881,6 +2949,12 @@ public abstract class RecentsView SPLIT_SELECT_TRANSLATION_X = + new FloatProperty("splitSelectTranslationX") { + @Override + public void setValue(TaskView taskView, float v) { + taskView.setSplitSelectTranslationX(v); + } + + @Override + public Float get(TaskView taskView) { + return taskView.mSplitSelectTranslationX; + } + }; + + private static final FloatProperty SPLIT_SELECT_TRANSLATION_Y = + new FloatProperty("splitSelectTranslationY") { + @Override + public void setValue(TaskView taskView, float v) { + taskView.setSplitSelectTranslationY(v); + } + + @Override + public Float get(TaskView taskView) { + return taskView.mSplitSelectTranslationY; + } + }; + private static final FloatProperty DISMISS_TRANSLATION_X = new FloatProperty("dismissTranslationX") { @Override @@ -345,6 +371,9 @@ public class TaskView extends FrameLayout implements Reusable { // The following grid translations scales with mGridProgress. private float mGridTranslationX; private float mGridTranslationY; + // Used when in SplitScreenSelectState + private float mSplitSelectTranslationY; + private float mSplitSelectTranslationX; private ObjectAnimator mIconAndDimAnimator; private float mIconScaleAnimStartProgress = 0; @@ -825,8 +854,10 @@ public class TaskView extends FrameLayout implements Reusable { protected void resetViewTransforms() { // fullscreenTranslation and accumulatedTranslation should not be reset, as // resetViewTransforms is called during Quickswitch scrolling. - mDismissTranslationX = mTaskOffsetTranslationX = mTaskResistanceTranslationX = 0f; - mDismissTranslationY = mTaskOffsetTranslationY = mTaskResistanceTranslationY = 0f; + mDismissTranslationX = mTaskOffsetTranslationX = mTaskResistanceTranslationX = + mSplitSelectTranslationX = 0f; + mDismissTranslationY = mTaskOffsetTranslationY = mTaskResistanceTranslationY = + mSplitSelectTranslationY = 0f; applyTranslationX(); applyTranslationY(); setTranslationZ(0); @@ -956,6 +987,15 @@ public class TaskView extends FrameLayout implements Reusable { setScaleY(scale); } + private void setSplitSelectTranslationX(float x) { + mSplitSelectTranslationX = x; + applyTranslationX(); + } + + private void setSplitSelectTranslationY(float y) { + mSplitSelectTranslationY = y; + applyTranslationY(); + } private void setDismissTranslationX(float x) { mDismissTranslationX = x; applyTranslationX(); @@ -1056,12 +1096,12 @@ public class TaskView extends FrameLayout implements Reusable { private void applyTranslationX() { setTranslationX(mDismissTranslationX + mTaskOffsetTranslationX + mTaskResistanceTranslationX - + getPersistentTranslationX()); + + mSplitSelectTranslationX + getPersistentTranslationX()); } private void applyTranslationY() { setTranslationY(mDismissTranslationY + mTaskOffsetTranslationY + mTaskResistanceTranslationY - + getPersistentTranslationY()); + + mSplitSelectTranslationY + getPersistentTranslationY()); } /** @@ -1085,6 +1125,16 @@ public class TaskView extends FrameLayout implements Reusable { + getGridTrans(mGridTranslationY); } + public FloatProperty getPrimarySplitTranslationProperty() { + return getPagedOrientationHandler().getPrimaryValue( + SPLIT_SELECT_TRANSLATION_X, SPLIT_SELECT_TRANSLATION_Y); + } + + public FloatProperty getSecondarySplitTranslationProperty() { + return getPagedOrientationHandler().getSecondaryValue( + SPLIT_SELECT_TRANSLATION_X, SPLIT_SELECT_TRANSLATION_Y); + } + public FloatProperty getPrimaryDismissTranslationProperty() { return getPagedOrientationHandler().getPrimaryValue( DISMISS_TRANSLATION_X, DISMISS_TRANSLATION_Y); diff --git a/src/com/android/launcher3/touch/LandscapePagedViewHandler.java b/src/com/android/launcher3/touch/LandscapePagedViewHandler.java index 2fd5efc3f6..44e55e102c 100644 --- a/src/com/android/launcher3/touch/LandscapePagedViewHandler.java +++ b/src/com/android/launcher3/touch/LandscapePagedViewHandler.java @@ -159,6 +159,19 @@ public class LandscapePagedViewHandler implements PagedOrientationHandler { return VIEW_TRANSLATE_X; } + @Override + public int getSplitTaskViewDismissDirection(SplitPositionOption splitPosition, + DeviceProfile dp) { + // Don't use device profile here because we know we're in fake landscape, only split option + // available is top/left + if (splitPosition.mStagePosition == STAGE_POSITION_TOP_OR_LEFT) { + // Top (visually left) side + return SPLIT_TRANSLATE_PRIMARY_NEGATIVE; + } + throw new IllegalStateException("Invalid split stage position: " + + splitPosition.mStagePosition); + } + @Override public int getPrimaryScroll(View view) { return view.getScrollY(); diff --git a/src/com/android/launcher3/touch/PagedOrientationHandler.java b/src/com/android/launcher3/touch/PagedOrientationHandler.java index 6c2f17ee34..d8e5a485fd 100644 --- a/src/com/android/launcher3/touch/PagedOrientationHandler.java +++ b/src/com/android/launcher3/touch/PagedOrientationHandler.java @@ -42,6 +42,10 @@ import java.util.List; */ public interface PagedOrientationHandler { + int SPLIT_TRANSLATE_PRIMARY_POSITIVE = 0; + int SPLIT_TRANSLATE_PRIMARY_NEGATIVE = 1; + int SPLIT_TRANSLATE_SECONDARY_NEGATIVE = 2; + PagedOrientationHandler PORTRAIT = new PortraitPagedViewHandler(); PagedOrientationHandler LANDSCAPE = new LandscapePagedViewHandler(); PagedOrientationHandler SEASCAPE = new SeascapePagedViewHandler(); @@ -71,6 +75,13 @@ public interface PagedOrientationHandler { int getSecondaryDimension(View view); FloatProperty getPrimaryViewTranslate(); FloatProperty getSecondaryViewTranslate(); + + /** + * @param splitPosition The position where the view to be split will go + * @return {@link #SPLIT_TRANSLATE_*} constants to indicate which direction the + * dismissal should happen + */ + int getSplitTaskViewDismissDirection(SplitPositionOption splitPosition, DeviceProfile dp); int getPrimaryScroll(View view); float getPrimaryScale(View view); int getChildStart(View view); diff --git a/src/com/android/launcher3/touch/PortraitPagedViewHandler.java b/src/com/android/launcher3/touch/PortraitPagedViewHandler.java index f6a6448602..01897d727d 100644 --- a/src/com/android/launcher3/touch/PortraitPagedViewHandler.java +++ b/src/com/android/launcher3/touch/PortraitPagedViewHandler.java @@ -155,6 +155,25 @@ public class PortraitPagedViewHandler implements PagedOrientationHandler { return VIEW_TRANSLATE_Y; } + @Override + public int getSplitTaskViewDismissDirection(SplitPositionOption splitPosition, + DeviceProfile dp) { + if (splitPosition.mStagePosition == STAGE_POSITION_TOP_OR_LEFT) { + if (dp.isLandscape) { + // Left side + return SPLIT_TRANSLATE_PRIMARY_NEGATIVE; + } else { + // Top side + return SPLIT_TRANSLATE_SECONDARY_NEGATIVE; + } + } else if (splitPosition.mStagePosition == STAGE_POSITION_BOTTOM_OR_RIGHT) { + // We don't have a bottom option, so should be right + return SPLIT_TRANSLATE_PRIMARY_POSITIVE; + } + throw new IllegalStateException("Invalid split stage position: " + + splitPosition.mStagePosition); + } + @Override public int getPrimaryScroll(View view) { return view.getScrollX();