Merge "Fix tutorial background color not up-to-date occasionally" into sc-dev

This commit is contained in:
Jason Chang
2021-07-27 16:00:30 +00:00
committed by Android (Google) Code Review
11 changed files with 235 additions and 199 deletions

View File

@@ -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) {
}
}

View File

@@ -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) {

View File

@@ -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<DisplayAreaAppearedInfo> registerOrganizer(int displayAreaFeature) {
synchronized (mLock) {
final List<DisplayAreaAppearedInfo> 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<DisplayAreaAppearedInfo> 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);
}
}

View File

@@ -180,6 +180,7 @@ public class OneHandedController implements RemoteCallable<OneHandedController>
public void onStopFinished(Rect bounds) {
mState.setState(STATE_NONE);
notifyShortcutStateChanged(STATE_NONE);
mBackgroundPanelOrganizer.onStopFinished();
}
};
@@ -223,13 +224,14 @@ public class OneHandedController implements RemoteCallable<OneHandedController>
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<OneHandedController>
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<OneHandedController>
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<OneHandedController>
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<OneHandedController>
OneHandedDisplayAreaOrganizer.FEATURE_ONE_HANDED);
}
if (mBackgroundPanelOrganizer.getBackgroundSurface() == null) {
if (!mBackgroundPanelOrganizer.isRegistered()) {
mBackgroundPanelOrganizer.registerOrganizer(
OneHandedBackgroundPanelOrganizer.FEATURE_ONE_HANDED_BACKGROUND_PANEL);
}

View File

@@ -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 {

View File

@@ -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 = " ";

View File

@@ -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;

View File

@@ -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();
}
}

View File

@@ -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(

View File

@@ -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(

View File

@@ -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);
}