Merge "Fix tutorial background color not up-to-date occasionally" into sc-dev
This commit is contained in:
@@ -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) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 = " ";
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user