From 500e2b146d2ba78ca57fbee5a5b9dbe24e6a3e96 Mon Sep 17 00:00:00 2001 From: Bill Lin Date: Wed, 14 Jul 2021 17:23:46 +0800 Subject: [PATCH] Fix One-handed tutorial looks janky on entering transition According to systrace, one-handed-tutorial-overlay got jank problem(SurfaceFlinger GPU Deadline Missed, App Deadline Missed, Buffer stuffing). 1.setLayerType(LAYER_TYPE_HARDWARE) when create targetViewContainer setLayerType(LAYER_TYPE_NONE) when removeTutorialFromWindowManager 2.Rename isShowing() to isAttached() 3.Remove redundant float casting 4.Remove redundant increment param Test: manual trigger OHM Test: atest WMShellUnitTests Bug: 193589897 Change-Id: Ieec397795b46dee9ca04375bfc26b09441688d08 --- .../OneHandedAnimationController.java | 8 ++- .../onehanded/OneHandedTutorialHandler.java | 56 +++++++++---------- .../OneHandedTutorialHandlerTest.java | 21 ++++--- 3 files changed, 46 insertions(+), 39 deletions(-) diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedAnimationController.java index 1ae2636241866..bfb2cc6a8fc54 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedAnimationController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedAnimationController.java @@ -163,6 +163,7 @@ public class OneHandedAnimationController { mOneHandedAnimationCallbacks.forEach( (callback) -> callback.onOneHandedAnimationEnd(tx, this) ); + mOneHandedAnimationCallbacks.clear(); } @Override @@ -171,6 +172,7 @@ public class OneHandedAnimationController { mOneHandedAnimationCallbacks.forEach( (callback) -> callback.onOneHandedAnimationCancel(this) ); + mOneHandedAnimationCallbacks.clear(); } @Override @@ -182,7 +184,7 @@ public class OneHandedAnimationController { final SurfaceControl.Transaction tx = newSurfaceControlTransaction(); applySurfaceControlTransaction(mLeash, tx, animation.getAnimatedFraction()); mOneHandedAnimationCallbacks.forEach( - (callback) -> callback.onAnimationUpdate(0f, (float) mCurrentValue) + (callback) -> callback.onAnimationUpdate(0f, mCurrentValue) ); } @@ -216,7 +218,7 @@ public class OneHandedAnimationController { } float getDestinationOffset() { - return ((float) mEndValue - (float) mStartValue); + return (mEndValue - mStartValue); } @TransitionDirection @@ -302,7 +304,7 @@ public class OneHandedAnimationController { @Override public float getInterpolation(float input) { return (float) (Math.pow(2, -10 * input) * Math.sin(((input - 4.0f) / 4.0f) - * (2.0f * Math.PI) / 4.0f) + 1); + * (2.0f * Math.PI) / 4.0f) + 1.0f); } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedTutorialHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedTutorialHandler.java index 0f6c4b081cb7f..d0206a4e3dbfd 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedTutorialHandler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedTutorialHandler.java @@ -16,6 +16,8 @@ package com.android.wm.shell.onehanded; +import static android.view.View.LAYER_TYPE_HARDWARE; +import static android.view.View.LAYER_TYPE_NONE; import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; import static com.android.wm.shell.onehanded.OneHandedState.STATE_ACTIVE; @@ -45,9 +47,8 @@ import java.io.PrintWriter; /** * Handles tutorial visibility and synchronized transition for One Handed operations, - * TargetViewContainer only be created and attach to window when - * shown counts < {@link MAX_TUTORIAL_SHOW_COUNT}, and detach TargetViewContainer from window - * after exiting one handed mode. + * TargetViewContainer only be created and always attach to window, + * detach TargetViewContainer from window after exiting one handed mode. */ public class OneHandedTutorialHandler implements OneHandedTransitionCallback, OneHandedState.OnStateChangedListener { @@ -58,7 +59,6 @@ public class OneHandedTutorialHandler implements OneHandedTransitionCallback, private final float mTutorialHeightRatio; private final WindowManager mWindowManager; - private boolean mIsShowing; private @OneHandedState.State int mCurrentState; private int mTutorialAreaHeight; @@ -80,11 +80,10 @@ public class OneHandedTutorialHandler implements OneHandedTransitionCallback, mAnimationCallback = new OneHandedAnimationCallback() { @Override public void onAnimationUpdate(float xPos, float yPos) { - if (!isShowing()) { + if (!isAttached()) { return; } - mTargetViewContainer.setTransitionGroup(true); - mTargetViewContainer.setTranslationY(yPos - mTargetViewContainer.getHeight()); + mTargetViewContainer.setTranslationY(yPos - mTutorialAreaHeight); } }; } @@ -101,7 +100,7 @@ public class OneHandedTutorialHandler implements OneHandedTransitionCallback, // no - op break; case STATE_NONE: - removeTutorialFromWindowManager(true /* increment */); + removeTutorialFromWindowManager(); break; default: break; @@ -124,13 +123,14 @@ public class OneHandedTutorialHandler implements OneHandedTransitionCallback, @VisibleForTesting void createViewAndAttachToWindow(Context context) { - if (isShowing()) { + if (isAttached()) { return; } mTutorialView = LayoutInflater.from(context).inflate(R.layout.one_handed_tutorial, null); mTargetViewContainer = new FrameLayout(context); mTargetViewContainer.setClipChildren(false); mTargetViewContainer.addView(mTutorialView); + mTargetViewContainer.setLayerType(LAYER_TYPE_HARDWARE, null); attachTargetToWindow(); } @@ -139,29 +139,27 @@ public class OneHandedTutorialHandler implements OneHandedTransitionCallback, * Adds the tutorial target view to the WindowManager and update its layout. */ private void attachTargetToWindow() { - if (!mTargetViewContainer.isAttachedToWindow()) { - try { - mWindowManager.addView(mTargetViewContainer, getTutorialTargetLayoutParams()); - mIsShowing = true; - } catch (IllegalStateException e) { - // This shouldn't happen, but if the target is already added, just update its - // layout params. - mWindowManager.updateViewLayout( - mTargetViewContainer, getTutorialTargetLayoutParams()); - } + try { + mWindowManager.addView(mTargetViewContainer, getTutorialTargetLayoutParams()); + } catch (IllegalStateException e) { + // This shouldn't happen, but if the target is already added, just update its + // layout params. + mWindowManager.updateViewLayout(mTargetViewContainer, getTutorialTargetLayoutParams()); } } @VisibleForTesting - void removeTutorialFromWindowManager(boolean increment) { - if (mTargetViewContainer != null && mTargetViewContainer.isAttachedToWindow()) { - mWindowManager.removeViewImmediate(mTargetViewContainer); - mIsShowing = false; + void removeTutorialFromWindowManager() { + if (!isAttached()) { + return; } + mTargetViewContainer.setLayerType(LAYER_TYPE_NONE, null); + mWindowManager.removeViewImmediate(mTargetViewContainer); + mTargetViewContainer = null; } @Nullable OneHandedAnimationCallback getAnimationCallback() { - return isShowing() ? mAnimationCallback : null /* Disabled */; + return mAnimationCallback; } /** @@ -183,15 +181,15 @@ public class OneHandedTutorialHandler implements OneHandedTransitionCallback, } @VisibleForTesting - boolean isShowing() { - return mIsShowing; + boolean isAttached() { + return mTargetViewContainer != null && mTargetViewContainer.isAttachedToWindow(); } /** * onConfigurationChanged events for updating tutorial text. */ public void onConfigurationChanged() { - removeTutorialFromWindowManager(false /* increment */); + removeTutorialFromWindowManager(); if (mCurrentState == STATE_ENTERING || mCurrentState == STATE_ACTIVE) { createViewAndAttachToWindow(mContext); } @@ -200,8 +198,8 @@ public class OneHandedTutorialHandler implements OneHandedTransitionCallback, void dump(@NonNull PrintWriter pw) { final String innerPrefix = " "; pw.println(TAG); - pw.print(innerPrefix + "mIsShowing="); - pw.println(mIsShowing); + pw.print(innerPrefix + "isAttached="); + pw.println(isAttached()); pw.print(innerPrefix + "mCurrentState="); pw.println(mCurrentState); pw.print(innerPrefix + "mDisplayBounds="); diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedTutorialHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedTutorialHandlerTest.java index 25bdb8ef92634..ae1d3b2a4c41b 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedTutorialHandlerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedTutorialHandlerTest.java @@ -77,7 +77,7 @@ public class OneHandedTutorialHandlerTest extends OneHandedTestCase { @Test public void testOnStateChangedEntering_createViewAndAttachToWindow() { - when(mSpiedTutorialHandler.isShowing()).thenReturn(true); + when(mSpiedTutorialHandler.isAttached()).thenReturn(true); try { mSpiedTutorialHandler.onStateChanged(STATE_ENTERING); } catch (ClassCastException e) { @@ -89,23 +89,27 @@ public class OneHandedTutorialHandlerTest extends OneHandedTestCase { @Test public void testOnStateChangedNone_removeViewAndAttachToWindow() { - when(mSpiedTutorialHandler.isShowing()).thenReturn(true); + when(mSpiedTutorialHandler.isAttached()).thenReturn(true); try { mSpiedTutorialHandler.onStateChanged(STATE_NONE); } catch (ClassCastException e) { // no-op, just assert removeTutorialFromWindowManager() to be called + } catch (NullPointerException e) { + // no-op, just assert removeTutorialFromWindowManager() to be called } - verify(mSpiedTutorialHandler).removeTutorialFromWindowManager(true); + verify(mSpiedTutorialHandler).removeTutorialFromWindowManager(); } @Test public void testOnStateChangedNone_shouldNotAttachWindow() { - when(mSpiedTutorialHandler.isShowing()).thenReturn(true); + when(mSpiedTutorialHandler.isAttached()).thenReturn(true); try { mSpiedTutorialHandler.onStateChanged(STATE_NONE); } catch (ClassCastException e) { // no-op, just assert setTutorialShownCountIncrement() never be called + } catch (NullPointerException e) { + // no-op, just assert setTutorialShownCountIncrement() never be called } verify(mSpiedTutorialHandler, never()).createViewAndAttachToWindow(any()); @@ -113,7 +117,7 @@ public class OneHandedTutorialHandlerTest extends OneHandedTestCase { @Test public void testOnConfigurationChanged_shouldUpdateViewContent() { - when(mSpiedTutorialHandler.isShowing()).thenReturn(true); + when(mSpiedTutorialHandler.isAttached()).thenReturn(true); try { mSpiedTutorialHandler.onStateChanged(STATE_ENTERING); } catch (ClassCastException e) { @@ -122,9 +126,12 @@ public class OneHandedTutorialHandlerTest extends OneHandedTestCase { try { mSpiedTutorialHandler.onConfigurationChanged(); } catch (ClassCastException e) { - // no-op, just assert removeTutorialFromWindowManager() be called + } catch (NullPointerException e) { + // no-op, just assert removeTutorialFromWindowManager() be called, + // and createViewAndAttachToWindow() be called twice } - verify(mSpiedTutorialHandler).removeTutorialFromWindowManager(false); + verify(mSpiedTutorialHandler).createViewAndAttachToWindow(any()); + verify(mSpiedTutorialHandler).removeTutorialFromWindowManager(); } }