From f40204087c6b2ed2dc228ac77e046b52ac85675a Mon Sep 17 00:00:00 2001 From: Jason Chang Date: Sat, 24 Jul 2021 02:20:13 +0800 Subject: [PATCH] Fix tutorial background color not up-to-date occasionally 1. Fix bug in the legacy code flow - Obtain color from contextThemeWrapper Theme_DeviceDefault_DayNight - In OneHandedDisplayAreaOrganizer#finishOffset() Remove redundant call "cb.onStartTransition" due to ambugiuous. 2. Improve performance - Remove redundunt callbacks. - Avoid create/remove leash on each start/end cycle. - Dispatch Transaction to bkg leash through onAnimationUpdate() bkg leash apply the same Transaction of display area. - Adjust animation duration of Tutorial panel. - Move bkg leash depend on yPos value to reduce SF componsition overhead. 3. Improve code readibility - Code flow : Register -> onStart() -> show background -> detach background -> Unregister -> remove leash. - Remove redundant synchronization due to wmshell already guarantee thread safe. - Move getTranslationFraction to SettingsUtil. - Move getTransitionDuration to SettingsUtil. Bug: 194507756 Bug: 193589897 Test: Local verify when changing dark theme and wallpaper theme. Test: atest WMShellUnitTests Change-Id: Ib55753be9e9f4665c20ad34437f86bf80cc9f3b4 --- .../onehanded/OneHandedAnimationCallback.java | 2 +- .../OneHandedAnimationController.java | 4 +- .../OneHandedBackgroundPanelOrganizer.java | 266 ++++++++++-------- .../shell/onehanded/OneHandedController.java | 11 +- .../OneHandedDisplayAreaOrganizer.java | 8 +- .../onehanded/OneHandedSettingsUtil.java | 23 +- .../onehanded/OneHandedTutorialHandler.java | 83 +++--- ...OneHandedBackgroundPanelOrganizerTest.java | 31 +- .../onehanded/OneHandedControllerTest.java | 2 +- .../shell/onehanded/OneHandedStateTest.java | 2 +- .../OneHandedTutorialHandlerTest.java | 2 +- 11 files changed, 235 insertions(+), 199 deletions(-) diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedAnimationCallback.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedAnimationCallback.java index 24e511143cff6..8969cc8a7da93 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedAnimationCallback.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedAnimationCallback.java @@ -46,7 +46,7 @@ public interface OneHandedAnimationCallback { /** * Called when OneHanded animator is updating position */ - default void onAnimationUpdate(float xPos, float yPos) { + default void onAnimationUpdate(SurfaceControl.Transaction tx, float xPos, float yPos) { } } 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 bfb2cc6a8fc54..4b7832845a1d6 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 @@ -182,10 +182,10 @@ public class OneHandedAnimationController { @Override public void onAnimationUpdate(ValueAnimator animation) { final SurfaceControl.Transaction tx = newSurfaceControlTransaction(); - applySurfaceControlTransaction(mLeash, tx, animation.getAnimatedFraction()); mOneHandedAnimationCallbacks.forEach( - (callback) -> callback.onAnimationUpdate(0f, mCurrentValue) + (callback) -> callback.onAnimationUpdate(tx, 0f, mCurrentValue) ); + applySurfaceControlTransaction(mLeash, tx, animation.getAnimatedFraction()); } void onStartTransaction(SurfaceControl leash, SurfaceControl.Transaction tx) { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedBackgroundPanelOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedBackgroundPanelOrganizer.java index 3ccb9e7570d56..97461e607e667 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedBackgroundPanelOrganizer.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedBackgroundPanelOrganizer.java @@ -16,12 +16,14 @@ package com.android.wm.shell.onehanded; +import android.animation.ValueAnimator; import android.content.Context; import android.graphics.Color; import android.graphics.PixelFormat; import android.graphics.Rect; import android.view.SurfaceControl; import android.view.SurfaceSession; +import android.view.animation.LinearInterpolator; import android.window.DisplayAreaAppearedInfo; import android.window.DisplayAreaInfo; import android.window.DisplayAreaOrganizer; @@ -29,8 +31,8 @@ import android.window.DisplayAreaOrganizer; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; +import androidx.appcompat.view.ContextThemeWrapper; -import com.android.internal.annotations.GuardedBy; import com.android.wm.shell.R; import com.android.wm.shell.common.DisplayLayout; @@ -44,194 +46,212 @@ import java.util.concurrent.Executor; * the screen has entered one handed mode. */ public class OneHandedBackgroundPanelOrganizer extends DisplayAreaOrganizer - implements OneHandedTransitionCallback { + implements OneHandedAnimationCallback { private static final String TAG = "OneHandedBackgroundPanelOrganizer"; private static final int THEME_COLOR_OFFSET = 10; + private static final int ALPHA_ANIMATION_DURATION = 200; private final Context mContext; - private final Object mLock = new Object(); private final SurfaceSession mSurfaceSession = new SurfaceSession(); - private final Executor mMainExecutor; private final OneHandedSurfaceTransactionHelper.SurfaceControlTransactionFactory - mSurfaceControlTransactionFactory; + mTransactionFactory; - private float[] mDefaultColor; + private ValueAnimator mAlphaAnimator; + + private float mTranslationFraction; + private float[] mThemeColor; /** * The background to distinguish the boundary of translated windows and empty region when * one handed mode triggered. */ private Rect mBkgBounds; + private Rect mStableInsets; + + @Nullable @VisibleForTesting - @GuardedBy("mLock") - boolean mIsShowing; + SurfaceControl mBackgroundSurface; @Nullable - @GuardedBy("mLock") - private SurfaceControl mBackgroundSurface; - @Nullable - @GuardedBy("mLock") private SurfaceControl mParentLeash; - private final OneHandedAnimationCallback mOneHandedAnimationCallback = - new OneHandedAnimationCallback() { - @Override - public void onOneHandedAnimationStart( - OneHandedAnimationController.OneHandedTransitionAnimator animator) { - mMainExecutor.execute(() -> showBackgroundPanelLayer()); - } - }; - - @Override - public void onStopFinished(Rect bounds) { - mMainExecutor.execute(() -> removeBackgroundPanelLayer()); - } - public OneHandedBackgroundPanelOrganizer(Context context, DisplayLayout displayLayout, - Executor executor) { + OneHandedSettingsUtil settingsUtil, Executor executor) { super(executor); mContext = context; - // Ensure the mBkgBounds is portrait, due to OHM only support on portrait - if (displayLayout.height() > displayLayout.width()) { - mBkgBounds = new Rect(0, 0, displayLayout.width(), displayLayout.height()); - } else { - mBkgBounds = new Rect(0, 0, displayLayout.height(), displayLayout.width()); - } + mTranslationFraction = settingsUtil.getTranslationFraction(context); + mTransactionFactory = SurfaceControl.Transaction::new; updateThemeColors(); - mMainExecutor = executor; - mSurfaceControlTransactionFactory = SurfaceControl.Transaction::new; } @Override public void onDisplayAreaAppeared(@NonNull DisplayAreaInfo displayAreaInfo, @NonNull SurfaceControl leash) { - synchronized (mLock) { - if (mParentLeash == null) { - mParentLeash = leash; - } else { - throw new RuntimeException("There should be only one DisplayArea for " - + "the one-handed mode background panel"); - } - } - } - - OneHandedAnimationCallback getOneHandedAnimationCallback() { - return mOneHandedAnimationCallback; + mParentLeash = leash; } @Override public List registerOrganizer(int displayAreaFeature) { - synchronized (mLock) { - final List displayAreaInfos; - displayAreaInfos = super.registerOrganizer(displayAreaFeature); - for (int i = 0; i < displayAreaInfos.size(); i++) { - final DisplayAreaAppearedInfo info = displayAreaInfos.get(i); - onDisplayAreaAppeared(info.getDisplayAreaInfo(), info.getLeash()); - } - return displayAreaInfos; + final List displayAreaInfos; + displayAreaInfos = super.registerOrganizer(displayAreaFeature); + for (int i = 0; i < displayAreaInfos.size(); i++) { + final DisplayAreaAppearedInfo info = displayAreaInfos.get(i); + onDisplayAreaAppeared(info.getDisplayAreaInfo(), info.getLeash()); } + return displayAreaInfos; } @Override public void unregisterOrganizer() { - synchronized (mLock) { - super.unregisterOrganizer(); - mParentLeash = null; - } + super.unregisterOrganizer(); + removeBackgroundPanelLayer(); + mParentLeash = null; + } + + @Override + public void onAnimationUpdate(SurfaceControl.Transaction tx, float xPos, float yPos) { + final int yTopPos = (mStableInsets.top - mBkgBounds.height()) + Math.round(yPos); + tx.setPosition(mBackgroundSurface, 0, yTopPos); } @Nullable @VisibleForTesting - SurfaceControl getBackgroundSurface() { - synchronized (mLock) { - if (mParentLeash == null) { - return null; - } + boolean isRegistered() { + return mParentLeash != null; + } - if (mBackgroundSurface == null) { - mBackgroundSurface = new SurfaceControl.Builder(mSurfaceSession) - .setParent(mParentLeash) - .setBufferSize(mBkgBounds.width(), mBkgBounds.height()) - .setColorLayer() - .setFormat(PixelFormat.RGB_888) - .setOpaque(true) - .setName("one-handed-background-panel") - .setCallsite("OneHandedBackgroundPanelOrganizer") - .build(); - } - return mBackgroundSurface; + void createBackgroundSurface() { + mBackgroundSurface = new SurfaceControl.Builder(mSurfaceSession) + .setBufferSize(mBkgBounds.width(), mBkgBounds.height()) + .setColorLayer() + .setFormat(PixelFormat.RGB_888) + .setOpaque(true) + .setName("one-handed-background-panel") + .setCallsite("OneHandedBackgroundPanelOrganizer") + .build(); + + // TODO(185890335) Avoid Dimming for mid-range luminance wallpapers flash. + mAlphaAnimator = ValueAnimator.ofFloat(1.0f, 0.0f); + mAlphaAnimator.setInterpolator(new LinearInterpolator()); + mAlphaAnimator.setDuration(ALPHA_ANIMATION_DURATION); + mAlphaAnimator.addUpdateListener( + animator -> detachBackgroundFromParent(animator)); + } + + void detachBackgroundFromParent(ValueAnimator animator) { + if (mBackgroundSurface == null || mParentLeash == null) { + return; } + // TODO(185890335) Avoid Dimming for mid-range luminance wallpapers flash. + final float currentValue = (float) animator.getAnimatedValue(); + final SurfaceControl.Transaction tx = mTransactionFactory.getTransaction(); + if (currentValue == 0.0f) { + tx.reparent(mBackgroundSurface, null).apply(); + } else { + tx.setAlpha(mBackgroundSurface, (float) animator.getAnimatedValue()).apply(); + } + } + + /** + * Called when onDisplayAdded() or onDisplayRemoved() callback. + * + * @param displayLayout The latest {@link DisplayLayout} representing current displayId + */ + public void onDisplayChanged(DisplayLayout displayLayout) { + mStableInsets = displayLayout.stableInsets(); + // Ensure the mBkgBounds is portrait, due to OHM only support on portrait + if (displayLayout.height() > displayLayout.width()) { + mBkgBounds = new Rect(0, 0, displayLayout.width(), + Math.round(displayLayout.height() * mTranslationFraction) + mStableInsets.top); + } else { + mBkgBounds = new Rect(0, 0, displayLayout.height(), + Math.round(displayLayout.width() * mTranslationFraction) + mStableInsets.top); + } + } + + @VisibleForTesting + void onStart() { + if (mBackgroundSurface == null) { + createBackgroundSurface(); + } + showBackgroundPanelLayer(); + } + + /** + * Called when transition finished. + */ + public void onStopFinished() { + mAlphaAnimator.start(); } @VisibleForTesting void showBackgroundPanelLayer() { - synchronized (mLock) { - if (mIsShowing) { - return; - } - - if (getBackgroundSurface() == null) { - return; - } - - SurfaceControl.Transaction transaction = - mSurfaceControlTransactionFactory.getTransaction(); - transaction.setLayer(mBackgroundSurface, -1 /* at bottom-most layer */) - .setColor(mBackgroundSurface, mDefaultColor) - .show(mBackgroundSurface) - .apply(); - transaction.close(); - mIsShowing = true; + if (mParentLeash == null) { + return; } + + if (mBackgroundSurface == null) { + createBackgroundSurface(); + } + + // TODO(185890335) Avoid Dimming for mid-range luminance wallpapers flash. + if (mAlphaAnimator.isRunning()) { + mAlphaAnimator.end(); + } + + mTransactionFactory.getTransaction() + .reparent(mBackgroundSurface, mParentLeash) + .setAlpha(mBackgroundSurface, 1.0f) + .setLayer(mBackgroundSurface, -1 /* at bottom-most layer */) + .setColor(mBackgroundSurface, mThemeColor) + .show(mBackgroundSurface) + .apply(); } @VisibleForTesting void removeBackgroundPanelLayer() { - synchronized (mLock) { - if (mBackgroundSurface == null) { - return; - } - - SurfaceControl.Transaction transaction = - mSurfaceControlTransactionFactory.getTransaction(); - transaction.remove(mBackgroundSurface).apply(); - transaction.close(); - mBackgroundSurface = null; - mIsShowing = false; + if (mBackgroundSurface == null) { + return; } + + mTransactionFactory.getTransaction() + .remove(mBackgroundSurface) + .apply(); + mBackgroundSurface = null; } /** * onConfigurationChanged events for updating tutorial text. */ public void onConfigurationChanged() { - synchronized (mLock) { - if (mBackgroundSurface == null) { - getBackgroundSurface(); - } else { - removeBackgroundPanelLayer(); - } - updateThemeColors(); - showBackgroundPanelLayer(); - } + updateThemeColors(); + showBackgroundPanelLayer(); } private void updateThemeColors() { - synchronized (mLock) { - final int themeColor = mContext.getColor(R.color.one_handed_tutorial_background_color); - mDefaultColor = new float[]{(Color.red(themeColor) - THEME_COLOR_OFFSET) / 255.0f, - (Color.green(themeColor) - THEME_COLOR_OFFSET) / 255.0f, - (Color.blue(themeColor) - THEME_COLOR_OFFSET) / 255.0f}; - } + final Context themedContext = new ContextThemeWrapper(mContext, + com.android.internal.R.style.Theme_DeviceDefault_DayNight); + final int themeColor = themedContext.getColor( + R.color.one_handed_tutorial_background_color); + mThemeColor = new float[]{ + adjustColor(Color.red(themeColor)), + adjustColor(Color.green(themeColor)), + adjustColor(Color.blue(themeColor))}; + } + + private float adjustColor(int origColor) { + return Math.max(origColor - THEME_COLOR_OFFSET, 0) / 255.0f; } void dump(@NonNull PrintWriter pw) { final String innerPrefix = " "; pw.println(TAG); - pw.print(innerPrefix + "mIsShowing="); - pw.println(mIsShowing); + pw.print(innerPrefix + "mBackgroundSurface="); + pw.println(mBackgroundSurface); pw.print(innerPrefix + "mBkgBounds="); pw.println(mBkgBounds); - pw.print(innerPrefix + "mDefaultColor="); - pw.println(mDefaultColor); + pw.print(innerPrefix + "mThemeColor="); + pw.println(mThemeColor); + pw.print(innerPrefix + "mTranslationFraction="); + pw.println(mTranslationFraction); } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java index 09cde38a0cfc9..b0fe856df7c8c 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java @@ -180,6 +180,7 @@ public class OneHandedController implements RemoteCallable public void onStopFinished(Rect bounds) { mState.setState(STATE_NONE); notifyShortcutStateChanged(STATE_NONE); + mBackgroundPanelOrganizer.onStopFinished(); } }; @@ -223,13 +224,14 @@ public class OneHandedController implements RemoteCallable OneHandedTimeoutHandler timeoutHandler = new OneHandedTimeoutHandler(mainExecutor); OneHandedState transitionState = new OneHandedState(); OneHandedTutorialHandler tutorialHandler = new OneHandedTutorialHandler(context, - windowManager); + settingsUtil, windowManager); OneHandedAnimationController animationController = new OneHandedAnimationController(context); OneHandedTouchHandler touchHandler = new OneHandedTouchHandler(timeoutHandler, mainExecutor); OneHandedBackgroundPanelOrganizer oneHandedBackgroundPanelOrganizer = - new OneHandedBackgroundPanelOrganizer(context, displayLayout, mainExecutor); + new OneHandedBackgroundPanelOrganizer(context, displayLayout, settingsUtil, + mainExecutor); OneHandedDisplayAreaOrganizer organizer = new OneHandedDisplayAreaOrganizer( context, displayLayout, settingsUtil, animationController, tutorialHandler, oneHandedBackgroundPanelOrganizer, mainExecutor); @@ -386,6 +388,7 @@ public class OneHandedController implements RemoteCallable mDisplayAreaOrganizer.getDisplayLayout().height() * mOffSetFraction); mOneHandedAccessibilityUtil.announcementForScreenReader( mOneHandedAccessibilityUtil.getOneHandedStartDescription()); + mBackgroundPanelOrganizer.onStart(); mDisplayAreaOrganizer.scheduleOffset(0, yOffSet); mTimeoutHandler.resetTimer(); mOneHandedUiEventLogger.writeEvent( @@ -423,7 +426,6 @@ public class OneHandedController implements RemoteCallable stopOneHanded(OneHandedUiEventLogger.EVENT_ONE_HANDED_TRIGGER_OVERSPACE_OUT)); mDisplayAreaOrganizer.registerTransitionCallback(mTouchHandler); mDisplayAreaOrganizer.registerTransitionCallback(mTutorialHandler); - mDisplayAreaOrganizer.registerTransitionCallback(mBackgroundPanelOrganizer); mDisplayAreaOrganizer.registerTransitionCallback(mTransitionCallBack); if (mTaskChangeToExit) { mTaskStackListener.addListener(mTaskStackListenerCallback); @@ -469,6 +471,7 @@ public class OneHandedController implements RemoteCallable final DisplayLayout newDisplayLayout = mDisplayController.getDisplayLayout(displayId); mDisplayAreaOrganizer.setDisplayLayout(newDisplayLayout); mTutorialHandler.onDisplayChanged(newDisplayLayout); + mBackgroundPanelOrganizer.onDisplayChanged(newDisplayLayout); } private ContentObserver getObserver(Runnable onChangeRunnable) { @@ -606,7 +609,7 @@ public class OneHandedController implements RemoteCallable OneHandedDisplayAreaOrganizer.FEATURE_ONE_HANDED); } - if (mBackgroundPanelOrganizer.getBackgroundSurface() == null) { + if (!mBackgroundPanelOrganizer.isRegistered()) { mBackgroundPanelOrganizer.registerOrganizer( OneHandedBackgroundPanelOrganizer.FEATURE_ONE_HANDED_BACKGROUND_PANEL); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java index 03a90c6d46774..c2bbd9e99bac0 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java @@ -135,8 +135,8 @@ public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer { SystemProperties.getInt(ONE_HANDED_MODE_TRANSLATE_ANIMATION_DURATION, animationDurationConfig); mSurfaceControlTransactionFactory = SurfaceControl.Transaction::new; - mTutorialHandler = tutorialHandler; mBackgroundPanelOrganizer = oneHandedBackgroundGradientOrganizer; + mTutorialHandler = tutorialHandler; } @Override @@ -249,9 +249,8 @@ public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer { if (animator != null) { animator.setTransitionDirection(direction) .addOneHandedAnimationCallback(mOneHandedAnimationCallback) - .addOneHandedAnimationCallback(mTutorialHandler.getAnimationCallback()) - .addOneHandedAnimationCallback( - mBackgroundPanelOrganizer.getOneHandedAnimationCallback()) + .addOneHandedAnimationCallback(mTutorialHandler) + .addOneHandedAnimationCallback(mBackgroundPanelOrganizer) .setDuration(durationMs) .start(); } @@ -267,7 +266,6 @@ public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer { mLastVisualDisplayBounds.offsetTo(0, Math.round(mLastVisualOffset)); for (int i = mTransitionCallbacks.size() - 1; i >= 0; i--) { final OneHandedTransitionCallback cb = mTransitionCallbacks.get(i); - cb.onStartTransition(false /* isTransitioning */); if (direction == TRANSITION_DIRECTION_TRIGGER) { cb.onStartFinished(getLastVisualDisplayBounds()); } else { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedSettingsUtil.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedSettingsUtil.java index 5911f8d66b324..60074b8cdb47c 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedSettingsUtil.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedSettingsUtil.java @@ -20,6 +20,7 @@ import static com.android.internal.accessibility.AccessibilityShortcutController import android.annotation.IntDef; import android.content.ContentResolver; +import android.content.Context; import android.database.ContentObserver; import android.net.Uri; import android.provider.Settings; @@ -27,6 +28,8 @@ import android.text.TextUtils; import androidx.annotation.Nullable; +import com.android.wm.shell.R; + import java.io.PrintWriter; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -36,7 +39,6 @@ import java.lang.annotation.RetentionPolicy; */ public final class OneHandedSettingsUtil { private static final String TAG = "OneHandedSettingsUtil"; - private static final String ONE_HANDED_MODE_TARGET_NAME = ONE_HANDED_COMPONENT_NAME.getShortClassName(); @@ -204,6 +206,25 @@ public final class OneHandedSettingsUtil { Settings.Secure.ONE_HANDED_MODE_ACTIVATED, state, userId); } + /** + * Obtains one-handed mode transition duration from resource config. + * + * @return durationMs The duration in milli-seconds + */ + public int getTransitionDuration(Context context) { + return context.getResources().getInteger( + R.integer.config_one_handed_translate_animation_duration); + } + + /** + * Obtains one-handed mode offset fraction from resource config. + * + * @return fraction The fraction of offset of the whole screen. + */ + public float getTranslationFraction(Context context) { + return context.getResources().getFraction(R.fraction.config_one_handed_offset, 1, 1); + } + void dump(PrintWriter pw, String prefix, ContentResolver resolver, int userId) { final String innerPrefix = " "; 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 97e04b5a7abda..f58c6b173af9f 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 @@ -32,9 +32,9 @@ import android.content.res.ColorStateList; import android.content.res.TypedArray; import android.graphics.PixelFormat; import android.graphics.Rect; -import android.os.SystemProperties; import android.view.Gravity; import android.view.LayoutInflater; +import android.view.SurfaceControl; import android.view.View; import android.view.ViewGroup; import android.view.WindowManager; @@ -58,66 +58,54 @@ import java.io.PrintWriter; * detach TargetViewContainer from window after exiting one handed mode. */ public class OneHandedTutorialHandler implements OneHandedTransitionCallback, - OneHandedState.OnStateChangedListener { + OneHandedState.OnStateChangedListener, OneHandedAnimationCallback { private static final String TAG = "OneHandedTutorialHandler"; - private static final String OFFSET_PERCENTAGE = "persist.debug.one_handed_offset_percentage"; - private static final String TRANSLATE_ANIMATION_DURATION = - "persist.debug.one_handed_translate_animation_duration"; - private static final float START_TRANSITION_FRACTION = 0.7f; + private static final float START_TRANSITION_FRACTION = 0.6f; private final float mTutorialHeightRatio; private final WindowManager mWindowManager; - private final OneHandedAnimationCallback mAnimationCallback; private @OneHandedState.State int mCurrentState; private int mTutorialAreaHeight; private Context mContext; private Rect mDisplayBounds; + private ValueAnimator mAlphaAnimator; private @Nullable View mTutorialView; private @Nullable ViewGroup mTargetViewContainer; private float mAlphaTransitionStart; - private ValueAnimator mAlphaAnimator; private int mAlphaAnimationDurationMs; - public OneHandedTutorialHandler(Context context, WindowManager windowManager) { + public OneHandedTutorialHandler(Context context, OneHandedSettingsUtil settingsUtil, + WindowManager windowManager) { mContext = context; mWindowManager = windowManager; - final float offsetPercentageConfig = context.getResources().getFraction( - R.fraction.config_one_handed_offset, 1, 1); - final int sysPropPercentageConfig = SystemProperties.getInt( - OFFSET_PERCENTAGE, Math.round(offsetPercentageConfig * 100.0f)); - mTutorialHeightRatio = sysPropPercentageConfig / 100.0f; - final int animationDuration = context.getResources().getInteger( - R.integer.config_one_handed_translate_animation_duration); - mAlphaAnimationDurationMs = SystemProperties.getInt(TRANSLATE_ANIMATION_DURATION, - animationDuration); - mAnimationCallback = new OneHandedAnimationCallback() { - @Override - public void onOneHandedAnimationCancel( - OneHandedAnimationController.OneHandedTransitionAnimator animator) { - if (mAlphaAnimator != null) { - mAlphaAnimator.cancel(); - } - } + mTutorialHeightRatio = settingsUtil.getTranslationFraction(context); + mAlphaAnimationDurationMs = settingsUtil.getTransitionDuration(context); + } - @Override - public void onAnimationUpdate(float xPos, float yPos) { - if (!isAttached()) { - return; - } - if (yPos < mAlphaTransitionStart) { - checkTransitionEnd(); - return; - } - if (mAlphaAnimator == null || mAlphaAnimator.isStarted() - || mAlphaAnimator.isRunning()) { - return; - } - mAlphaAnimator.start(); - } - }; + @Override + public void onOneHandedAnimationCancel( + OneHandedAnimationController.OneHandedTransitionAnimator animator) { + if (mAlphaAnimator != null) { + mAlphaAnimator.cancel(); + } + } + + @Override + public void onAnimationUpdate(SurfaceControl.Transaction tx, float xPos, float yPos) { + if (!isAttached()) { + return; + } + if (yPos < mAlphaTransitionStart) { + checkTransitionEnd(); + return; + } + if (mAlphaAnimator == null || mAlphaAnimator.isStarted() || mAlphaAnimator.isRunning()) { + return; + } + mAlphaAnimator.start(); } @Override @@ -145,6 +133,7 @@ public class OneHandedTutorialHandler implements OneHandedTransitionCallback, /** * Called when onDisplayAdded() or onDisplayRemoved() callback. + * * @param displayLayout The latest {@link DisplayLayout} representing current displayId */ public void onDisplayChanged(DisplayLayout displayLayout) { @@ -196,10 +185,6 @@ public class OneHandedTutorialHandler implements OneHandedTransitionCallback, mTargetViewContainer = null; } - @Nullable OneHandedAnimationCallback getAnimationCallback() { - return mAnimationCallback; - } - /** * Returns layout params for the dismiss target, using the latest display metrics. */ @@ -264,15 +249,17 @@ public class OneHandedTutorialHandler implements OneHandedTransitionCallback, private void setupAlphaTransition(boolean isEntering) { final float start = isEntering ? 0.0f : 1.0f; final float end = isEntering ? 1.0f : 0.0f; + final int duration = isEntering ? mAlphaAnimationDurationMs : Math.round( + mAlphaAnimationDurationMs * (1.0f - mTutorialHeightRatio)); mAlphaAnimator = ValueAnimator.ofFloat(start, end); mAlphaAnimator.setInterpolator(new LinearInterpolator()); - mAlphaAnimator.setDuration(mAlphaAnimationDurationMs); + mAlphaAnimator.setDuration(duration); mAlphaAnimator.addUpdateListener( animator -> mTargetViewContainer.setAlpha((float) animator.getAnimatedValue())); } private void checkTransitionEnd() { - if (mAlphaAnimator != null && mAlphaAnimator.isRunning()) { + if (mAlphaAnimator != null && (mAlphaAnimator.isRunning() || mAlphaAnimator.isStarted())) { mAlphaAnimator.end(); mAlphaAnimator.removeAllUpdateListeners(); mAlphaAnimator = null; diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedBackgroundPanelOrganizerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedBackgroundPanelOrganizerTest.java index 3f47c040dd8d4..99c610765c046 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedBackgroundPanelOrganizerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedBackgroundPanelOrganizerTest.java @@ -22,7 +22,10 @@ import static android.window.DisplayAreaOrganizer.FEATURE_ONE_HANDED_BACKGROUND_ import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.reset; import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.testing.AndroidTestingRunner; @@ -54,17 +57,17 @@ public class OneHandedBackgroundPanelOrganizerTest extends OneHandedTestCase { private OneHandedBackgroundPanelOrganizer mSpiedBackgroundPanelOrganizer; private WindowContainerToken mToken; private SurfaceControl mLeash; - private TestableLooper mTestableLooper; @Mock IWindowContainerToken mMockRealToken; @Mock DisplayController mMockDisplayController; + @Mock + OneHandedSettingsUtil mMockSettingsUtil; @Before public void setUp() { MockitoAnnotations.initMocks(this); - mTestableLooper = TestableLooper.get(this); mToken = new WindowContainerToken(mMockRealToken); mLeash = new SurfaceControl(); mDisplay = mContext.getDisplay(); @@ -74,32 +77,36 @@ public class OneHandedBackgroundPanelOrganizerTest extends OneHandedTestCase { FEATURE_ONE_HANDED_BACKGROUND_PANEL); mSpiedBackgroundPanelOrganizer = spy( - new OneHandedBackgroundPanelOrganizer(mContext, mDisplayLayout, Runnable::run)); + new OneHandedBackgroundPanelOrganizer(mContext, mDisplayLayout, mMockSettingsUtil, + Runnable::run)); + mSpiedBackgroundPanelOrganizer.onDisplayChanged(mDisplayLayout); } @Test public void testOnDisplayAreaAppeared() { mSpiedBackgroundPanelOrganizer.onDisplayAreaAppeared(mDisplayAreaInfo, mLeash); - mTestableLooper.processAllMessages(); - assertThat(mSpiedBackgroundPanelOrganizer.getBackgroundSurface()).isNotNull(); + assertThat(mSpiedBackgroundPanelOrganizer.isRegistered()).isTrue(); + verify(mSpiedBackgroundPanelOrganizer, never()).showBackgroundPanelLayer(); } @Test public void testShowBackgroundLayer() { - mSpiedBackgroundPanelOrganizer.onDisplayAreaAppeared(mDisplayAreaInfo, mLeash); - mSpiedBackgroundPanelOrganizer.showBackgroundPanelLayer(); - mTestableLooper.processAllMessages(); + mSpiedBackgroundPanelOrganizer.onDisplayAreaAppeared(mDisplayAreaInfo, null); + mSpiedBackgroundPanelOrganizer.onStart(); - assertThat(mSpiedBackgroundPanelOrganizer.mIsShowing).isTrue(); + verify(mSpiedBackgroundPanelOrganizer).showBackgroundPanelLayer(); } @Test public void testRemoveBackgroundLayer() { mSpiedBackgroundPanelOrganizer.onDisplayAreaAppeared(mDisplayAreaInfo, mLeash); - mSpiedBackgroundPanelOrganizer.removeBackgroundPanelLayer(); - mTestableLooper.processAllMessages(); - assertThat(mSpiedBackgroundPanelOrganizer.mIsShowing).isFalse(); + assertThat(mSpiedBackgroundPanelOrganizer.isRegistered()).isNotNull(); + + reset(mSpiedBackgroundPanelOrganizer); + mSpiedBackgroundPanelOrganizer.removeBackgroundPanelLayer(); + + assertThat(mSpiedBackgroundPanelOrganizer.mBackgroundSurface).isNull(); } } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java index b224ae6a19b53..911fe0753845b 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java @@ -110,7 +110,7 @@ public class OneHandedControllerTest extends OneHandedTestCase { when(mMockDisplayController.getDisplay(anyInt())).thenReturn(mDisplay); when(mMockDisplayAreaOrganizer.getDisplayAreaTokenMap()).thenReturn(new ArrayMap<>()); when(mMockDisplayAreaOrganizer.isReady()).thenReturn(true); - when(mMockBackgroundOrganizer.getBackgroundSurface()).thenReturn(mMockLeash); + when(mMockBackgroundOrganizer.isRegistered()).thenReturn(true); when(mMockSettingsUitl.getSettingsOneHandedModeEnabled(any(), anyInt())).thenReturn( mDefaultEnabled); when(mMockSettingsUitl.getSettingsOneHandedModeTimeout(any(), anyInt())).thenReturn( diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedStateTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedStateTest.java index e61f0617852ad..bea69c5d80ef7 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedStateTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedStateTest.java @@ -102,7 +102,7 @@ public class OneHandedStateTest extends OneHandedTestCase { when(mMockDisplayController.getDisplay(anyInt())).thenReturn(mDisplay); when(mMockDisplayAreaOrganizer.getDisplayAreaTokenMap()).thenReturn(new ArrayMap<>()); - when(mMockBackgroundOrganizer.getBackgroundSurface()).thenReturn(mMockLeash); + when(mMockBackgroundOrganizer.isRegistered()).thenReturn(true); when(mMockSettingsUitl.getSettingsOneHandedModeEnabled(any(), anyInt())).thenReturn( mDefaultEnabled); when(mMockSettingsUitl.getSettingsOneHandedModeTimeout(any(), anyInt())).thenReturn( 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 ae1d3b2a4c41b..b1434ca325b73 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 @@ -66,7 +66,7 @@ public class OneHandedTutorialHandlerTest extends OneHandedTestCase { mDisplayLayout = new DisplayLayout(mContext, mDisplay); mSpiedTransitionState = spy(new OneHandedState()); mSpiedTutorialHandler = spy( - new OneHandedTutorialHandler(mContext, mMockWindowManager)); + new OneHandedTutorialHandler(mContext, mMockSettingsUtil, mMockWindowManager)); mTimeoutHandler = new OneHandedTimeoutHandler(mMockShellMainExecutor); }