diff --git a/libs/WindowManager/Shell/res/color/one_handed_tutorial_background_color.xml b/libs/WindowManager/Shell/res/color/one_handed_tutorial_background_color.xml new file mode 100644 index 0000000000000..4f56e0f023a42 --- /dev/null +++ b/libs/WindowManager/Shell/res/color/one_handed_tutorial_background_color.xml @@ -0,0 +1,21 @@ + + + + + + diff --git a/libs/WindowManager/Shell/res/drawable-hdpi/one_handed_tutorial.png b/libs/WindowManager/Shell/res/drawable-hdpi/one_handed_tutorial.png deleted file mode 100644 index 6c1f1cfdea7cc..0000000000000 Binary files a/libs/WindowManager/Shell/res/drawable-hdpi/one_handed_tutorial.png and /dev/null differ diff --git a/libs/WindowManager/Shell/res/drawable/one_handed_tutorial_icon.xml b/libs/WindowManager/Shell/res/drawable/one_handed_tutorial_icon.xml new file mode 100644 index 0000000000000..b32f34ef7c588 --- /dev/null +++ b/libs/WindowManager/Shell/res/drawable/one_handed_tutorial_icon.xml @@ -0,0 +1,14 @@ + + + + diff --git a/libs/WindowManager/Shell/res/layout/one_handed_tutorial.xml b/libs/WindowManager/Shell/res/layout/one_handed_tutorial.xml index 0190aad2d0ef2..d29ed8b5a9eca 100644 --- a/libs/WindowManager/Shell/res/layout/one_handed_tutorial.xml +++ b/libs/WindowManager/Shell/res/layout/one_handed_tutorial.xml @@ -31,7 +31,7 @@ android:layout_marginTop="6dp" android:layout_marginBottom="0dp" android:gravity="center_horizontal" - android:src="@drawable/one_handed_tutorial" + android:src="@drawable/one_handed_tutorial_icon" android:scaleType="centerInside" /> displayLayout.width()) { mBkgBounds = new Rect(0, 0, displayLayout.width(), displayLayout.height()); } else { mBkgBounds = new Rect(0, 0, displayLayout.height(), displayLayout.width()); } - final int defaultColor = ContextCompat.getColor(context, R.color.GM2_grey_800); - mDefaultColor = new float[]{Color.red(defaultColor) / 255.0f, - Color.green(defaultColor) / 255.0f, Color.blue(defaultColor) / 255.0f}; + updateThemeColors(); mMainExecutor = executor; mSurfaceControlTransactionFactory = SurfaceControl.Transaction::new; } @@ -170,7 +170,6 @@ public class OneHandedBackgroundPanelOrganizer extends DisplayAreaOrganizer } if (getBackgroundSurface() == null) { - Log.w(TAG, "mBackgroundSurface is null !"); return; } @@ -201,6 +200,30 @@ public class OneHandedBackgroundPanelOrganizer extends DisplayAreaOrganizer } } + /** + * onConfigurationChanged events for updating tutorial text. + */ + public void onConfigurationChanged() { + synchronized (mLock) { + if (mBackgroundSurface == null) { + getBackgroundSurface(); + } else { + removeBackgroundPanelLayer(); + } + 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}; + } + } + void dump(@NonNull PrintWriter pw) { final String innerPrefix = " "; pw.println(TAG); 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 2038cff4a9660..09cde38a0cfc9 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 @@ -658,12 +658,13 @@ public class OneHandedController implements RemoteCallable } private void onConfigChanged(Configuration newConfig) { - if (mTutorialHandler == null) { + if (mTutorialHandler == null || mBackgroundPanelOrganizer == null) { return; } if (!mIsOneHandedEnabled || newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) { return; } + mBackgroundPanelOrganizer.onConfigurationChanged(); mTutorialHandler.onConfigurationChanged(); } 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 d0206a4e3dbfd..97e04b5a7abda 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 @@ -25,8 +25,11 @@ import static com.android.wm.shell.onehanded.OneHandedState.STATE_ENTERING; import static com.android.wm.shell.onehanded.OneHandedState.STATE_EXITING; import static com.android.wm.shell.onehanded.OneHandedState.STATE_NONE; +import android.animation.ValueAnimator; import android.annotation.Nullable; import android.content.Context; +import android.content.res.ColorStateList; +import android.content.res.TypedArray; import android.graphics.PixelFormat; import android.graphics.Rect; import android.os.SystemProperties; @@ -35,9 +38,13 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.WindowManager; +import android.view.animation.LinearInterpolator; import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.TextView; import androidx.annotation.NonNull; +import androidx.appcompat.view.ContextThemeWrapper; import com.android.internal.annotations.VisibleForTesting; import com.android.wm.shell.R; @@ -53,11 +60,14 @@ import java.io.PrintWriter; public class OneHandedTutorialHandler implements OneHandedTransitionCallback, OneHandedState.OnStateChangedListener { private static final String TAG = "OneHandedTutorialHandler"; - private static final String ONE_HANDED_MODE_OFFSET_PERCENTAGE = - "persist.debug.one_handed_offset_percentage"; + 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 final float mTutorialHeightRatio; private final WindowManager mWindowManager; + private final OneHandedAnimationCallback mAnimationCallback; private @OneHandedState.State int mCurrentState; private int mTutorialAreaHeight; @@ -67,7 +77,9 @@ public class OneHandedTutorialHandler implements OneHandedTransitionCallback, private @Nullable View mTutorialView; private @Nullable ViewGroup mTargetViewContainer; - private final OneHandedAnimationCallback mAnimationCallback; + private float mAlphaTransitionStart; + private ValueAnimator mAlphaAnimator; + private int mAlphaAnimationDurationMs; public OneHandedTutorialHandler(Context context, WindowManager windowManager) { mContext = context; @@ -75,15 +87,35 @@ public class OneHandedTutorialHandler implements OneHandedTransitionCallback, final float offsetPercentageConfig = context.getResources().getFraction( R.fraction.config_one_handed_offset, 1, 1); final int sysPropPercentageConfig = SystemProperties.getInt( - ONE_HANDED_MODE_OFFSET_PERCENTAGE, Math.round(offsetPercentageConfig * 100.0f)); + 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(); + } + } + @Override public void onAnimationUpdate(float xPos, float yPos) { if (!isAttached()) { return; } - mTargetViewContainer.setTranslationY(yPos - mTutorialAreaHeight); + if (yPos < mAlphaTransitionStart) { + checkTransitionEnd(); + return; + } + if (mAlphaAnimator == null || mAlphaAnimator.isStarted() + || mAlphaAnimator.isRunning()) { + return; + } + mAlphaAnimator.start(); } }; } @@ -94,12 +126,16 @@ public class OneHandedTutorialHandler implements OneHandedTransitionCallback, switch (newState) { case STATE_ENTERING: createViewAndAttachToWindow(mContext); + updateThemeColor(); + setupAlphaTransition(true /* isEntering */); break; case STATE_ACTIVE: - case STATE_EXITING: - // no - op + checkTransitionEnd(); + setupAlphaTransition(false /* isEntering */); break; + case STATE_EXITING: case STATE_NONE: + checkTransitionEnd(); removeTutorialFromWindowManager(); break; default: @@ -119,6 +155,7 @@ public class OneHandedTutorialHandler implements OneHandedTransitionCallback, mDisplayBounds = new Rect(0, 0, displayLayout.height(), displayLayout.width()); } mTutorialAreaHeight = Math.round(mDisplayBounds.height() * mTutorialHeightRatio); + mAlphaTransitionStart = mTutorialAreaHeight * START_TRANSITION_FRACTION; } @VisibleForTesting @@ -129,6 +166,7 @@ public class OneHandedTutorialHandler implements OneHandedTransitionCallback, mTutorialView = LayoutInflater.from(context).inflate(R.layout.one_handed_tutorial, null); mTargetViewContainer = new FrameLayout(context); mTargetViewContainer.setClipChildren(false); + mTargetViewContainer.setAlpha(mCurrentState == STATE_ACTIVE ? 1.0f : 0.0f); mTargetViewContainer.addView(mTutorialView); mTargetViewContainer.setLayerType(LAYER_TYPE_HARDWARE, null); @@ -192,6 +230,52 @@ public class OneHandedTutorialHandler implements OneHandedTransitionCallback, removeTutorialFromWindowManager(); if (mCurrentState == STATE_ENTERING || mCurrentState == STATE_ACTIVE) { createViewAndAttachToWindow(mContext); + updateThemeColor(); + checkTransitionEnd(); + } + } + + private void updateThemeColor() { + if (mTutorialView == null) { + return; + } + + final Context themedContext = new ContextThemeWrapper(mTutorialView.getContext(), + com.android.internal.R.style.Theme_DeviceDefault_DayNight); + final int textColorPrimary; + final int themedTextColorSecondary; + TypedArray ta = themedContext.obtainStyledAttributes(new int[]{ + com.android.internal.R.attr.textColorPrimary, + com.android.internal.R.attr.textColorSecondary}); + textColorPrimary = ta.getColor(0, 0); + themedTextColorSecondary = ta.getColor(1, 0); + ta.recycle(); + + final ImageView iconView = mTutorialView.findViewById(R.id.one_handed_tutorial_image); + iconView.setImageTintList(ColorStateList.valueOf(textColorPrimary)); + + final TextView tutorialTitle = mTutorialView.findViewById(R.id.one_handed_tutorial_title); + final TextView tutorialDesc = mTutorialView.findViewById( + R.id.one_handed_tutorial_description); + tutorialTitle.setTextColor(textColorPrimary); + tutorialDesc.setTextColor(themedTextColorSecondary); + } + + private void setupAlphaTransition(boolean isEntering) { + final float start = isEntering ? 0.0f : 1.0f; + final float end = isEntering ? 1.0f : 0.0f; + mAlphaAnimator = ValueAnimator.ofFloat(start, end); + mAlphaAnimator.setInterpolator(new LinearInterpolator()); + mAlphaAnimator.setDuration(mAlphaAnimationDurationMs); + mAlphaAnimator.addUpdateListener( + animator -> mTargetViewContainer.setAlpha((float) animator.getAnimatedValue())); + } + + private void checkTransitionEnd() { + if (mAlphaAnimator != null && mAlphaAnimator.isRunning()) { + mAlphaAnimator.end(); + mAlphaAnimator.removeAllUpdateListeners(); + mAlphaAnimator = null; } } @@ -206,5 +290,9 @@ public class OneHandedTutorialHandler implements OneHandedTransitionCallback, pw.println(mDisplayBounds); pw.print(innerPrefix + "mTutorialAreaHeight="); pw.println(mTutorialAreaHeight); + pw.print(innerPrefix + "mAlphaTransitionStart="); + pw.println(mAlphaTransitionStart); + pw.print(innerPrefix + "mAlphaAnimationDurationMs="); + pw.println(mAlphaAnimationDurationMs); } }