From 170306d54a79a0390727636563dd22ca742dc09e Mon Sep 17 00:00:00 2001 From: Alex Chau Date: Thu, 28 Mar 2024 21:10:12 +0000 Subject: [PATCH 1/5] Update Split button visibility based on DeviceProfile change - Updating Split button visibility in notifyPageSwitchListener() is sometimes too late and causes OverviewActions failed to re-center after removing Split button - Instead, update Split button visibility based on DeviceProfile change in updateDimension(), which is the ultimate source of information impacting button visibility Fix: 321291049 Test: Clear all tasks, fold, launch app, swipe up to Overivew Flag: None Change-Id: If518cb02429011fedfb8df3dd05dd7ab180d849a --- .../com/android/quickstep/views/OverviewActionsView.java | 9 +++++---- .../src/com/android/quickstep/views/RecentsView.java | 2 -- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/quickstep/src/com/android/quickstep/views/OverviewActionsView.java b/quickstep/src/com/android/quickstep/views/OverviewActionsView.java index 384a8d8656..882ccec9e7 100644 --- a/quickstep/src/com/android/quickstep/views/OverviewActionsView.java +++ b/quickstep/src/com/android/quickstep/views/OverviewActionsView.java @@ -243,13 +243,13 @@ public class OverviewActionsView extends FrameLayo /** * Updates a batch of flags to hide and show actions buttons for tablet/non tablet case. - * @param isSmallScreen True if the current display is a small screen. */ - public void updateForSmallScreen(boolean isSmallScreen) { + private void updateForIsTablet() { + assert mDp != null; // Update flags to see if split button should be hidden. - updateSplitButtonHiddenFlags(FLAG_SMALL_SCREEN_HIDE_SPLIT, isSmallScreen); + updateSplitButtonHiddenFlags(FLAG_SMALL_SCREEN_HIDE_SPLIT, !mDp.isTablet); // Update flags to see if save app pair button should be hidden. - updateAppPairButtonHiddenFlags(FLAG_SMALL_SCREEN_HIDE_APP_PAIR, isSmallScreen); + updateAppPairButtonHiddenFlags(FLAG_SMALL_SCREEN_HIDE_APP_PAIR, !mDp.isTablet); } /** @@ -386,6 +386,7 @@ public class OverviewActionsView extends FrameLayo mDp = dp; mTaskSize.set(taskSize); updateVerticalMargin(DisplayController.getNavigationMode(getContext())); + updateForIsTablet(); requestLayout(); diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java index 2aa16a948a..e57af3a85a 100644 --- a/quickstep/src/com/android/quickstep/views/RecentsView.java +++ b/quickstep/src/com/android/quickstep/views/RecentsView.java @@ -3962,8 +3962,6 @@ public abstract class RecentsView Date: Fri, 29 Mar 2024 16:08:43 -0700 Subject: [PATCH 2/5] Fix Taskbar Background Visibility After Entering IME then Overview. Fixed issue whereby taskbar background disappears as expected when the IME switcher is present, but does not appear again if the overview button is pressed after this state. Flag: NONE Test: Manually tested in Felix Landscape mode. Bug: 297472865 Change-Id: If1074b28870c794db8a87dd6cd59f9656dc7c15d --- .../com/android/launcher3/taskbar/TaskbarStashController.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java index 3d584642b9..ba8a0741a7 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java @@ -598,7 +598,8 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba ? stashTranslation : 0) .setDuration(duration)); mAnimator.play(mTaskbarImeBgAlpha.animateToValue( - hasAnyFlag(FLAG_STASHED_IN_APP_IME) ? 0 : 1).setDuration(duration)); + (hasAnyFlag(FLAG_STASHED_IN_APP_IME) && isStashed) ? 0 : 1).setDuration( + duration)); mAnimator.addListener(AnimatorListeners.forEndCallback(() -> { mAnimator = null; mIsStashed = isStashed; From 2b724ec00d7654a2de0737950f6ef88ac5575f9f Mon Sep 17 00:00:00 2001 From: Sebastian Franco Date: Tue, 2 Apr 2024 11:42:17 -0700 Subject: [PATCH 3/5] Adding screen record to testEmptyPageDoesNotGetRemovedIfPagePairIsNotEmpty Bug: 329935119 Test: NA Flag: NA Change-Id: I86c0620d6207b09f04c8038932ed34f4444a6626 --- .../launcher3/ui/workspace/TaplTwoPanelWorkspaceTest.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/src/com/android/launcher3/ui/workspace/TaplTwoPanelWorkspaceTest.java b/tests/src/com/android/launcher3/ui/workspace/TaplTwoPanelWorkspaceTest.java index 43fc8ffa3f..913dfa2285 100644 --- a/tests/src/com/android/launcher3/ui/workspace/TaplTwoPanelWorkspaceTest.java +++ b/tests/src/com/android/launcher3/ui/workspace/TaplTwoPanelWorkspaceTest.java @@ -37,6 +37,7 @@ import com.android.launcher3.ui.AbstractLauncherUiTest; import com.android.launcher3.ui.PortraitLandscapeRunner.PortraitLandscape; import com.android.launcher3.util.LauncherLayoutBuilder; import com.android.launcher3.util.TestUtil; +import com.android.launcher3.util.rule.ScreenRecordRule; import org.junit.After; import org.junit.Before; @@ -240,6 +241,7 @@ public class TaplTwoPanelWorkspaceTest extends AbstractLauncherUiTest { }); } + @ScreenRecordRule.ScreenRecord // b/329935119 @Test @PortraitLandscape public void testEmptyPageDoesNotGetRemovedIfPagePairIsNotEmpty() { From fcbef122e60dd397492ea210a8075715ad60e71e Mon Sep 17 00:00:00 2001 From: Jeremy Sim Date: Fri, 22 Mar 2024 16:05:09 -0700 Subject: [PATCH 4/5] Refactor how app pair icons draw This changes (and cleans up) the way app pair icons are composed. Previously, the background and 2 icons were drawn individually and separately onto the canvas. Now, they are composed into a combined drawable first. This also allows the full icon drawable to be requested by external functions (which will be needed for display app pairs in folder previews). Bug: 315731527 Flag: ACONFIG com.android.wm.shell.enable_app_pairs TRUNKFOOD Test: Visually confirmed that app pairs loooks the same in all scenarios: rotation, disabled, themed, taskbar, pinned taskbar. Screenshot test to follow. Change-Id: I7242e0c525ef578a54a06fb9137fcfc42c6f0e86 (cherry picked from commit b37faec28713934ec5bea41935a6bf83c29c011c) Merged-In: I7242e0c525ef578a54a06fb9137fcfc42c6f0e86 --- .../launcher3/taskbar/TaskbarView.java | 3 +- src/com/android/launcher3/BubbleTextView.java | 7 +- .../launcher3/apppairs/AppPairIcon.java | 67 ++++-- .../apppairs/AppPairIconBackground.java | 166 -------------- .../apppairs/AppPairIconDrawable.java | 208 ++++++++++++++++++ .../apppairs/AppPairIconDrawingParams.kt | 98 +++++++++ .../launcher3/apppairs/AppPairIconGraphic.kt | 193 ++++++---------- .../graphics/LauncherPreviewRenderer.java | 8 +- .../android/launcher3/util/ItemInflater.kt | 3 +- 9 files changed, 430 insertions(+), 323 deletions(-) create mode 100644 src/com/android/launcher3/apppairs/AppPairIconDrawable.java create mode 100644 src/com/android/launcher3/apppairs/AppPairIconDrawingParams.kt diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java index 367bf6cfb2..c81bf7aacc 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java @@ -354,7 +354,8 @@ public class TaskbarView extends FrameLayout implements FolderIcon.FolderIconPar break; case ITEM_TYPE_APP_PAIR: hotseatView = AppPairIcon.inflateIcon( - expectedLayoutResId, mActivityContext, this, folderInfo); + expectedLayoutResId, mActivityContext, this, folderInfo, + BubbleTextView.DISPLAY_TASKBAR); ((AppPairIcon) hotseatView).setTextVisible(false); break; default: diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java index 3ae1ce117b..b9daf28e12 100644 --- a/src/com/android/launcher3/BubbleTextView.java +++ b/src/com/android/launcher3/BubbleTextView.java @@ -58,7 +58,6 @@ import androidx.annotation.UiThread; import androidx.annotation.VisibleForTesting; import com.android.launcher3.accessibility.BaseAccessibilityDelegate; -import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.dot.DotInfo; import com.android.launcher3.dragndrop.DragOptions.PreDragCondition; import com.android.launcher3.dragndrop.DraggableView; @@ -96,10 +95,10 @@ import java.util.Locale; public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver, IconLabelDotView, DraggableView, Reorderable { - private static final int DISPLAY_WORKSPACE = 0; + public static final int DISPLAY_WORKSPACE = 0; public static final int DISPLAY_ALL_APPS = 1; - private static final int DISPLAY_FOLDER = 2; - protected static final int DISPLAY_TASKBAR = 5; + public static final int DISPLAY_FOLDER = 2; + public static final int DISPLAY_TASKBAR = 5; public static final int DISPLAY_SEARCH_RESULT = 6; public static final int DISPLAY_SEARCH_RESULT_SMALL = 7; public static final int DISPLAY_PREDICTION_ROW = 8; diff --git a/src/com/android/launcher3/apppairs/AppPairIcon.java b/src/com/android/launcher3/apppairs/AppPairIcon.java index a3800f7c44..12fc298408 100644 --- a/src/com/android/launcher3/apppairs/AppPairIcon.java +++ b/src/com/android/launcher3/apppairs/AppPairIcon.java @@ -16,13 +16,14 @@ package com.android.launcher3.apppairs; +import static com.android.launcher3.BubbleTextView.DISPLAY_FOLDER; + import android.content.Context; import android.graphics.Canvas; +import android.graphics.Paint; import android.graphics.Rect; import android.util.AttributeSet; -import android.util.Log; import android.view.LayoutInflater; -import android.view.View; import android.view.ViewGroup; import android.widget.FrameLayout; @@ -38,7 +39,6 @@ import com.android.launcher3.model.data.WorkspaceItemInfo; import com.android.launcher3.util.MultiTranslateDelegate; import com.android.launcher3.views.ActivityContext; -import java.util.Collections; import java.util.Comparator; import java.util.function.Predicate; @@ -62,6 +62,9 @@ public class AppPairIcon extends FrameLayout implements DraggableView, Reorderab private BubbleTextView mAppPairName; // The underlying ItemInfo that stores info about the app pair members, etc. private FolderInfo mInfo; + // The containing element that holds this icon: workspace, taskbar, folder, etc. Affects certain + // aspects of how the icon is drawn. + private int mContainer; // Required for Reorderable -- handles translation and bouncing movements private final MultiTranslateDelegate mTranslateDelegate = new MultiTranslateDelegate(this); @@ -79,7 +82,7 @@ public class AppPairIcon extends FrameLayout implements DraggableView, Reorderab * Builds an AppPairIcon to be added to the Launcher. */ public static AppPairIcon inflateIcon(int resId, ActivityContext activity, - @Nullable ViewGroup group, FolderInfo appPairInfo) { + @Nullable ViewGroup group, FolderInfo appPairInfo, int container) { DeviceProfile grid = activity.getDeviceProfile(); LayoutInflater inflater = (group != null) ? LayoutInflater.from(group.getContext()) @@ -87,30 +90,32 @@ public class AppPairIcon extends FrameLayout implements DraggableView, Reorderab AppPairIcon icon = (AppPairIcon) inflater.inflate(resId, group, false); // Sort contents, so that left-hand app comes first - Collections.sort(appPairInfo.contents, Comparator.comparingInt(a -> a.rank)); + appPairInfo.contents.sort(Comparator.comparingInt(a -> a.rank)); - icon.setClipToPadding(false); icon.setTag(appPairInfo); icon.setOnClickListener(activity.getItemOnClickListener()); icon.mInfo = appPairInfo; + icon.mContainer = container; - if (icon.mInfo.contents.size() != 2) { - Log.wtf(TAG, "AppPair contents not 2, size: " + icon.mInfo.contents.size()); - return icon; - } - - icon.checkScreenSize(); + icon.checkDisabledState(); // Set up icon drawable area icon.mIconGraphic = icon.findViewById(R.id.app_pair_icon_graphic); - icon.mIconGraphic.init(activity, icon); + icon.mIconGraphic.init(icon, container); // Set up app pair title icon.mAppPairName = icon.findViewById(R.id.app_pair_icon_name); - icon.mAppPairName.setCompoundDrawablePadding(0); FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) icon.mAppPairName.getLayoutParams(); - lp.topMargin = grid.iconSizePx + grid.iconDrawablePaddingPx; + // Shift the title text down to leave room for the icon graphic. Since the icon graphic is + // a separate element (and not set as a CompoundDrawable on the BubbleTextView), we need to + // shift the text down manually. + lp.topMargin = container == DISPLAY_FOLDER + ? grid.folderChildIconSizePx + grid.folderChildDrawablePaddingPx + : grid.iconSizePx + grid.iconDrawablePaddingPx; + // For some reason, app icons have setIncludeFontPadding(false) inside folders, so we set it + // here to match that. + icon.mAppPairName.setIncludeFontPadding(container != DISPLAY_FOLDER); icon.mAppPairName.setText(appPairInfo.title); // Set up accessibility @@ -174,7 +179,11 @@ public class AppPairIcon extends FrameLayout implements DraggableView, Reorderab return mInfo; } - public View getIconDrawableArea() { + public BubbleTextView getTitleTextView() { + return mAppPairName; + } + + public AppPairIconGraphic getIconDrawableArea() { return mIconGraphic; } @@ -194,12 +203,14 @@ public class AppPairIcon extends FrameLayout implements DraggableView, Reorderab * {@link AppPairIconGraphic#dispatchDraw(Canvas)} or clicked on * {@link com.android.launcher3.touch.ItemClickHandler#onClickAppPairIcon(View)} */ - public void checkScreenSize() { + public void checkDisabledState() { DeviceProfile dp = ActivityContext.lookupContext(getContext()).getDeviceProfile(); // If user is on a small screen, we can't launch if either of the apps is non-resizeable mIsLaunchableAtScreenSize = dp.isTablet || getInfo().contents.stream().noneMatch( wii -> wii.hasStatusFlag(WorkspaceItemInfo.FLAG_NON_RESIZEABLE)); + // Invalidate to update icons + mIconGraphic.redraw(); } /** @@ -209,8 +220,26 @@ public class AppPairIcon extends FrameLayout implements DraggableView, Reorderab // If either of the app pair icons return true on the predicate (i.e. in the list of // updated apps), redraw the icon graphic (icon background and both icons). if (getInfo().contents.stream().anyMatch(itemCheck)) { - checkScreenSize(); - mIconGraphic.invalidate(); + checkDisabledState(); } } + + /** + * Inside folders, icons are vertically centered in their rows. See + * {@link BubbleTextView#onMeasure(int, int)} for comparison. + */ + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + if (mContainer == DISPLAY_FOLDER) { + int height = MeasureSpec.getSize(heightMeasureSpec); + ActivityContext activity = ActivityContext.lookupContext(getContext()); + Paint.FontMetrics fm = mAppPairName.getPaint().getFontMetrics(); + int cellHeightPx = activity.getDeviceProfile().folderChildIconSizePx + + activity.getDeviceProfile().folderChildDrawablePaddingPx + + (int) Math.ceil(fm.bottom - fm.top); + setPadding(getPaddingLeft(), (height - cellHeightPx) / 2, getPaddingRight(), + getPaddingBottom()); + } + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + } } diff --git a/src/com/android/launcher3/apppairs/AppPairIconBackground.java b/src/com/android/launcher3/apppairs/AppPairIconBackground.java index b5011f126c..8b13789179 100644 --- a/src/com/android/launcher3/apppairs/AppPairIconBackground.java +++ b/src/com/android/launcher3/apppairs/AppPairIconBackground.java @@ -1,167 +1 @@ -/* - * Copyright (C) 2023 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.apppairs; - -import android.content.Context; -import android.content.res.TypedArray; -import android.graphics.Canvas; -import android.graphics.ColorFilter; -import android.graphics.Paint; -import android.graphics.PixelFormat; -import android.graphics.RectF; -import android.graphics.drawable.Drawable; -import android.os.Build; - -import com.android.launcher3.R; - -/** - * A Drawable for the background behind the twin app icons (looks like two rectangles). - */ -class AppPairIconBackground extends Drawable { - // The underlying view that we are drawing this background on. - private final AppPairIconGraphic icon; - private final Paint mBackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG); - - /** - * Null values to use with - * {@link Canvas#drawDoubleRoundRect(RectF, float[], RectF, float[], Paint)}, since there - * doesn't seem to be any other API for drawing rectangles with 4 different corner radii. - */ - private static final RectF EMPTY_RECT = new RectF(); - private static final float[] ARRAY_OF_ZEROES = new float[8]; - - AppPairIconBackground(Context context, AppPairIconGraphic iconGraphic) { - icon = iconGraphic; - // Set up background paint color - TypedArray ta = context.getTheme().obtainStyledAttributes(R.styleable.FolderIconPreview); - mBackgroundPaint.setStyle(Paint.Style.FILL); - mBackgroundPaint.setColor( - ta.getColor(R.styleable.FolderIconPreview_folderPreviewColor, 0)); - ta.recycle(); - } - - @Override - public void draw(Canvas canvas) { - if (icon.isLeftRightSplit()) { - drawLeftRightSplit(canvas); - } else { - drawTopBottomSplit(canvas); - } - } - - /** - * When device is in landscape, we draw the rectangles with a left-right split. - */ - private void drawLeftRightSplit(Canvas canvas) { - // Get the bounds where we will draw the background image - int width = getBounds().width(); - int height = getBounds().height(); - - // The left half of the background image, excluding center channel - RectF leftSide = new RectF( - 0, - 0, - (width / 2f) - (icon.getCenterChannelSize() / 2f), - height - ); - // The right half of the background image, excluding center channel - RectF rightSide = new RectF( - (width / 2f) + (icon.getCenterChannelSize() / 2f), - 0, - width, - height - ); - - drawCustomRoundedRect(canvas, leftSide, new float[]{ - icon.getBigRadius(), icon.getBigRadius(), - icon.getSmallRadius(), icon.getSmallRadius(), - icon.getSmallRadius(), icon.getSmallRadius(), - icon.getBigRadius(), icon.getBigRadius()}); - drawCustomRoundedRect(canvas, rightSide, new float[]{ - icon.getSmallRadius(), icon.getSmallRadius(), - icon.getBigRadius(), icon.getBigRadius(), - icon.getBigRadius(), icon.getBigRadius(), - icon.getSmallRadius(), icon.getSmallRadius()}); - } - - /** - * When device is in portrait, we draw the rectangles with a top-bottom split. - */ - private void drawTopBottomSplit(Canvas canvas) { - // Get the bounds where we will draw the background image - int width = getBounds().width(); - int height = getBounds().height(); - - // The top half of the background image, excluding center channel - RectF topSide = new RectF( - 0, - 0, - width, - (height / 2f) - (icon.getCenterChannelSize() / 2f) - ); - // The bottom half of the background image, excluding center channel - RectF bottomSide = new RectF( - 0, - (height / 2f) + (icon.getCenterChannelSize() / 2f), - width, - height - ); - - drawCustomRoundedRect(canvas, topSide, new float[]{ - icon.getBigRadius(), icon.getBigRadius(), - icon.getBigRadius(), icon.getBigRadius(), - icon.getSmallRadius(), icon.getSmallRadius(), - icon.getSmallRadius(), icon.getSmallRadius()}); - drawCustomRoundedRect(canvas, bottomSide, new float[]{ - icon.getSmallRadius(), icon.getSmallRadius(), - icon.getSmallRadius(), icon.getSmallRadius(), - icon.getBigRadius(), icon.getBigRadius(), - icon.getBigRadius(), icon.getBigRadius()}); - } - - /** - * Draws a rectangle with custom rounded corners. - * @param c The Canvas to draw on. - * @param rect The bounds of the rectangle. - * @param radii An array of 8 radii for the corners: top left x, top left y, top right x, top - * right y, bottom right x, and so on. - */ - private void drawCustomRoundedRect(Canvas c, RectF rect, float[] radii) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { - // Canvas.drawDoubleRoundRect is supported from Q onward - c.drawDoubleRoundRect(rect, radii, EMPTY_RECT, ARRAY_OF_ZEROES, mBackgroundPaint); - } else { - // Fallback rectangle with uniform rounded corners - c.drawRoundRect(rect, icon.getBigRadius(), icon.getBigRadius(), mBackgroundPaint); - } - } - - @Override - public int getOpacity() { - return PixelFormat.OPAQUE; - } - - @Override - public void setAlpha(int i) { - mBackgroundPaint.setAlpha(i); - } - - @Override - public void setColorFilter(ColorFilter colorFilter) { - // Required by Drawable but not used. - } -} diff --git a/src/com/android/launcher3/apppairs/AppPairIconDrawable.java b/src/com/android/launcher3/apppairs/AppPairIconDrawable.java new file mode 100644 index 0000000000..c0ac11a4a1 --- /dev/null +++ b/src/com/android/launcher3/apppairs/AppPairIconDrawable.java @@ -0,0 +1,208 @@ +/* + * Copyright (C) 2023 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.apppairs; + +import android.graphics.Canvas; +import android.graphics.ColorFilter; +import android.graphics.Paint; +import android.graphics.PixelFormat; +import android.graphics.RectF; +import android.graphics.drawable.Drawable; +import android.os.Build; + +import androidx.annotation.NonNull; + +import com.android.launcher3.icons.FastBitmapDrawable; + +/** + * A composed Drawable consisting of the two app pair icons and the background behind them (looks + * like two rectangles). + */ +class AppPairIconDrawable extends Drawable { + private final Paint mBackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private final AppPairIconDrawingParams mP; + private final FastBitmapDrawable mIcon1; + private final FastBitmapDrawable mIcon2; + + /** + * Null values to use with + * {@link Canvas#drawDoubleRoundRect(RectF, float[], RectF, float[], Paint)}, since there + * doesn't seem to be any other API for drawing rectangles with 4 different corner radii. + */ + private static final RectF EMPTY_RECT = new RectF(); + private static final float[] ARRAY_OF_ZEROES = new float[8]; + + AppPairIconDrawable( + AppPairIconDrawingParams p, FastBitmapDrawable icon1, FastBitmapDrawable icon2) { + mP = p; + mBackgroundPaint.setStyle(Paint.Style.FILL); + mBackgroundPaint.setColor(p.getBgColor()); + mIcon1 = icon1; + mIcon2 = icon2; + } + + @Override + public void draw(@NonNull Canvas canvas) { + if (mP.isLeftRightSplit()) { + drawLeftRightSplit(canvas); + } else { + drawTopBottomSplit(canvas); + } + + canvas.translate( + mP.getStandardIconPadding() + mP.getOuterPadding(), + mP.getStandardIconPadding() + mP.getOuterPadding() + ); + + // Draw first icon. + canvas.save(); + // The app icons are placed differently depending on device orientation. + if (mP.isLeftRightSplit()) { + canvas.translate( + mP.getInnerPadding(), + mP.getBackgroundSize() / 2f - mP.getMemberIconSize() / 2f + ); + } else { + canvas.translate( + mP.getBackgroundSize() / 2f - mP.getMemberIconSize() / 2f, + mP.getInnerPadding() + ); + } + + mIcon1.draw(canvas); + canvas.restore(); + + // Draw second icon. + canvas.save(); + // The app icons are placed differently depending on device orientation. + if (mP.isLeftRightSplit()) { + canvas.translate( + mP.getBackgroundSize() - (mP.getInnerPadding() + mP.getMemberIconSize()), + mP.getBackgroundSize() / 2f - mP.getMemberIconSize() / 2f + ); + } else { + canvas.translate( + mP.getBackgroundSize() / 2f - mP.getMemberIconSize() / 2f, + mP.getBackgroundSize() - (mP.getInnerPadding() + mP.getMemberIconSize()) + ); + } + + mIcon2.draw(canvas); + } + + /** + * When device is in landscape, we draw the rectangles with a left-right split. + */ + private void drawLeftRightSplit(Canvas canvas) { + // Get the bounds where we will draw the background image + int width = mP.getIconSize(); + int height = mP.getIconSize(); + + // The left half of the background image, excluding center channel + RectF leftSide = new RectF( + mP.getStandardIconPadding() + mP.getOuterPadding(), + mP.getStandardIconPadding() + mP.getOuterPadding(), + (width / 2f) - (mP.getCenterChannelSize() / 2f), + height - (mP.getStandardIconPadding() + mP.getOuterPadding()) + ); + // The right half of the background image, excluding center channel + RectF rightSide = new RectF( + (width / 2f) + (mP.getCenterChannelSize() / 2f), + (mP.getStandardIconPadding() + mP.getOuterPadding()), + width - (mP.getStandardIconPadding() + mP.getOuterPadding()), + height - (mP.getStandardIconPadding() + mP.getOuterPadding()) + ); + + drawCustomRoundedRect(canvas, leftSide, new float[]{ + mP.getBigRadius(), mP.getBigRadius(), + mP.getSmallRadius(), mP.getSmallRadius(), + mP.getSmallRadius(), mP.getSmallRadius(), + mP.getBigRadius(), mP.getBigRadius()}); + drawCustomRoundedRect(canvas, rightSide, new float[]{ + mP.getSmallRadius(), mP.getSmallRadius(), + mP.getBigRadius(), mP.getBigRadius(), + mP.getBigRadius(), mP.getBigRadius(), + mP.getSmallRadius(), mP.getSmallRadius()}); + } + + /** + * When device is in portrait, we draw the rectangles with a top-bottom split. + */ + private void drawTopBottomSplit(Canvas canvas) { + // Get the bounds where we will draw the background image + int width = mP.getIconSize(); + int height = mP.getIconSize(); + + // The top half of the background image, excluding center channel + RectF topSide = new RectF( + (mP.getStandardIconPadding() + mP.getOuterPadding()), + (mP.getStandardIconPadding() + mP.getOuterPadding()), + width - (mP.getStandardIconPadding() + mP.getOuterPadding()), + (height / 2f) - (mP.getCenterChannelSize() / 2f) + ); + // The bottom half of the background image, excluding center channel + RectF bottomSide = new RectF( + (mP.getStandardIconPadding() + mP.getOuterPadding()), + (height / 2f) + (mP.getCenterChannelSize() / 2f), + width - (mP.getStandardIconPadding() + mP.getOuterPadding()), + height - (mP.getStandardIconPadding() + mP.getOuterPadding()) + ); + + drawCustomRoundedRect(canvas, topSide, new float[]{ + mP.getBigRadius(), mP.getBigRadius(), + mP.getBigRadius(), mP.getBigRadius(), + mP.getSmallRadius(), mP.getSmallRadius(), + mP.getSmallRadius(), mP.getSmallRadius()}); + drawCustomRoundedRect(canvas, bottomSide, new float[]{ + mP.getSmallRadius(), mP.getSmallRadius(), + mP.getSmallRadius(), mP.getSmallRadius(), + mP.getBigRadius(), mP.getBigRadius(), + mP.getBigRadius(), mP.getBigRadius()}); + } + + /** + * Draws a rectangle with custom rounded corners. + * @param c The Canvas to draw on. + * @param rect The bounds of the rectangle. + * @param radii An array of 8 radii for the corners: top left x, top left y, top right x, top + * right y, bottom right x, and so on. + */ + private void drawCustomRoundedRect(Canvas c, RectF rect, float[] radii) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + // Canvas.drawDoubleRoundRect is supported from Q onward + c.drawDoubleRoundRect(rect, radii, EMPTY_RECT, ARRAY_OF_ZEROES, mBackgroundPaint); + } else { + // Fallback rectangle with uniform rounded corners + c.drawRoundRect(rect, mP.getBigRadius(), mP.getBigRadius(), mBackgroundPaint); + } + } + + @Override + public int getOpacity() { + return PixelFormat.OPAQUE; + } + + @Override + public void setAlpha(int i) { + mBackgroundPaint.setAlpha(i); + } + + @Override + public void setColorFilter(ColorFilter colorFilter) { + mBackgroundPaint.setColorFilter(colorFilter); + } +} diff --git a/src/com/android/launcher3/apppairs/AppPairIconDrawingParams.kt b/src/com/android/launcher3/apppairs/AppPairIconDrawingParams.kt new file mode 100644 index 0000000000..62e5771776 --- /dev/null +++ b/src/com/android/launcher3/apppairs/AppPairIconDrawingParams.kt @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2024 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.apppairs + +import android.content.Context +import com.android.launcher3.BubbleTextView.DISPLAY_FOLDER +import com.android.launcher3.DeviceProfile +import com.android.launcher3.R +import com.android.launcher3.views.ActivityContext + +class AppPairIconDrawingParams(val context: Context, container: Int) { + companion object { + // Design specs -- the below ratios are in relation to the size of a standard app icon. + // Note: The standard app icon has two sizes. One is the full size of the drawable (returned + // by dp.iconSizePx), and one is the visual size of the icon on-screen (11/12 of that). + // Hence the calculations below. + const val STANDARD_ICON_PADDING = 1 / 24f + const val STANDARD_ICON_SHRINK = 1 - STANDARD_ICON_PADDING * 2 + // App pairs are slightly smaller than the *visual* size of a standard icon, so all ratios + // are calculated with that in mind. + const val OUTER_PADDING_SCALE = 1 / 30f * STANDARD_ICON_SHRINK + const val INNER_PADDING_SCALE = 1 / 24f * STANDARD_ICON_SHRINK + const val CENTER_CHANNEL_SCALE = 1 / 30f * STANDARD_ICON_SHRINK + const val BIG_RADIUS_SCALE = 1 / 5f * STANDARD_ICON_SHRINK + const val SMALL_RADIUS_SCALE = 1 / 15f * STANDARD_ICON_SHRINK + const val MEMBER_ICON_SCALE = 11 / 30f * STANDARD_ICON_SHRINK + } + + // The size at which this graphic will be drawn. + val iconSize: Int + // Standard app icons are padded by this amount on each side. + val standardIconPadding: Float + // App pair icons are slightly smaller than regular icons, so we pad the icon by this much on + // each side. + val outerPadding: Float + // The colored background (two rectangles in a square area) is this big. + val backgroundSize: Float + // The size of the channel between the two halves of the app pair icon. + val centerChannelSize: Float + // The corner radius of the outside corners. + val bigRadius: Float + // The corner radius of the inside corners, touching the center channel. + val smallRadius: Float + // Inside of the icon, the two member apps are padded by this much. + val innerPadding: Float + // The two member apps have icons that are this big (in diameter). + val memberIconSize: Float + // The app pair icon appears differently in portrait and landscape. + var isLeftRightSplit: Boolean = true + // The background paint color (based on container). + val bgColor: Int + + init { + val activity: ActivityContext = ActivityContext.lookupContext(context) + val dp = activity.deviceProfile + iconSize = if (container == DISPLAY_FOLDER) dp.folderChildIconSizePx else dp.iconSizePx + standardIconPadding = iconSize * STANDARD_ICON_PADDING + outerPadding = iconSize * OUTER_PADDING_SCALE + backgroundSize = iconSize * STANDARD_ICON_SHRINK - (outerPadding * 2) + centerChannelSize = iconSize * CENTER_CHANNEL_SCALE + bigRadius = iconSize * BIG_RADIUS_SCALE + smallRadius = iconSize * SMALL_RADIUS_SCALE + innerPadding = iconSize * INNER_PADDING_SCALE + memberIconSize = iconSize * MEMBER_ICON_SCALE + updateOrientation(dp) + if (container == DISPLAY_FOLDER) { + val ta = + context.theme.obtainStyledAttributes( + intArrayOf(R.attr.materialColorSurfaceContainerLowest) + ) + bgColor = ta.getColor(0, 0) + ta.recycle() + } else { + val ta = context.theme.obtainStyledAttributes(R.styleable.FolderIconPreview) + bgColor = ta.getColor(R.styleable.FolderIconPreview_folderPreviewColor, 0) + ta.recycle() + } + } + + /** Checks the device orientation and updates isLeftRightSplit accordingly. */ + fun updateOrientation(dp: DeviceProfile) { + isLeftRightSplit = dp.isLeftRightSplit + } +} diff --git a/src/com/android/launcher3/apppairs/AppPairIconGraphic.kt b/src/com/android/launcher3/apppairs/AppPairIconGraphic.kt index a4ac4c8d63..04050b0294 100644 --- a/src/com/android/launcher3/apppairs/AppPairIconGraphic.kt +++ b/src/com/android/launcher3/apppairs/AppPairIconGraphic.kt @@ -21,13 +21,13 @@ import android.graphics.Canvas import android.graphics.Rect import android.graphics.drawable.Drawable import android.util.AttributeSet -import android.util.Log import android.view.Gravity import android.widget.FrameLayout import com.android.launcher3.DeviceProfile import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener import com.android.launcher3.icons.BitmapInfo -import com.android.launcher3.icons.PlaceHolderIconDrawable +import com.android.launcher3.icons.FastBitmapDrawable.getDisabledColorFilter +import com.android.launcher3.model.data.FolderInfo import com.android.launcher3.model.data.WorkspaceItemInfo import com.android.launcher3.util.Themes import com.android.launcher3.views.ActivityContext @@ -41,168 +41,101 @@ class AppPairIconGraphic @JvmOverloads constructor(context: Context, attrs: Attr private val TAG = "AppPairIconGraphic" companion object { - // Design specs -- the below ratios are in relation to the size of a standard app icon. - private const val OUTER_PADDING_SCALE = 1 / 30f - private const val INNER_PADDING_SCALE = 1 / 24f - private const val MEMBER_ICON_SCALE = 11 / 30f - private const val CENTER_CHANNEL_SCALE = 1 / 30f - private const val BIG_RADIUS_SCALE = 1 / 5f - private const val SMALL_RADIUS_SCALE = 1 / 15f - // Disabled alpha is 38%, or 97/255 - private const val DISABLED_ALPHA = 97 - private const val ENABLED_ALPHA = 255 + /** Composes a drawable for this icon, consisting of a background and 2 app icons. */ + @JvmStatic + fun composeDrawable(appPairInfo: FolderInfo, p: AppPairIconDrawingParams): Drawable { + // Generate new icons, using themed flag if needed. + val flags = if (Themes.isThemedIconEnabled(p.context)) BitmapInfo.FLAG_THEMED else 0 + val appIcon1 = appPairInfo.contents[0].newIcon(p.context, flags) + val appIcon2 = appPairInfo.contents[1].newIcon(p.context, flags) + appIcon1.setBounds(0, 0, p.memberIconSize.toInt(), p.memberIconSize.toInt()) + appIcon2.setBounds(0, 0, p.memberIconSize.toInt(), p.memberIconSize.toInt()) + + // Check disabled status. + val activity: ActivityContext = ActivityContext.lookupContext(p.context) + val isLaunchableAtScreenSize = + activity.deviceProfile.isTablet || + appPairInfo.contents.stream().noneMatch { wii: WorkspaceItemInfo -> + wii.hasStatusFlag(WorkspaceItemInfo.FLAG_NON_RESIZEABLE) + } + val shouldDrawAsDisabled = appPairInfo.isDisabled || !isLaunchableAtScreenSize + + // Set disabled status on icons. + appIcon1.setIsDisabled(shouldDrawAsDisabled) + appIcon2.setIsDisabled(shouldDrawAsDisabled) + + // Create icon drawable. + val fullIconDrawable = AppPairIconDrawable(p, appIcon1, appIcon2) + fullIconDrawable.setBounds(0, 0, p.iconSize, p.iconSize) + + // Set disabled color filter on background paint. + fullIconDrawable.colorFilter = + if (shouldDrawAsDisabled) getDisabledColorFilter() else null + + return fullIconDrawable + } } - // App pair icons are slightly smaller than regular icons, so we pad the icon by this much on - // each side. - private var outerPadding = 0f - // Inside of the icon, the two member apps are padded by this much. - private var innerPadding = 0f - // The colored background (two rectangles in a square area) is this big. - private var backgroundSize = 0f - // The two member apps have icons that are this big (in diameter). - private var memberIconSize = 0f - // The size of the center channel. - var centerChannelSize = 0f - // The large outer radius of the background rectangles. - var bigRadius = 0f - // The small inner radius of the background rectangles. - var smallRadius = 0f - // The app pairs icon appears differently in portrait and landscape. - var isLeftRightSplit = false - - private lateinit var activityContext: ActivityContext private lateinit var parentIcon: AppPairIcon - private lateinit var appPairBackground: Drawable - private var appIcon1: Drawable? = null - private var appIcon2: Drawable? = null + private lateinit var drawParams: AppPairIconDrawingParams + private lateinit var drawable: Drawable - fun init(activity: ActivityContext, icon: AppPairIcon) { - activityContext = activity - - // Calculate device-specific measurements - val defaultIconSize = activity.deviceProfile.iconSizePx - outerPadding = OUTER_PADDING_SCALE * defaultIconSize - innerPadding = INNER_PADDING_SCALE * defaultIconSize - backgroundSize = defaultIconSize - outerPadding * 2 - memberIconSize = MEMBER_ICON_SCALE * defaultIconSize - centerChannelSize = CENTER_CHANNEL_SCALE * defaultIconSize - bigRadius = BIG_RADIUS_SCALE * defaultIconSize - smallRadius = SMALL_RADIUS_SCALE * defaultIconSize + fun init(icon: AppPairIcon, container: Int) { parentIcon = icon - updateOrientation() - - appPairBackground = AppPairIconBackground(context, this) - appPairBackground.setBounds(0, 0, backgroundSize.toInt(), backgroundSize.toInt()) - applyIcons(parentIcon.info.contents) + drawParams = AppPairIconDrawingParams(context, container) + drawable = composeDrawable(icon.info, drawParams) // Center the drawable area in the larger icon canvas val lp: LayoutParams = layoutParams as LayoutParams lp.gravity = Gravity.CENTER_HORIZONTAL - lp.topMargin = outerPadding.toInt() - lp.height = backgroundSize.toInt() - lp.width = backgroundSize.toInt() + lp.height = drawParams.iconSize + lp.width = drawParams.iconSize layoutParams = lp } override fun onAttachedToWindow() { super.onAttachedToWindow() - activityContext.addOnDeviceProfileChangeListener(this) + getActivityContext().addOnDeviceProfileChangeListener(this) } override fun onDetachedFromWindow() { super.onDetachedFromWindow() - activityContext.removeOnDeviceProfileChangeListener(this) + getActivityContext().removeOnDeviceProfileChangeListener(this) } - /** Checks the device orientation and updates isLeftRightSplit accordingly. */ - private fun updateOrientation() { - val activity: ActivityContext = ActivityContext.lookupContext(context) - isLeftRightSplit = activity.deviceProfile.isLeftRightSplit + private fun getActivityContext(): ActivityContext { + return ActivityContext.lookupContext(context) } /** When device profile changes, update orientation */ - override fun onDeviceProfileChanged(dp: DeviceProfile?) { - updateOrientation() + override fun onDeviceProfileChanged(dp: DeviceProfile) { + drawParams.updateOrientation(dp) + redraw() + } + + /** Updates the icon drawable and redraws it */ + fun redraw() { + drawable = composeDrawable(parentIcon.info, drawParams) invalidate() } - /** Sets up app pair member icons for drawing. */ - private fun applyIcons(contents: ArrayList) { - // App pair should always contain 2 members; if not 2, return to avoid a crash loop - if (contents.size != 2) { - Log.wtf(TAG, "AppPair contents not 2, size: " + contents.size, Throwable()) - return - } - - // Generate new icons, using themed flag if needed - val flags = if (Themes.isThemedIconEnabled(context)) BitmapInfo.FLAG_THEMED else 0 - val newIcon1 = parentIcon.info.contents[0].newIcon(context, flags) - val newIcon2 = parentIcon.info.contents[1].newIcon(context, flags) - - // If app icons did not draw fully last time, animate to full icon - (appIcon1 as? PlaceHolderIconDrawable)?.animateIconUpdate(newIcon1) - (appIcon2 as? PlaceHolderIconDrawable)?.animateIconUpdate(newIcon2) - - appIcon1 = newIcon1 - appIcon2 = newIcon2 - appIcon1?.setBounds(0, 0, memberIconSize.toInt(), memberIconSize.toInt()) - appIcon2?.setBounds(0, 0, memberIconSize.toInt(), memberIconSize.toInt()) - } - - /** Gets this icon graphic's bounds, with respect to the parent icon's coordinate system. */ + /** + * Gets this icon graphic's visual bounds, with respect to the parent icon's coordinate system. + */ fun getIconBounds(outBounds: Rect) { - outBounds.set(0, 0, backgroundSize.toInt(), backgroundSize.toInt()) + outBounds.set(0, 0, drawParams.backgroundSize.toInt(), drawParams.backgroundSize.toInt()) + outBounds.offset( // x-coordinate in parent's coordinate system - ((parentIcon.width - backgroundSize) / 2).toInt(), + ((parentIcon.width - drawParams.backgroundSize) / 2).toInt(), // y-coordinate in parent's coordinate system - parentIcon.paddingTop + outerPadding.toInt() + (parentIcon.paddingTop + drawParams.standardIconPadding + drawParams.outerPadding) + .toInt() ) } override fun dispatchDraw(canvas: Canvas) { super.dispatchDraw(canvas) - - val drawAlpha = - if (!parentIcon.isLaunchableAtScreenSize || parentIcon.info.isDisabled) DISABLED_ALPHA - else ENABLED_ALPHA - - // Draw background - appPairBackground.alpha = drawAlpha - appPairBackground.draw(canvas) - - // Make sure icons are loaded and fresh - applyIcons(parentIcon.info.contents) - - // Draw first icon - canvas.save() - // The app icons are placed differently depending on device orientation. - if (isLeftRightSplit) { - canvas.translate(innerPadding, height / 2f - memberIconSize / 2f) - } else { - canvas.translate(width / 2f - memberIconSize / 2f, innerPadding) - } - appIcon1?.alpha = drawAlpha - appIcon1?.draw(canvas) - canvas.restore() - - // Draw second icon - canvas.save() - // The app icons are placed differently depending on device orientation. - if (isLeftRightSplit) { - canvas.translate( - width - (innerPadding + memberIconSize), - height / 2f - memberIconSize / 2f - ) - } else { - canvas.translate( - width / 2f - memberIconSize / 2f, - height - (innerPadding + memberIconSize) - ) - } - appIcon2?.alpha = drawAlpha - appIcon2?.draw(canvas) - canvas.restore() + drawable.draw(canvas) } } diff --git a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java index e0a66276b6..1a57d91d7c 100644 --- a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java +++ b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java @@ -20,6 +20,8 @@ import static android.view.View.MeasureSpec.EXACTLY; import static android.view.View.MeasureSpec.makeMeasureSpec; import static android.view.View.VISIBLE; +import static com.android.launcher3.BubbleTextView.DISPLAY_TASKBAR; +import static com.android.launcher3.BubbleTextView.DISPLAY_WORKSPACE; import static com.android.launcher3.DeviceProfile.DEFAULT_SCALE; import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION; import static com.android.launcher3.config.FeatureFlags.shouldShowFirstPageWidget; @@ -388,12 +390,14 @@ public class LauncherPreviewRenderer extends ContextWrapper } private void inflateAndAddCollectionIcon(FolderInfo info) { - CellLayout screen = info.container == Favorites.CONTAINER_DESKTOP + boolean isOnDesktop = info.container == Favorites.CONTAINER_DESKTOP; + CellLayout screen = isOnDesktop ? mWorkspaceScreens.get(info.screenId) : mHotseat; FrameLayout folderIcon = info.itemType == Favorites.ITEM_TYPE_FOLDER ? FolderIcon.inflateIcon(R.layout.folder_icon, this, screen, info) - : AppPairIcon.inflateIcon(R.layout.app_pair_icon, this, screen, info); + : AppPairIcon.inflateIcon(R.layout.app_pair_icon, this, screen, info, + isOnDesktop ? DISPLAY_WORKSPACE : DISPLAY_TASKBAR); addInScreenFromBind(folderIcon, info); } diff --git a/src/com/android/launcher3/util/ItemInflater.kt b/src/com/android/launcher3/util/ItemInflater.kt index cc66af1189..0f8311d50a 100644 --- a/src/com/android/launcher3/util/ItemInflater.kt +++ b/src/com/android/launcher3/util/ItemInflater.kt @@ -81,7 +81,8 @@ class ItemInflater( R.layout.app_pair_icon, context, parent, - item as FolderInfo + item as FolderInfo, + BubbleTextView.DISPLAY_WORKSPACE ) Favorites.ITEM_TYPE_APPWIDGET, Favorites.ITEM_TYPE_CUSTOM_APPWIDGET -> From 38bc885de9407f7e50e76fbe6470f8425cb5f61b Mon Sep 17 00:00:00 2001 From: Uwais Ashraf Date: Wed, 3 Apr 2024 12:49:52 +0000 Subject: [PATCH 5/5] Revert "Update Split button visibility based on DeviceProfile change" This reverts commit 170306d54a79a0390727636563dd22ca742dc09e. Reason for revert: Cause of b/332673787 Bug: 321291049 Change-Id: Id5ae99d28a7497debaabbc5ed09cd18f9c253750 --- .../com/android/quickstep/views/OverviewActionsView.java | 9 ++++----- .../src/com/android/quickstep/views/RecentsView.java | 2 ++ 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/quickstep/src/com/android/quickstep/views/OverviewActionsView.java b/quickstep/src/com/android/quickstep/views/OverviewActionsView.java index 882ccec9e7..384a8d8656 100644 --- a/quickstep/src/com/android/quickstep/views/OverviewActionsView.java +++ b/quickstep/src/com/android/quickstep/views/OverviewActionsView.java @@ -243,13 +243,13 @@ public class OverviewActionsView extends FrameLayo /** * Updates a batch of flags to hide and show actions buttons for tablet/non tablet case. + * @param isSmallScreen True if the current display is a small screen. */ - private void updateForIsTablet() { - assert mDp != null; + public void updateForSmallScreen(boolean isSmallScreen) { // Update flags to see if split button should be hidden. - updateSplitButtonHiddenFlags(FLAG_SMALL_SCREEN_HIDE_SPLIT, !mDp.isTablet); + updateSplitButtonHiddenFlags(FLAG_SMALL_SCREEN_HIDE_SPLIT, isSmallScreen); // Update flags to see if save app pair button should be hidden. - updateAppPairButtonHiddenFlags(FLAG_SMALL_SCREEN_HIDE_APP_PAIR, !mDp.isTablet); + updateAppPairButtonHiddenFlags(FLAG_SMALL_SCREEN_HIDE_APP_PAIR, isSmallScreen); } /** @@ -386,7 +386,6 @@ public class OverviewActionsView extends FrameLayo mDp = dp; mTaskSize.set(taskSize); updateVerticalMargin(DisplayController.getNavigationMode(getContext())); - updateForIsTablet(); requestLayout(); diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java index e57af3a85a..2aa16a948a 100644 --- a/quickstep/src/com/android/quickstep/views/RecentsView.java +++ b/quickstep/src/com/android/quickstep/views/RecentsView.java @@ -3962,6 +3962,8 @@ public abstract class RecentsView