From b0cce86385ed85e2721fca4d2a8a8109138394be Mon Sep 17 00:00:00 2001 From: Jeremy Sim Date: Mon, 9 May 2022 17:18:56 -0700 Subject: [PATCH] Implement non-disappearing View for split staging instructions The instructions for how to perform a splitscreen operation, previously conveyed through a disappearing Toast, are now conveyed through a custom View object. Fixes: 219987907 Test: Manual Change-Id: Iff2bb6e334e0325e8a091d76a5f9b8767071365f --- .../split_instructions_background.xml | 21 +++ .../res/layout/split_instructions_view.xml | 35 +++++ .../android/quickstep/views/RecentsView.java | 16 ++- .../views/SplitInstructionsView.java | 123 ++++++++++++++++++ res/values/dimens.xml | 13 +- .../touch/LandscapePagedViewHandler.java | 23 ++++ .../touch/PagedOrientationHandler.java | 10 ++ .../touch/PortraitPagedViewHandler.java | 55 ++++++++ .../touch/SeascapePagedViewHandler.java | 24 ++++ 9 files changed, 317 insertions(+), 3 deletions(-) create mode 100644 quickstep/res/drawable/split_instructions_background.xml create mode 100644 quickstep/res/layout/split_instructions_view.xml create mode 100644 quickstep/src/com/android/quickstep/views/SplitInstructionsView.java diff --git a/quickstep/res/drawable/split_instructions_background.xml b/quickstep/res/drawable/split_instructions_background.xml new file mode 100644 index 0000000000..6d0e7dba1c --- /dev/null +++ b/quickstep/res/drawable/split_instructions_background.xml @@ -0,0 +1,21 @@ + + + + + + \ No newline at end of file diff --git a/quickstep/res/layout/split_instructions_view.xml b/quickstep/res/layout/split_instructions_view.xml new file mode 100644 index 0000000000..91fb05cd0a --- /dev/null +++ b/quickstep/res/layout/split_instructions_view.xml @@ -0,0 +1,35 @@ + + + + + \ No newline at end of file diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java index 2360396cf7..a2f67929b3 100644 --- a/quickstep/src/com/android/quickstep/views/RecentsView.java +++ b/quickstep/src/com/android/quickstep/views/RecentsView.java @@ -630,6 +630,8 @@ public abstract class RecentsView { if (success) { - mSplitToast.show(); InteractionJankMonitorWrapper.end( InteractionJankMonitorWrapper.CUJ_SPLIT_SCREEN_ENTER); } else { @@ -4099,6 +4105,10 @@ public abstract class RecentsView ALPHA_FLOAT = + new FloatProperty("SplitInstructionsAlpha") { + @Override + public void setValue(SplitInstructionsView splitInstructionsView, float v) { + splitInstructionsView.setVisibility(v != 0 ? VISIBLE : GONE); + splitInstructionsView.setAlpha(v); + } + + @Override + public Float get(SplitInstructionsView splitInstructionsView) { + return splitInstructionsView.getAlpha(); + } + }; + + public SplitInstructionsView(Context context) { + this(context, null); + } + + public SplitInstructionsView(Context context, @Nullable AttributeSet attrs) { + this(context, attrs, 0); + } + + public SplitInstructionsView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + mLauncher = (StatefulActivity) context; + } + + static SplitInstructionsView getSplitInstructionsView(StatefulActivity launcher) { + ViewGroup dragLayer = launcher.getDragLayer(); + final SplitInstructionsView splitInstructionsView = + (SplitInstructionsView) launcher.getLayoutInflater().inflate( + R.layout.split_instructions_view, + dragLayer, + false + ); + + dragLayer.addView(splitInstructionsView); + return splitInstructionsView; + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + ensureProperRotation(); + } + + void ensureProperRotation() { + ((RecentsView) mLauncher.getOverviewPanel()).getPagedOrientationHandler() + .setSplitInstructionsParams( + this, + mLauncher.getDeviceProfile(), + getMeasuredHeight(), + getMeasuredWidth(), + getThreeButtonNavShift() + ); + } + + // In some cases, when user is using 3-button nav, there isn't enough room for both the + // 3-button nav and a centered SplitInstructionsView. This function will return an int that will + // be used to shift the SplitInstructionsView over a bit so that everything looks well-spaced. + // In many cases, this will return 0, since we don't need to shift it away from the center. + int getThreeButtonNavShift() { + DeviceProfile dp = mLauncher.getDeviceProfile(); + if ((DisplayController.getNavigationMode(getContext()) == THREE_BUTTONS) + && ((dp.isTwoPanels) || (dp.isTablet && !dp.isLandscape))) { + int navButtonWidth = getResources().getDimensionPixelSize( + R.dimen.taskbar_nav_buttons_size); + int extraMargin = getResources().getDimensionPixelSize( + R.dimen.taskbar_contextual_button_margin); + // Explanation: The 3-button nav for non-phones sits on one side of the screen, taking + // up 3 buttons + a side margin worth of space. Our splitInstructionsView starts in the + // center of the screen and we want to center it in the remaining space, therefore we + // want to shift it over by half the 3-button layout's width. + // If the user is using an RtL layout, we shift it the opposite way. + return -((3 * navButtonWidth + extraMargin) / 2) * (isLayoutRtl() ? -1 : 1); + } else { + return 0; + } + } +} diff --git a/res/values/dimens.xml b/res/values/dimens.xml index 766dca35c2..e7b3375c4b 100644 --- a/res/values/dimens.xml +++ b/res/values/dimens.xml @@ -390,8 +390,17 @@ 16dp 44dp 216dp - - + 22dp + 1dp + 24dp + 12dp + 32dp + 44dp + 33dp + 51dp + 24dp + 60dp + 28dp 6dp diff --git a/src/com/android/launcher3/touch/LandscapePagedViewHandler.java b/src/com/android/launcher3/touch/LandscapePagedViewHandler.java index 121088a014..21372cf690 100644 --- a/src/com/android/launcher3/touch/LandscapePagedViewHandler.java +++ b/src/com/android/launcher3/touch/LandscapePagedViewHandler.java @@ -19,6 +19,7 @@ package com.android.launcher3.touch; import static android.view.Gravity.BOTTOM; import static android.view.Gravity.CENTER_VERTICAL; import static android.view.Gravity.END; +import static android.view.Gravity.LEFT; import static android.view.Gravity.START; import static android.view.Gravity.TOP; import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; @@ -424,6 +425,28 @@ public class LandscapePagedViewHandler implements PagedOrientationHandler { - 1.0f * drawableHeight / 2)); } + @Override + public void setSplitInstructionsParams(View out, DeviceProfile dp, int splitInstructionsHeight, + int splitInstructionsWidth, int threeButtonNavShift) { + out.setPivotX(0); + out.setPivotY(0); + out.setRotation(getDegreesRotated()); + int distanceToEdge = out.getResources().getDimensionPixelSize( + R.dimen.split_instructions_bottom_margin_phone_landscape); + // Adjust for any insets on the left edge + int insetCorrectionX = dp.getInsets().left; + // Center the view in case of unbalanced insets on top or bottom of screen + int insetCorrectionY = (dp.getInsets().bottom - dp.getInsets().top) / 2; + out.setTranslationX(splitInstructionsHeight + distanceToEdge - insetCorrectionX); + out.setTranslationY(((splitInstructionsHeight - splitInstructionsWidth) / 2f) + + insetCorrectionY); + FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) out.getLayoutParams(); + // Setting gravity to LEFT instead of the lint-recommended START because we always want this + // view to be screen-left when phone is in landscape, regardless of the RtL setting. + lp.gravity = LEFT | CENTER_VERTICAL; + out.setLayoutParams(lp); + } + @Override public void getFinalSplitPlaceholderBounds(int splitDividerSize, DeviceProfile dp, @StagePosition int stagePosition, Rect out1, Rect out2) { diff --git a/src/com/android/launcher3/touch/PagedOrientationHandler.java b/src/com/android/launcher3/touch/PagedOrientationHandler.java index 4fcf378541..74e2020b0c 100644 --- a/src/com/android/launcher3/touch/PagedOrientationHandler.java +++ b/src/com/android/launcher3/touch/PagedOrientationHandler.java @@ -134,6 +134,16 @@ public interface PagedOrientationHandler { int drawableWidth, int drawableHeight, DeviceProfile dp, @StagePosition int stagePosition); + /** + * Sets positioning and rotation for a SplitInstructionsView. + * @param out The SplitInstructionsView that needs to be positioned. + * @param dp The device profile, used to report rotation and device type. + * @param splitInstructionsHeight The SplitInstructionView's height. + * @param splitInstructionsWidth The SplitInstructionView's width. + */ + void setSplitInstructionsParams(View out, DeviceProfile dp, int splitInstructionsHeight, + int splitInstructionsWidth, int threeButtonNavShift); + /** * @param splitDividerSize height of split screen drag handle in portrait, width in landscape * @param stagePosition the split position option (top/left, bottom/right) of the first diff --git a/src/com/android/launcher3/touch/PortraitPagedViewHandler.java b/src/com/android/launcher3/touch/PortraitPagedViewHandler.java index 80a8c19d54..816e3962e8 100644 --- a/src/com/android/launcher3/touch/PortraitPagedViewHandler.java +++ b/src/com/android/launcher3/touch/PortraitPagedViewHandler.java @@ -27,6 +27,7 @@ import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_X; import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_Y; import static com.android.launcher3.touch.SingleAxisSwipeDetector.VERTICAL; +import static com.android.launcher3.util.DisplayController.NavigationMode.THREE_BUTTONS; import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT; import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT; @@ -47,7 +48,9 @@ import android.widget.FrameLayout; import android.widget.LinearLayout; import com.android.launcher3.DeviceProfile; +import com.android.launcher3.R; import com.android.launcher3.Utilities; +import com.android.launcher3.util.DisplayController; import com.android.launcher3.util.SplitConfigurationOptions; import com.android.launcher3.util.SplitConfigurationOptions.SplitPositionOption; import com.android.launcher3.util.SplitConfigurationOptions.StagePosition; @@ -484,6 +487,58 @@ public class PortraitPagedViewHandler implements PagedOrientationHandler { } } + @Override + public void setSplitInstructionsParams(View out, DeviceProfile dp, int splitInstructionsHeight, + int splitInstructionsWidth, int threeButtonNavShift) { + out.setPivotX(0); + out.setPivotY(0); + out.setRotation(getDegreesRotated()); + int distanceToEdge; + if ((DisplayController.getNavigationMode(out.getContext()) == THREE_BUTTONS) + && (dp.isTwoPanels || dp.isTablet)) { + // If 3-button nav is active, align the splitInstructionsView with it. + distanceToEdge = dp.getTaskbarOffsetY() + + ((dp.taskbarSize - splitInstructionsHeight) / 2); + } else { + // If 3-button nav is not active, set bottom margin according to spec. + if (dp.isPhone) { + if (dp.isLandscape) { + distanceToEdge = out.getResources().getDimensionPixelSize( + R.dimen.split_instructions_bottom_margin_phone_landscape); + } else { + distanceToEdge = out.getResources().getDimensionPixelSize( + R.dimen.split_instructions_bottom_margin_phone_portrait); + } + } else if (dp.isTwoPanels) { + if (dp.isLandscape) { + distanceToEdge = out.getResources().getDimensionPixelSize( + R.dimen.split_instructions_bottom_margin_twopanels_landscape); + } else { + distanceToEdge = out.getResources().getDimensionPixelSize( + R.dimen.split_instructions_bottom_margin_twopanels_portrait); + } + } else { + if (dp.isLandscape) { + distanceToEdge = out.getResources().getDimensionPixelSize( + R.dimen.split_instructions_bottom_margin_tablet_landscape); + } else { + distanceToEdge = out.getResources().getDimensionPixelSize( + R.dimen.split_instructions_bottom_margin_tablet_portrait); + } + } + } + + // Center the view in case of unbalanced insets on left or right of screen + int insetCorrectionX = (dp.getInsets().right - dp.getInsets().left) / 2; + // Adjust for any insets on the bottom edge + int insetCorrectionY = dp.getInsets().bottom; + out.setTranslationX(insetCorrectionX + threeButtonNavShift); + out.setTranslationY(-distanceToEdge + insetCorrectionY); + FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) out.getLayoutParams(); + lp.gravity = CENTER_HORIZONTAL | BOTTOM; + out.setLayoutParams(lp); + } + @Override public void getFinalSplitPlaceholderBounds(int splitDividerSize, DeviceProfile dp, @StagePosition int stagePosition, Rect out1, Rect out2) { diff --git a/src/com/android/launcher3/touch/SeascapePagedViewHandler.java b/src/com/android/launcher3/touch/SeascapePagedViewHandler.java index 74b6a5b28e..71adb7ab7e 100644 --- a/src/com/android/launcher3/touch/SeascapePagedViewHandler.java +++ b/src/com/android/launcher3/touch/SeascapePagedViewHandler.java @@ -19,6 +19,7 @@ package com.android.launcher3.touch; import static android.view.Gravity.BOTTOM; import static android.view.Gravity.CENTER_VERTICAL; import static android.view.Gravity.END; +import static android.view.Gravity.RIGHT; import static android.view.Gravity.START; import static com.android.launcher3.touch.SingleAxisSwipeDetector.HORIZONTAL; @@ -166,6 +167,29 @@ public class SeascapePagedViewHandler extends LandscapePagedViewHandler { STAGE_POSITION_BOTTOM_OR_RIGHT, STAGE_TYPE_MAIN)); } + @Override + public void setSplitInstructionsParams(View out, DeviceProfile dp, int splitInstructionsHeight, + int splitInstructionsWidth, int threeButtonNavShift) { + out.setPivotX(0); + out.setPivotY(0); + out.setRotation(getDegreesRotated()); + int distanceToEdge = out.getResources().getDimensionPixelSize( + R.dimen.split_instructions_bottom_margin_phone_landscape); + // Adjust for any insets on the right edge + int insetCorrectionX = dp.getInsets().right; + // Center the view in case of unbalanced insets on top or bottom of screen + int insetCorrectionY = (dp.getInsets().bottom - dp.getInsets().top) / 2; + out.setTranslationX(splitInstructionsWidth - splitInstructionsHeight - distanceToEdge + + insetCorrectionX); + out.setTranslationY(((splitInstructionsHeight + splitInstructionsWidth) / 2f) + + insetCorrectionY); + FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) out.getLayoutParams(); + // Setting gravity to RIGHT instead of the lint-recommended END because we always want this + // view to be screen-right when phone is in seascape, regardless of the RtL setting. + lp.gravity = RIGHT | CENTER_VERTICAL; + out.setLayoutParams(lp); + } + @Override public void setTaskIconParams(FrameLayout.LayoutParams iconParams, int taskIconMargin, int taskIconHeight, int thumbnailTopMargin, boolean isRtl) {