summaryrefslogtreecommitdiff
path: root/libs/WindowManager/Shell
diff options
context:
space:
mode:
Diffstat (limited to 'libs/WindowManager/Shell')
-rw-r--r--libs/WindowManager/Shell/res/color/one_handed_tutorial_background_color.xml21
-rw-r--r--libs/WindowManager/Shell/res/drawable-hdpi/one_handed_tutorial.pngbin1766 -> 0 bytes
-rw-r--r--libs/WindowManager/Shell/res/drawable/one_handed_tutorial_icon.xml14
-rw-r--r--libs/WindowManager/Shell/res/layout/one_handed_tutorial.xml7
-rw-r--r--libs/WindowManager/Shell/res/values/config.xml3
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java18
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedAnimationController.java8
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedBackgroundPanelOrganizer.java37
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java3
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedTutorialHandler.java156
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java55
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java72
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java7
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java20
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenIconDrawableFactory.java68
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedTutorialHandlerTest.java21
16 files changed, 363 insertions, 147 deletions
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 000000000000..4f56e0f023a4
--- /dev/null
+++ b/libs/WindowManager/Shell/res/color/one_handed_tutorial_background_color.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
+ <item android:color="?androidprv:attr/colorSurfaceVariant"/>
+</selector>
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 6c1f1cfdea7c..000000000000
--- a/libs/WindowManager/Shell/res/drawable-hdpi/one_handed_tutorial.png
+++ /dev/null
Binary files 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 000000000000..b32f34ef7c58
--- /dev/null
+++ b/libs/WindowManager/Shell/res/drawable/one_handed_tutorial_icon.xml
@@ -0,0 +1,14 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="32dp"
+ android:height="60dp"
+ android:viewportWidth="32"
+ android:viewportHeight="60">
+ <path
+ android:pathData="M1.9703,30.5041C1.9703,28.295 3.7612,26.5042 5.9703,26.5042H25.5551C27.7642,26.5042 29.5551,28.295 29.5551,30.5042V54.0296C29.5551,56.2387 27.7642,58.0296 25.5551,58.0296H5.9703C3.7612,58.0296 1.9703,56.2387 1.9703,54.0296V30.5041Z"
+ android:fillColor="#000000"
+ android:fillAlpha="0.16"/>
+ <path
+ android:pathData="M25.5254,2H6C3.7909,2 2,3.7909 2,6V54C2,56.2091 3.7909,58 6,58H25.5254C27.7346,58 29.5254,56.2091 29.5254,54V6C29.5254,3.7909 27.7346,2 25.5254,2ZM6,0C2.6863,0 0,2.6863 0,6V54C0,57.3137 2.6863,60 6,60H25.5254C28.8391,60 31.5254,57.3137 31.5254,54V6C31.5254,2.6863 28.8391,0 25.5254,0H6ZM12.2034,47.2336L12.8307,47.861L15.3178,45.3783V52.1277H16.2076V45.3783L18.6903,47.8654L19.322,47.2336L15.7627,43.6743L12.2034,47.2336ZM19.7034,55.0742H11.822V56.552H19.7034V55.0742Z"
+ android:fillColor="#000000"
+ android:fillType="evenOdd"/>
+</vector>
diff --git a/libs/WindowManager/Shell/res/layout/one_handed_tutorial.xml b/libs/WindowManager/Shell/res/layout/one_handed_tutorial.xml
index 0190aad2d0ef..d29ed8b5a9ec 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" />
<TextView
@@ -45,7 +45,6 @@
android:fontFamily="google-sans-medium"
android:text="@string/one_handed_tutorial_title"
android:textSize="16sp"
- android:textStyle="bold"
android:textColor="@android:color/white"/>
<TextView
@@ -54,8 +53,8 @@
android:layout_height="wrap_content"
android:layout_marginTop="6dp"
android:layout_marginBottom="0dp"
- android:layout_marginStart="46dp"
- android:layout_marginEnd="46dp"
+ android:layout_marginStart="60dp"
+ android:layout_marginEnd="60dp"
android:gravity="center_horizontal"
android:fontFamily="roboto-regular"
android:text="@string/one_handed_tutorial_description"
diff --git a/libs/WindowManager/Shell/res/values/config.xml b/libs/WindowManager/Shell/res/values/config.xml
index 8cea869aea34..d0e4f7a02ffc 100644
--- a/libs/WindowManager/Shell/res/values/config.xml
+++ b/libs/WindowManager/Shell/res/values/config.xml
@@ -36,6 +36,9 @@
<!-- Allow PIP to resize via dragging the corner of PiP. -->
<bool name="config_pipEnableDragCornerResize">false</bool>
+ <!-- PiP minimum size, which is a % based off the shorter side of display width and height -->
+ <fraction name="config_pipShortestEdgePercent">40%</fraction>
+
<!-- Animation duration when using long press on recents to dock -->
<integer name="long_press_dock_anim_duration">250</integer>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
index 92e455ce4e3a..c0df06f2954f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
@@ -45,6 +45,7 @@ import android.view.Choreographer;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.SurfaceControl;
+import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.ViewGroup;
@@ -205,6 +206,7 @@ public class BubbleStackView extends FrameLayout
* between bubble activities without needing both to be alive at the same time.
*/
private SurfaceView mAnimatingOutSurfaceView;
+ private boolean mAnimatingOutSurfaceReady;
/** Container for the animating-out SurfaceView. */
private FrameLayout mAnimatingOutSurfaceContainer;
@@ -811,6 +813,20 @@ public class BubbleStackView extends FrameLayout
mAnimatingOutSurfaceView.setZOrderOnTop(true);
mAnimatingOutSurfaceView.setCornerRadius(mCornerRadius);
mAnimatingOutSurfaceView.setLayoutParams(new ViewGroup.LayoutParams(0, 0));
+ mAnimatingOutSurfaceView.getHolder().addCallback(new SurfaceHolder.Callback() {
+ @Override
+ public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) {}
+
+ @Override
+ public void surfaceCreated(SurfaceHolder surfaceHolder) {
+ mAnimatingOutSurfaceReady = true;
+ }
+
+ @Override
+ public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
+ mAnimatingOutSurfaceReady = false;
+ }
+ });
mAnimatingOutSurfaceContainer.addView(mAnimatingOutSurfaceView);
mAnimatingOutSurfaceContainer.setPadding(
@@ -2653,7 +2669,7 @@ public class BubbleStackView extends FrameLayout
return;
}
- if (!mIsExpanded) {
+ if (!mIsExpanded || !mAnimatingOutSurfaceReady) {
onComplete.accept(false);
return;
}
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 1ae263624186..bfb2cc6a8fc5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedAnimationController.java
@@ -163,6 +163,7 @@ public class OneHandedAnimationController {
mOneHandedAnimationCallbacks.forEach(
(callback) -> callback.onOneHandedAnimationEnd(tx, this)
);
+ mOneHandedAnimationCallbacks.clear();
}
@Override
@@ -171,6 +172,7 @@ public class OneHandedAnimationController {
mOneHandedAnimationCallbacks.forEach(
(callback) -> callback.onOneHandedAnimationCancel(this)
);
+ mOneHandedAnimationCallbacks.clear();
}
@Override
@@ -182,7 +184,7 @@ public class OneHandedAnimationController {
final SurfaceControl.Transaction tx = newSurfaceControlTransaction();
applySurfaceControlTransaction(mLeash, tx, animation.getAnimatedFraction());
mOneHandedAnimationCallbacks.forEach(
- (callback) -> callback.onAnimationUpdate(0f, (float) mCurrentValue)
+ (callback) -> callback.onAnimationUpdate(0f, mCurrentValue)
);
}
@@ -216,7 +218,7 @@ public class OneHandedAnimationController {
}
float getDestinationOffset() {
- return ((float) mEndValue - (float) mStartValue);
+ return (mEndValue - mStartValue);
}
@TransitionDirection
@@ -302,7 +304,7 @@ public class OneHandedAnimationController {
@Override
public float getInterpolation(float input) {
return (float) (Math.pow(2, -10 * input) * Math.sin(((input - 4.0f) / 4.0f)
- * (2.0f * Math.PI) / 4.0f) + 1);
+ * (2.0f * Math.PI) / 4.0f) + 1.0f);
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedBackgroundPanelOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedBackgroundPanelOrganizer.java
index 481b94817385..3ccb9e7570d5 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
@@ -20,7 +20,6 @@ import android.content.Context;
import android.graphics.Color;
import android.graphics.PixelFormat;
import android.graphics.Rect;
-import android.util.Log;
import android.view.SurfaceControl;
import android.view.SurfaceSession;
import android.window.DisplayAreaAppearedInfo;
@@ -30,7 +29,6 @@ import android.window.DisplayAreaOrganizer;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
-import androidx.core.content.ContextCompat;
import com.android.internal.annotations.GuardedBy;
import com.android.wm.shell.R;
@@ -48,14 +46,17 @@ import java.util.concurrent.Executor;
public class OneHandedBackgroundPanelOrganizer extends DisplayAreaOrganizer
implements OneHandedTransitionCallback {
private static final String TAG = "OneHandedBackgroundPanelOrganizer";
+ private static final int THEME_COLOR_OFFSET = 10;
+ private final Context mContext;
private final Object mLock = new Object();
private final SurfaceSession mSurfaceSession = new SurfaceSession();
- private final float[] mDefaultColor;
private final Executor mMainExecutor;
private final OneHandedSurfaceTransactionHelper.SurfaceControlTransactionFactory
mSurfaceControlTransactionFactory;
+ private float[] mDefaultColor;
+
/**
* The background to distinguish the boundary of translated windows and empty region when
* one handed mode triggered.
@@ -88,15 +89,14 @@ public class OneHandedBackgroundPanelOrganizer extends DisplayAreaOrganizer
public OneHandedBackgroundPanelOrganizer(Context context, DisplayLayout displayLayout,
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());
}
- 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 2038cff4a966..09cde38a0cfc 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<OneHandedController>
}
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 0f6c4b081cb7..97e04b5a7abd 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedTutorialHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedTutorialHandler.java
@@ -16,6 +16,8 @@
package com.android.wm.shell.onehanded;
+import static android.view.View.LAYER_TYPE_HARDWARE;
+import static android.view.View.LAYER_TYPE_NONE;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
import static com.android.wm.shell.onehanded.OneHandedState.STATE_ACTIVE;
@@ -23,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;
@@ -33,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;
@@ -45,20 +54,21 @@ import java.io.PrintWriter;
/**
* Handles tutorial visibility and synchronized transition for One Handed operations,
- * TargetViewContainer only be created and attach to window when
- * shown counts < {@link MAX_TUTORIAL_SHOW_COUNT}, and detach TargetViewContainer from window
- * after exiting one handed mode.
+ * TargetViewContainer only be created and always attach to window,
+ * detach TargetViewContainer from window after exiting one handed mode.
*/
public class OneHandedTutorialHandler implements OneHandedTransitionCallback,
OneHandedState.OnStateChangedListener {
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 boolean mIsShowing;
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,16 +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 (!isShowing()) {
+ if (!isAttached()) {
return;
}
- mTargetViewContainer.setTransitionGroup(true);
- mTargetViewContainer.setTranslationY(yPos - mTargetViewContainer.getHeight());
+ if (yPos < mAlphaTransitionStart) {
+ checkTransitionEnd();
+ return;
+ }
+ if (mAlphaAnimator == null || mAlphaAnimator.isStarted()
+ || mAlphaAnimator.isRunning()) {
+ return;
+ }
+ mAlphaAnimator.start();
}
};
}
@@ -95,13 +126,17 @@ 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:
- removeTutorialFromWindowManager(true /* increment */);
+ checkTransitionEnd();
+ removeTutorialFromWindowManager();
break;
default:
break;
@@ -120,17 +155,20 @@ 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
void createViewAndAttachToWindow(Context context) {
- if (isShowing()) {
+ if (isAttached()) {
return;
}
mTutorialView = LayoutInflater.from(context).inflate(R.layout.one_handed_tutorial, null);
mTargetViewContainer = new FrameLayout(context);
mTargetViewContainer.setClipChildren(false);
+ mTargetViewContainer.setAlpha(mCurrentState == STATE_ACTIVE ? 1.0f : 0.0f);
mTargetViewContainer.addView(mTutorialView);
+ mTargetViewContainer.setLayerType(LAYER_TYPE_HARDWARE, null);
attachTargetToWindow();
}
@@ -139,29 +177,27 @@ public class OneHandedTutorialHandler implements OneHandedTransitionCallback,
* Adds the tutorial target view to the WindowManager and update its layout.
*/
private void attachTargetToWindow() {
- if (!mTargetViewContainer.isAttachedToWindow()) {
- try {
- mWindowManager.addView(mTargetViewContainer, getTutorialTargetLayoutParams());
- mIsShowing = true;
- } catch (IllegalStateException e) {
- // This shouldn't happen, but if the target is already added, just update its
- // layout params.
- mWindowManager.updateViewLayout(
- mTargetViewContainer, getTutorialTargetLayoutParams());
- }
+ try {
+ mWindowManager.addView(mTargetViewContainer, getTutorialTargetLayoutParams());
+ } catch (IllegalStateException e) {
+ // This shouldn't happen, but if the target is already added, just update its
+ // layout params.
+ mWindowManager.updateViewLayout(mTargetViewContainer, getTutorialTargetLayoutParams());
}
}
@VisibleForTesting
- void removeTutorialFromWindowManager(boolean increment) {
- if (mTargetViewContainer != null && mTargetViewContainer.isAttachedToWindow()) {
- mWindowManager.removeViewImmediate(mTargetViewContainer);
- mIsShowing = false;
+ void removeTutorialFromWindowManager() {
+ if (!isAttached()) {
+ return;
}
+ mTargetViewContainer.setLayerType(LAYER_TYPE_NONE, null);
+ mWindowManager.removeViewImmediate(mTargetViewContainer);
+ mTargetViewContainer = null;
}
@Nullable OneHandedAnimationCallback getAnimationCallback() {
- return isShowing() ? mAnimationCallback : null /* Disabled */;
+ return mAnimationCallback;
}
/**
@@ -183,30 +219,80 @@ public class OneHandedTutorialHandler implements OneHandedTransitionCallback,
}
@VisibleForTesting
- boolean isShowing() {
- return mIsShowing;
+ boolean isAttached() {
+ return mTargetViewContainer != null && mTargetViewContainer.isAttachedToWindow();
}
/**
* onConfigurationChanged events for updating tutorial text.
*/
public void onConfigurationChanged() {
- removeTutorialFromWindowManager(false /* increment */);
+ removeTutorialFromWindowManager();
if (mCurrentState == STATE_ENTERING || mCurrentState == STATE_ACTIVE) {
createViewAndAttachToWindow(mContext);
+ 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;
}
}
void dump(@NonNull PrintWriter pw) {
final String innerPrefix = " ";
pw.println(TAG);
- pw.print(innerPrefix + "mIsShowing=");
- pw.println(mIsShowing);
+ pw.print(innerPrefix + "isAttached=");
+ pw.println(isAttached());
pw.print(innerPrefix + "mCurrentState=");
pw.println(mCurrentState);
pw.print(innerPrefix + "mDisplayBounds=");
pw.println(mDisplayBounds);
pw.print(innerPrefix + "mTutorialAreaHeight=");
pw.println(mTutorialAreaHeight);
+ pw.print(innerPrefix + "mAlphaTransitionStart=");
+ pw.println(mAlphaTransitionStart);
+ pw.print(innerPrefix + "mAlphaAnimationDurationMs=");
+ pw.println(mAlphaAnimationDurationMs);
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java
index c46b5590bab6..200af7415eb1 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java
@@ -26,10 +26,14 @@ import android.animation.RectEvaluator;
import android.animation.ValueAnimator;
import android.annotation.IntDef;
import android.app.TaskInfo;
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Color;
import android.graphics.Rect;
import android.view.Choreographer;
import android.view.Surface;
import android.view.SurfaceControl;
+import android.view.SurfaceSession;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
@@ -253,6 +257,7 @@ public class PipAnimationController {
mSurfaceControlTransactionFactory;
private PipSurfaceTransactionHelper mSurfaceTransactionHelper;
private @TransitionDirection int mTransitionDirection;
+ protected SurfaceControl mContentOverlay;
private PipTransitionAnimator(TaskInfo taskInfo, SurfaceControl leash,
@AnimationType int animationType, Rect destinationBounds, T baseValue, T startValue,
@@ -331,6 +336,53 @@ public class PipAnimationController {
return false;
}
+ SurfaceControl getContentOverlay() {
+ return mContentOverlay;
+ }
+
+ PipTransitionAnimator<T> setUseContentOverlay(Context context) {
+ final SurfaceControl.Transaction tx = newSurfaceControlTransaction();
+ if (mContentOverlay != null) {
+ // remove existing content overlay if there is any.
+ tx.remove(mContentOverlay);
+ tx.apply();
+ }
+ mContentOverlay = new SurfaceControl.Builder(new SurfaceSession())
+ .setCallsite("PipAnimation")
+ .setName("PipContentOverlay")
+ .setColorLayer()
+ .build();
+ tx.show(mContentOverlay);
+ tx.setLayer(mContentOverlay, Integer.MAX_VALUE);
+ tx.setColor(mContentOverlay, getContentOverlayColor(context));
+ tx.setAlpha(mContentOverlay, 0f);
+ tx.reparent(mContentOverlay, mLeash);
+ tx.apply();
+ return this;
+ }
+
+ private float[] getContentOverlayColor(Context context) {
+ final TypedArray ta = context.obtainStyledAttributes(new int[] {
+ android.R.attr.colorBackground });
+ try {
+ int colorAccent = ta.getColor(0, 0);
+ return new float[] {
+ Color.red(colorAccent) / 255f,
+ Color.green(colorAccent) / 255f,
+ Color.blue(colorAccent) / 255f };
+ } finally {
+ ta.recycle();
+ }
+ }
+
+ /**
+ * Clears the {@link #mContentOverlay}, this should be done after the content overlay is
+ * faded out, such as in {@link PipTaskOrganizer#fadeOutAndRemoveOverlay}
+ */
+ void clearContentOverlay() {
+ mContentOverlay = null;
+ }
+
@VisibleForTesting
@TransitionDirection public int getTransitionDirection() {
return mTransitionDirection;
@@ -517,6 +569,9 @@ public class PipAnimationController {
final Rect base = getBaseValue();
final Rect start = getStartValue();
final Rect end = getEndValue();
+ if (mContentOverlay != null) {
+ tx.setAlpha(mContentOverlay, fraction < 0.5f ? 0 : (fraction - 0.5f) * 2);
+ }
if (rotatedEndRect != null) {
// Animate the bounds in a different orientation. It only happens when
// switching between PiP and fullscreen.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
index f367cd608f37..5a506193b8a1 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
@@ -107,6 +107,13 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
*/
private static final int ONE_SHOT_ALPHA_ANIMATION_TIMEOUT_MS = 1000;
+ /**
+ * The fixed start delay in ms when fading out the content overlay from bounds animation.
+ * This is to overcome the flicker caused by configuration change when rotating from landscape
+ * to portrait PiP in button navigation mode.
+ */
+ private static final int CONTENT_OVERLAY_FADE_OUT_DELAY_MS = 500;
+
// Not a complete set of states but serves what we want right now.
private enum State {
UNDEFINED(0),
@@ -176,6 +183,10 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
final int direction = animator.getTransitionDirection();
final int animationType = animator.getAnimationType();
final Rect destinationBounds = animator.getDestinationBounds();
+ if (isInPipDirection(direction) && animator.getContentOverlay() != null) {
+ fadeOutAndRemoveOverlay(animator.getContentOverlay(),
+ animator::clearContentOverlay, true /* withStartDelay*/);
+ }
if (mWaitForFixedRotation && animationType == ANIM_TYPE_BOUNDS
&& direction == TRANSITION_DIRECTION_TO_PIP) {
// Notify the display to continue the deferred orientation change.
@@ -199,17 +210,17 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
finishResize(tx, destinationBounds, direction, animationType);
sendOnPipTransitionFinished(direction);
}
- if (direction == TRANSITION_DIRECTION_TO_PIP) {
- // TODO (b//169221267): Add jank listener for transactions without buffer updates.
- //InteractionJankMonitor.getInstance().end(
- // InteractionJankMonitor.CUJ_LAUNCHER_APP_CLOSE_TO_PIP);
- }
}
@Override
public void onPipAnimationCancel(TaskInfo taskInfo,
PipAnimationController.PipTransitionAnimator animator) {
- sendOnPipTransitionCancelled(animator.getTransitionDirection());
+ final int direction = animator.getTransitionDirection();
+ if (isInPipDirection(direction) && animator.getContentOverlay() != null) {
+ fadeOutAndRemoveOverlay(animator.getContentOverlay(),
+ animator::clearContentOverlay, true /* withStartDelay */);
+ }
+ sendOnPipTransitionCancelled(direction);
}
};
@@ -640,7 +651,8 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
// Remove the swipe to home overlay
if (swipeToHomeOverlay != null) {
- fadeOutAndRemoveOverlay(swipeToHomeOverlay);
+ fadeOutAndRemoveOverlay(swipeToHomeOverlay,
+ null /* callback */, false /* withStartDelay */);
}
}, tx);
mInSwipePipToHomeTransition = false;
@@ -723,9 +735,12 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
mOnDisplayIdChangeCallback.accept(Display.DEFAULT_DISPLAY);
}
- final PipAnimationController.PipTransitionAnimator animator =
+ final PipAnimationController.PipTransitionAnimator<?> animator =
mPipAnimationController.getCurrentAnimator();
if (animator != null) {
+ if (animator.getContentOverlay() != null) {
+ removeContentOverlay(animator.getContentOverlay(), animator::clearContentOverlay);
+ }
animator.removeAllUpdateListeners();
animator.removeAllListeners();
animator.cancel();
@@ -1196,7 +1211,8 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
snapshotDest);
// Start animation to fade out the snapshot.
- fadeOutAndRemoveOverlay(snapshotSurface);
+ fadeOutAndRemoveOverlay(snapshotSurface,
+ null /* callback */, false /* withStartDelay */);
});
} else {
applyFinishBoundsResize(wct, direction);
@@ -1287,15 +1303,20 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
animator.setTransitionDirection(direction)
.setPipAnimationCallback(mPipAnimationCallback)
.setPipTransactionHandler(mPipTransactionHandler)
- .setDuration(durationMs)
- .start();
- if (rotationDelta != Surface.ROTATION_0 && direction == TRANSITION_DIRECTION_TO_PIP) {
+ .setDuration(durationMs);
+ if (isInPipDirection(direction)) {
+ // Similar to auto-enter-pip transition, we use content overlay when there is no
+ // source rect hint to enter PiP use bounds animation.
+ if (sourceHintRect == null) animator.setUseContentOverlay(mContext);
// The destination bounds are used for the end rect of animation and the final bounds
// after animation finishes. So after the animation is started, the destination bounds
// can be updated to new rotation (computeRotatedBounds has changed the DisplayLayout
// without affecting the animation.
- animator.setDestinationBounds(mPipBoundsAlgorithm.getEntryDestinationBounds());
+ if (rotationDelta != Surface.ROTATION_0) {
+ animator.setDestinationBounds(mPipBoundsAlgorithm.getEntryDestinationBounds());
+ }
}
+ animator.start();
return animator;
}
@@ -1308,6 +1329,14 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
outDestinationBounds.set(mPipBoundsAlgorithm.getEntryDestinationBounds());
// Transform the destination bounds to current display coordinates.
rotateBounds(outDestinationBounds, displayBounds, mNextRotation, mCurrentRotation);
+ // When entering PiP (from button navigation mode), adjust the source rect hint by
+ // display cutout if applicable.
+ if (sourceHintRect != null && mTaskInfo.displayCutoutInsets != null) {
+ if (rotationDelta == Surface.ROTATION_270) {
+ sourceHintRect.offset(mTaskInfo.displayCutoutInsets.left,
+ mTaskInfo.displayCutoutInsets.top);
+ }
+ }
} else if (direction == TRANSITION_DIRECTION_LEAVE_PIP) {
final Rect rotatedDestinationBounds = new Rect(outDestinationBounds);
rotateBounds(rotatedDestinationBounds, mPipBoundsState.getDisplayBounds(),
@@ -1346,7 +1375,8 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
/**
* Fades out and removes an overlay surface.
*/
- private void fadeOutAndRemoveOverlay(SurfaceControl surface) {
+ private void fadeOutAndRemoveOverlay(SurfaceControl surface, Runnable callback,
+ boolean withStartDelay) {
if (surface == null) {
return;
}
@@ -1363,15 +1393,21 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
- final SurfaceControl.Transaction tx =
- mSurfaceControlTransactionFactory.getTransaction();
- tx.remove(surface);
- tx.apply();
+ removeContentOverlay(surface, callback);
}
});
+ animator.setStartDelay(withStartDelay ? CONTENT_OVERLAY_FADE_OUT_DELAY_MS : 0);
animator.start();
}
+ private void removeContentOverlay(SurfaceControl surface, Runnable callback) {
+ final SurfaceControl.Transaction tx =
+ mSurfaceControlTransactionFactory.getTransaction();
+ tx.remove(surface);
+ tx.apply();
+ if (callback != null) callback.run();
+ }
+
/**
* Dumps internal states.
*/
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
index 0bcd1a363eb6..7867f933de4f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
@@ -63,7 +63,6 @@ import java.io.PrintWriter;
* the PIP.
*/
public class PipTouchHandler {
- @VisibleForTesting static final float MINIMUM_SIZE_PERCENT = 0.4f;
private static final String TAG = "PipTouchHandler";
private static final float DEFAULT_STASH_VELOCITY_THRESHOLD = 18000.f;
@@ -115,6 +114,7 @@ public class PipTouchHandler {
private float mSavedSnapFraction = -1f;
private boolean mSendingHoverAccessibilityEvents;
private boolean mMovementWithinDismiss;
+ private float mMinimumSizePercent;
// Touch state
private final PipTouchState mTouchState;
@@ -252,6 +252,7 @@ public class PipTouchHandler {
mExpandedShortestEdgeSize = res.getDimensionPixelSize(
R.dimen.pip_expanded_shortest_edge_size);
mImeOffset = res.getDimensionPixelSize(R.dimen.pip_ime_offset);
+ mMinimumSizePercent = res.getFraction(R.fraction.config_pipShortestEdgePercent, 1, 1);
mPipDismissTargetHandler.updateMagneticTargetSize();
}
@@ -481,12 +482,12 @@ public class PipTouchHandler {
+ (mPipBoundsState.getDisplayBounds().height() - insetBounds.bottom);
final int minWidth, minHeight, maxWidth, maxHeight;
if (aspectRatio > 1f) {
- minWidth = (int) Math.min(normalBounds.width(), shorterLength * MINIMUM_SIZE_PERCENT);
+ minWidth = (int) Math.min(normalBounds.width(), shorterLength * mMinimumSizePercent);
minHeight = (int) (minWidth / aspectRatio);
maxWidth = (int) Math.max(normalBounds.width(), shorterLength - totalHorizontalPadding);
maxHeight = (int) (maxWidth / aspectRatio);
} else {
- minHeight = (int) Math.min(normalBounds.height(), shorterLength * MINIMUM_SIZE_PERCENT);
+ minHeight = (int) Math.min(normalBounds.height(), shorterLength * mMinimumSizePercent);
minWidth = (int) (minHeight * aspectRatio);
maxHeight = (int) Math.max(normalBounds.height(), shorterLength - totalVerticalPadding);
maxWidth = (int) (maxHeight * aspectRatio);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java
index 107a3f880354..56ad2be11853 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java
@@ -37,6 +37,7 @@ import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Rect;
import android.graphics.drawable.AdaptiveIconDrawable;
+import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
@@ -57,6 +58,7 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.graphics.palette.Palette;
import com.android.internal.graphics.palette.Quantizer;
import com.android.internal.graphics.palette.VariationalKMeansQuantizer;
+import com.android.launcher3.icons.BaseIconFactory;
import com.android.launcher3.icons.IconProvider;
import com.android.wm.shell.common.TransactionPool;
@@ -368,8 +370,14 @@ public class SplashscreenContentDrawer {
if (DEBUG) {
Slog.d(TAG, "The icon is not an AdaptiveIconDrawable");
}
- // TODO process legacy icon(bitmap)
- createIconDrawable(iconDrawable, true);
+ Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "legacy_icon_factory");
+ final ShapeIconFactory factory = new ShapeIconFactory(
+ SplashscreenContentDrawer.this.mContext,
+ scaledIconDpi, mFinalIconSize);
+ final Bitmap bitmap = factory.createScaledBitmapWithoutShadow(
+ iconDrawable, true /* shrinkNonAdaptiveIcons */);
+ Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
+ createIconDrawable(new BitmapDrawable(bitmap), true);
}
animationDuration = 0;
}
@@ -377,11 +385,15 @@ public class SplashscreenContentDrawer {
return fillViewWithIcon(mFinalIconSize, mFinalIconDrawable, animationDuration);
}
+ private class ShapeIconFactory extends BaseIconFactory {
+ protected ShapeIconFactory(Context context, int fillResIconDpi, int iconBitmapSize) {
+ super(context, fillResIconDpi, iconBitmapSize, true /* shapeDetection */);
+ }
+ }
+
private void createIconDrawable(Drawable iconDrawable, boolean legacy) {
if (legacy) {
mFinalIconDrawable = SplashscreenIconDrawableFactory.makeLegacyIconDrawable(
- mTmpAttrs.mIconBgColor != Color.TRANSPARENT
- ? mTmpAttrs.mIconBgColor : Color.WHITE,
iconDrawable, mDefaultIconSize, mFinalIconSize, mSplashscreenWorkerHandler);
} else {
mFinalIconDrawable = SplashscreenIconDrawableFactory.makeIconDrawable(
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenIconDrawableFactory.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenIconDrawableFactory.java
index 211941f44c8e..ba9123dca999 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenIconDrawableFactory.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenIconDrawableFactory.java
@@ -64,11 +64,10 @@ public class SplashscreenIconDrawableFactory {
}
}
- static Drawable makeLegacyIconDrawable(@ColorInt int backgroundColor,
- @NonNull Drawable foregroundDrawable, int srcIconSize, int iconSize,
- Handler splashscreenWorkerHandler) {
- return new ImmobileIconDrawable(new LegacyIconDrawable(backgroundColor,
- foregroundDrawable), srcIconSize, iconSize, splashscreenWorkerHandler);
+ static Drawable makeLegacyIconDrawable(@NonNull Drawable iconDrawable, int srcIconSize,
+ int iconSize, Handler splashscreenWorkerHandler) {
+ return new ImmobileIconDrawable(iconDrawable, srcIconSize, iconSize,
+ splashscreenWorkerHandler);
}
private static class ImmobileIconDrawable extends Drawable {
@@ -179,65 +178,6 @@ public class SplashscreenIconDrawableFactory {
}
}
- private static class LegacyIconDrawable extends MaskBackgroundDrawable {
- // reference FixedScaleDrawable
- // iconBounds = 0.7 * X * outerBounds, X is the scale of diagonal
- private static final float LEGACY_ICON_SCALE = .7f * .8f;
- private final Drawable mForegroundDrawable;
- private float mScaleX, mScaleY, mTransX, mTransY;
-
- LegacyIconDrawable(@ColorInt int backgroundColor, Drawable foregroundDrawable) {
- super(backgroundColor);
- mForegroundDrawable = foregroundDrawable;
- mScaleX = LEGACY_ICON_SCALE;
- mScaleY = LEGACY_ICON_SCALE;
- }
-
- @Override
- protected void updateLayerBounds(Rect bounds) {
- super.updateLayerBounds(bounds);
-
- if (mForegroundDrawable == null) {
- return;
- }
- float outerBoundsWidth = bounds.width();
- float outerBoundsHeight = bounds.height();
- float h = mForegroundDrawable.getIntrinsicHeight();
- float w = mForegroundDrawable.getIntrinsicWidth();
- mScaleX = LEGACY_ICON_SCALE;
- mScaleY = LEGACY_ICON_SCALE;
- if (h > w && w > 0) {
- mScaleX *= w / h;
- } else if (w > h && h > 0) {
- mScaleY *= h / w;
- }
- int innerBoundsWidth = (int) (0.5 + outerBoundsWidth * mScaleX);
- int innerBoundsHeight = (int) (0.5 + outerBoundsHeight * mScaleY);
- final Rect rect = new Rect(0, 0, innerBoundsWidth, innerBoundsHeight);
- mForegroundDrawable.setBounds(rect);
- mTransX = (outerBoundsWidth - innerBoundsWidth) / 2;
- mTransY = (outerBoundsHeight - innerBoundsHeight) / 2;
- invalidateSelf();
- }
-
- @Override
- public void draw(Canvas canvas) {
- super.draw(canvas);
- int saveCount = canvas.save();
- canvas.translate(mTransX, mTransY);
- if (mForegroundDrawable != null) {
- mForegroundDrawable.draw(canvas);
- }
- canvas.restoreToCount(saveCount);
- }
-
- @Override
- public void setColorFilter(ColorFilter colorFilter) {
- if (mForegroundDrawable != null) {
- mForegroundDrawable.setColorFilter(colorFilter);
- }
- }
- }
/**
* A lightweight AdaptiveIconDrawable which support foreground to be Animatable, and keep this
* drawable masked by config_icon_mask.
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 25bdb8ef9263..ae1d3b2a4c41 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedTutorialHandlerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedTutorialHandlerTest.java
@@ -77,7 +77,7 @@ public class OneHandedTutorialHandlerTest extends OneHandedTestCase {
@Test
public void testOnStateChangedEntering_createViewAndAttachToWindow() {
- when(mSpiedTutorialHandler.isShowing()).thenReturn(true);
+ when(mSpiedTutorialHandler.isAttached()).thenReturn(true);
try {
mSpiedTutorialHandler.onStateChanged(STATE_ENTERING);
} catch (ClassCastException e) {
@@ -89,23 +89,27 @@ public class OneHandedTutorialHandlerTest extends OneHandedTestCase {
@Test
public void testOnStateChangedNone_removeViewAndAttachToWindow() {
- when(mSpiedTutorialHandler.isShowing()).thenReturn(true);
+ when(mSpiedTutorialHandler.isAttached()).thenReturn(true);
try {
mSpiedTutorialHandler.onStateChanged(STATE_NONE);
} catch (ClassCastException e) {
// no-op, just assert removeTutorialFromWindowManager() to be called
+ } catch (NullPointerException e) {
+ // no-op, just assert removeTutorialFromWindowManager() to be called
}
- verify(mSpiedTutorialHandler).removeTutorialFromWindowManager(true);
+ verify(mSpiedTutorialHandler).removeTutorialFromWindowManager();
}
@Test
public void testOnStateChangedNone_shouldNotAttachWindow() {
- when(mSpiedTutorialHandler.isShowing()).thenReturn(true);
+ when(mSpiedTutorialHandler.isAttached()).thenReturn(true);
try {
mSpiedTutorialHandler.onStateChanged(STATE_NONE);
} catch (ClassCastException e) {
// no-op, just assert setTutorialShownCountIncrement() never be called
+ } catch (NullPointerException e) {
+ // no-op, just assert setTutorialShownCountIncrement() never be called
}
verify(mSpiedTutorialHandler, never()).createViewAndAttachToWindow(any());
@@ -113,7 +117,7 @@ public class OneHandedTutorialHandlerTest extends OneHandedTestCase {
@Test
public void testOnConfigurationChanged_shouldUpdateViewContent() {
- when(mSpiedTutorialHandler.isShowing()).thenReturn(true);
+ when(mSpiedTutorialHandler.isAttached()).thenReturn(true);
try {
mSpiedTutorialHandler.onStateChanged(STATE_ENTERING);
} catch (ClassCastException e) {
@@ -122,9 +126,12 @@ public class OneHandedTutorialHandlerTest extends OneHandedTestCase {
try {
mSpiedTutorialHandler.onConfigurationChanged();
} catch (ClassCastException e) {
- // no-op, just assert removeTutorialFromWindowManager() be called
+ } catch (NullPointerException e) {
+ // no-op, just assert removeTutorialFromWindowManager() be called,
+ // and createViewAndAttachToWindow() be called twice
}
- verify(mSpiedTutorialHandler).removeTutorialFromWindowManager(false);
+ verify(mSpiedTutorialHandler).createViewAndAttachToWindow(any());
+ verify(mSpiedTutorialHandler).removeTutorialFromWindowManager();
}
}