diff options
Diffstat (limited to 'libs')
21 files changed, 247 insertions, 84 deletions
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 78820a8fa870..ed0e481187e1 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 @@ -912,9 +912,6 @@ public class BubbleStackView extends FrameLayout removeOnLayoutChangeListener(mOrientationChangedListener); }; - // This must be a separate OnDrawListener since it should be called for every draw. - getViewTreeObserver().addOnDrawListener(mSystemGestureExcludeUpdater); - final ColorMatrix animatedMatrix = new ColorMatrix(); final ColorMatrix darkenMatrix = new ColorMatrix(); @@ -1274,12 +1271,14 @@ public class BubbleStackView extends FrameLayout protected void onAttachedToWindow() { super.onAttachedToWindow(); getViewTreeObserver().addOnComputeInternalInsetsListener(this); + getViewTreeObserver().addOnDrawListener(mSystemGestureExcludeUpdater); } @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); getViewTreeObserver().removeOnPreDrawListener(mViewUpdater); + getViewTreeObserver().removeOnDrawListener(mSystemGestureExcludeUpdater); getViewTreeObserver().removeOnComputeInternalInsetsListener(this); if (mBubbleOverflow != null) { mBubbleOverflow.cleanUpExpandedState(); 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 37a91d0c121c..d90cc4769286 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedBackgroundPanelOrganizer.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedBackgroundPanelOrganizer.java @@ -16,17 +16,14 @@ package com.android.wm.shell.onehanded; -import static android.view.Display.DEFAULT_DISPLAY; - import android.content.Context; import android.content.res.Resources; import android.graphics.PixelFormat; -import android.graphics.Point; import android.graphics.Rect; -import android.os.Handler; import android.util.Log; import android.view.SurfaceControl; import android.view.SurfaceSession; +import android.view.WindowManager; import android.window.DisplayAreaAppearedInfo; import android.window.DisplayAreaInfo; import android.window.DisplayAreaOrganizer; @@ -57,7 +54,7 @@ public class OneHandedBackgroundPanelOrganizer extends DisplayAreaOrganizer private final float mAlpha; private final Rect mRect; private final Executor mMainExecutor; - private final Point mDisplaySize = new Point(); + private final Rect mDisplaySize; private final OneHandedSurfaceTransactionHelper.SurfaceControlTransactionFactory mSurfaceControlTransactionFactory; @@ -85,15 +82,15 @@ public class OneHandedBackgroundPanelOrganizer extends DisplayAreaOrganizer mMainExecutor.execute(() -> removeBackgroundPanelLayer()); } - public OneHandedBackgroundPanelOrganizer(Context context, DisplayController displayController, - Executor executor) { + public OneHandedBackgroundPanelOrganizer(Context context, WindowManager windowManager, + DisplayController displayController, Executor executor) { super(executor); - displayController.getDisplay(DEFAULT_DISPLAY).getRealSize(mDisplaySize); + mDisplaySize = windowManager.getCurrentWindowMetrics().getBounds(); final Resources res = context.getResources(); final float defaultRGB = res.getFloat(R.dimen.config_one_handed_background_rgb); mColor = new float[]{defaultRGB, defaultRGB, defaultRGB}; mAlpha = res.getFloat(R.dimen.config_one_handed_background_alpha); - mRect = new Rect(0, 0, mDisplaySize.x, mDisplaySize.y); + mRect = new Rect(0, 0, mDisplaySize.width(), mDisplaySize.height()); mMainExecutor = executor; mSurfaceControlTransactionFactory = SurfaceControl.Transaction::new; } 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 a1b1de3faee2..d2eb361d664d 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 @@ -17,7 +17,6 @@ package com.android.wm.shell.onehanded; import static android.os.UserHandle.USER_CURRENT; -import static android.view.Display.DEFAULT_DISPLAY; import android.content.ComponentName; import android.content.Context; @@ -25,7 +24,7 @@ import android.content.om.IOverlayManager; import android.content.om.OverlayInfo; import android.content.res.Configuration; import android.database.ContentObserver; -import android.graphics.Point; +import android.graphics.Rect; import android.os.Handler; import android.os.RemoteException; import android.os.ServiceManager; @@ -33,6 +32,7 @@ import android.os.SystemProperties; import android.provider.Settings; import android.util.Slog; import android.view.ViewConfiguration; +import android.view.WindowManager; import android.view.accessibility.AccessibilityManager; import androidx.annotation.NonNull; @@ -82,6 +82,7 @@ public class OneHandedController { private final ShellExecutor mMainExecutor; private final Handler mMainHandler; private final OneHandedImpl mImpl = new OneHandedImpl(); + private final WindowManager mWindowManager; private OneHandedDisplayAreaOrganizer mDisplayAreaOrganizer; private final AccessibilityManager mAccessibilityManager; @@ -141,7 +142,7 @@ public class OneHandedController { */ @Nullable public static OneHandedController create( - Context context, DisplayController displayController, + Context context, WindowManager windowManager, DisplayController displayController, TaskStackListenerImpl taskStackListener, UiEventLogger uiEventLogger, ShellExecutor mainExecutor, Handler mainHandler) { if (!SystemProperties.getBoolean(SUPPORT_ONE_HANDED_MODE, false)) { @@ -151,22 +152,24 @@ public class OneHandedController { OneHandedTimeoutHandler timeoutHandler = new OneHandedTimeoutHandler(mainExecutor); OneHandedTutorialHandler tutorialHandler = new OneHandedTutorialHandler(context, - mainExecutor); + windowManager, mainExecutor); OneHandedAnimationController animationController = new OneHandedAnimationController(context); OneHandedTouchHandler touchHandler = new OneHandedTouchHandler(timeoutHandler, mainExecutor); OneHandedGestureHandler gestureHandler = new OneHandedGestureHandler( - context, displayController, ViewConfiguration.get(context), mainExecutor); + context, windowManager, displayController, ViewConfiguration.get(context), + mainExecutor); OneHandedBackgroundPanelOrganizer oneHandedBackgroundPanelOrganizer = - new OneHandedBackgroundPanelOrganizer(context, displayController, mainExecutor); + new OneHandedBackgroundPanelOrganizer(context, windowManager, displayController, + mainExecutor); OneHandedDisplayAreaOrganizer organizer = new OneHandedDisplayAreaOrganizer( - context, displayController, animationController, tutorialHandler, + context, windowManager, displayController, animationController, tutorialHandler, oneHandedBackgroundPanelOrganizer, mainExecutor); OneHandedUiEventLogger oneHandedUiEventsLogger = new OneHandedUiEventLogger(uiEventLogger); IOverlayManager overlayManager = IOverlayManager.Stub.asInterface( ServiceManager.getService(Context.OVERLAY_SERVICE)); - return new OneHandedController(context, displayController, + return new OneHandedController(context, windowManager, displayController, oneHandedBackgroundPanelOrganizer, organizer, touchHandler, tutorialHandler, gestureHandler, timeoutHandler, oneHandedUiEventsLogger, overlayManager, taskStackListener, mainExecutor, mainHandler); @@ -174,6 +177,7 @@ public class OneHandedController { @VisibleForTesting OneHandedController(Context context, + WindowManager windowManager, DisplayController displayController, OneHandedBackgroundPanelOrganizer backgroundPanelOrganizer, OneHandedDisplayAreaOrganizer displayAreaOrganizer, @@ -187,6 +191,7 @@ public class OneHandedController { ShellExecutor mainExecutor, Handler mainHandler) { mContext = context; + mWindowManager = windowManager; mBackgroundPanelOrganizer = backgroundPanelOrganizer; mDisplayAreaOrganizer = displayAreaOrganizer; mDisplayController = displayController; @@ -269,7 +274,7 @@ public class OneHandedController { return; } if (!mDisplayAreaOrganizer.isInOneHanded()) { - final int yOffSet = Math.round(getDisplaySize().y * mOffSetFraction); + final int yOffSet = Math.round(getDisplaySize().height() * mOffSetFraction); mDisplayAreaOrganizer.scheduleOffset(0, yOffSet); mTimeoutHandler.resetTimer(); @@ -426,14 +431,19 @@ public class OneHandedController { } /** - * Query the current display real size from {@link DisplayController} + * Query the current display real size from {@link WindowManager} * - * @return {@link DisplayController#getDisplay(int)#getDisplaySize()} + * @return {@link WindowManager#getCurrentWindowMetrics()#getBounds()} */ - private Point getDisplaySize() { - Point displaySize = new Point(); - if (mDisplayController != null && mDisplayController.getDisplay(DEFAULT_DISPLAY) != null) { - mDisplayController.getDisplay(DEFAULT_DISPLAY).getRealSize(displaySize); + private Rect getDisplaySize() { + if (mWindowManager == null) { + Slog.e(TAG, "WindowManager instance is null! Can not get display size!"); + return new Rect(); + } + final Rect displaySize = mWindowManager.getCurrentWindowMetrics().getBounds(); + if (displaySize.width() == 0 || displaySize.height() == 0) { + Slog.e(TAG, "Display size error! width = " + displaySize.width() + + ", height = " + displaySize.height()); } return displaySize; } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java index 4c5cc226b40f..0238fa8a7936 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java @@ -16,17 +16,16 @@ package com.android.wm.shell.onehanded; -import static android.view.Display.DEFAULT_DISPLAY; - import static com.android.wm.shell.onehanded.OneHandedAnimationController.TRANSITION_DIRECTION_EXIT; import static com.android.wm.shell.onehanded.OneHandedAnimationController.TRANSITION_DIRECTION_TRIGGER; import android.content.Context; -import android.graphics.Point; import android.graphics.Rect; import android.os.SystemProperties; import android.util.ArrayMap; +import android.util.Slog; import android.view.SurfaceControl; +import android.view.WindowManager; import android.window.DisplayAreaAppearedInfo; import android.window.DisplayAreaInfo; import android.window.DisplayAreaOrganizer; @@ -60,6 +59,7 @@ public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer { private static final String ONE_HANDED_MODE_TRANSLATE_ANIMATION_DURATION = "persist.debug.one_handed_translate_animation_duration"; + private final WindowManager mWindowManager; private final Rect mLastVisualDisplayBounds = new Rect(); private final Rect mDefaultDisplayBounds = new Rect(); @@ -110,12 +110,14 @@ public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer { * Constructor of OneHandedDisplayAreaOrganizer */ public OneHandedDisplayAreaOrganizer(Context context, + WindowManager windowManager, DisplayController displayController, OneHandedAnimationController animationController, OneHandedTutorialHandler tutorialHandler, OneHandedBackgroundPanelOrganizer oneHandedBackgroundGradientOrganizer, ShellExecutor mainExecutor) { super(mainExecutor); + mWindowManager = windowManager; mAnimationController = animationController; mDisplayController = displayController; mLastVisualDisplayBounds.set(getDisplayBounds()); @@ -292,11 +294,16 @@ public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer { @Nullable private Rect getDisplayBounds() { - Point realSize = new Point(0, 0); - if (mDisplayController != null && mDisplayController.getDisplay(DEFAULT_DISPLAY) != null) { - mDisplayController.getDisplay(DEFAULT_DISPLAY).getRealSize(realSize); + if (mWindowManager == null) { + Slog.e(TAG, "WindowManager instance is null! Can not get display size!"); + return new Rect(); + } + final Rect displayBounds = mWindowManager.getCurrentWindowMetrics().getBounds(); + if (displayBounds.width() == 0 || displayBounds.height() == 0) { + Slog.e(TAG, "Display size error! width = " + displayBounds.width() + + ", height = " + displayBounds.height()); } - return new Rect(0, 0, realSize.x, realSize.y); + return displayBounds; } @VisibleForTesting diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedGestureHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedGestureHandler.java index 91e649f98292..b86b954c9eeb 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedGestureHandler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedGestureHandler.java @@ -20,7 +20,6 @@ import static android.view.Display.DEFAULT_DISPLAY; import android.annotation.Nullable; import android.content.Context; -import android.graphics.Point; import android.graphics.PointF; import android.graphics.Rect; import android.hardware.input.InputManager; @@ -34,6 +33,7 @@ import android.view.InputMonitor; import android.view.MotionEvent; import android.view.Surface; import android.view.ViewConfiguration; +import android.view.WindowManager; import android.window.WindowContainerTransaction; import androidx.annotation.VisibleForTesting; @@ -59,8 +59,9 @@ public class OneHandedGestureHandler implements OneHandedTransitionCallback, private final PointF mDownPos = new PointF(); private final PointF mLastPos = new PointF(); private final PointF mStartDragPos = new PointF(); - private boolean mPassedSlop; + private final WindowManager mWindowManager; + private boolean mPassedSlop; private boolean mAllowGesture; private boolean mIsEnabled; private int mNavGestureHeight; @@ -86,9 +87,10 @@ public class OneHandedGestureHandler implements OneHandedTransitionCallback, * @param context {@link Context} * @param displayController {@link DisplayController} */ - public OneHandedGestureHandler(Context context, DisplayController displayController, - ViewConfiguration viewConfig, + public OneHandedGestureHandler(Context context, WindowManager windowManager, + DisplayController displayController, ViewConfiguration viewConfig, ShellExecutor mainExecutor) { + mWindowManager = windowManager; mDisplayController = displayController; mMainExecutor = mainExecutor; displayController.addDisplayChangingController(this); @@ -210,16 +212,10 @@ public class OneHandedGestureHandler implements OneHandedTransitionCallback, disposeInputChannel(); if (mIsEnabled && mIsThreeButtonModeEnabled) { - final Point displaySize = new Point(); - if (mDisplayController != null) { - final Display display = mDisplayController.getDisplay(DEFAULT_DISPLAY); - if (display != null) { - display.getRealSize(displaySize); - } - } + final Rect displaySize = mWindowManager.getCurrentWindowMetrics().getBounds(); // Register input event receiver to monitor the touch region of NavBar gesture height - mGestureRegion.set(0, displaySize.y - mNavGestureHeight, displaySize.x, - displaySize.y); + mGestureRegion.set(0, displaySize.height() - mNavGestureHeight, displaySize.width(), + displaySize.height()); mInputMonitor = InputManager.getInstance().monitorGestureInput( "onehanded-gesture-offset", DEFAULT_DISPLAY); try { 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 3f72b80a7dce..d539835da764 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 @@ -20,7 +20,6 @@ import android.content.ContentResolver; import android.content.Context; import android.content.res.Configuration; import android.graphics.PixelFormat; -import android.graphics.Point; import android.graphics.Rect; import android.os.SystemProperties; import android.provider.Settings; @@ -51,14 +50,13 @@ public class OneHandedTutorialHandler implements OneHandedTransitionCallback { private static final String ONE_HANDED_MODE_OFFSET_PERCENTAGE = "persist.debug.one_handed_offset_percentage"; private static final int MAX_TUTORIAL_SHOW_COUNT = 2; - private final Rect mLastUpdatedBounds = new Rect(); private final WindowManager mWindowManager; private final AccessibilityManager mAccessibilityManager; private final String mPackageName; + private final Rect mDisplaySize; private Context mContext; private View mTutorialView; - private Point mDisplaySize = new Point(); private ContentResolver mContentResolver; private boolean mCanShowTutorial; private String mStartOneHandedDescription; @@ -101,14 +99,14 @@ public class OneHandedTutorialHandler implements OneHandedTransitionCallback { } }; - public OneHandedTutorialHandler(Context context, ShellExecutor mainExecutor) { + public OneHandedTutorialHandler(Context context, WindowManager windowManager, + ShellExecutor mainExecutor) { mContext = context; - context.getDisplay().getRealSize(mDisplaySize); + mWindowManager = windowManager; + mDisplaySize = windowManager.getCurrentWindowMetrics().getBounds(); mPackageName = context.getPackageName(); mContentResolver = context.getContentResolver(); - mWindowManager = context.getSystemService(WindowManager.class); mAccessibilityManager = AccessibilityManager.getInstance(context); - mStartOneHandedDescription = context.getResources().getString( R.string.accessibility_action_start_one_handed); mStopOneHandedDescription = context.getResources().getString( @@ -121,7 +119,8 @@ public class OneHandedTutorialHandler implements OneHandedTransitionCallback { R.fraction.config_one_handed_offset, 1, 1); final int sysPropPercentageConfig = SystemProperties.getInt( ONE_HANDED_MODE_OFFSET_PERCENTAGE, Math.round(offsetPercentageConfig * 100.0f)); - mTutorialAreaHeight = Math.round(mDisplaySize.y * (sysPropPercentageConfig / 100.0f)); + mTutorialAreaHeight = Math.round( + mDisplaySize.height() * (sysPropPercentageConfig / 100.0f)); mainExecutor.execute(() -> { recreateTutorialView(mContext); @@ -214,7 +213,7 @@ public class OneHandedTutorialHandler implements OneHandedTransitionCallback { */ private WindowManager.LayoutParams getTutorialTargetLayoutParams() { final WindowManager.LayoutParams lp = new WindowManager.LayoutParams( - mDisplaySize.x, mTutorialAreaHeight, 0, 0, + mDisplaySize.width(), mTutorialAreaHeight, 0, 0, WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL, WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, @@ -228,9 +227,13 @@ public class OneHandedTutorialHandler implements OneHandedTransitionCallback { void dump(@NonNull PrintWriter pw) { final String innerPrefix = " "; - pw.println(TAG + "states: "); - pw.print(innerPrefix + "mLastUpdatedBounds="); - pw.println(mLastUpdatedBounds); + pw.println(TAG + " states: "); + pw.print(innerPrefix + "mTriggerState="); + pw.println(mTriggerState); + pw.print(innerPrefix + "mDisplaySize="); + pw.println(mDisplaySize); + pw.print(innerPrefix + "mTutorialAreaHeight="); + pw.println(mTutorialAreaHeight); } private boolean canShowTutorial() { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java index 31057f8d5fb8..c726c012c6a0 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java @@ -65,6 +65,8 @@ public class PipResizeGestureHandler { private static final int PINCH_RESIZE_SNAP_DURATION = 250; private static final int PINCH_RESIZE_MAX_ANGLE_ROTATION = 45; private static final float PINCH_RESIZE_AUTO_MAX_RATIO = 0.9f; + private static final float OVERROTATE_DAMP_FACTOR = 0.4f; + private static final float ANGLE_THRESHOLD = 5f; private final Context mContext; private final PipBoundsAlgorithm mPipBoundsAlgorithm; @@ -423,26 +425,28 @@ public class PipResizeGestureHandler { float down1X = mDownSecondaryPoint.x; float down1Y = mDownSecondaryPoint.y; + float angle = 0; if (down0X > focusX && down0Y < focusY && down1X < focusX && down1Y > focusY) { // Top right + Bottom left pinch to zoom. - mAngle = calculateRotationAngle(mLastResizeBounds.centerX(), + angle = calculateRotationAngle(mLastResizeBounds.centerX(), mLastResizeBounds.centerY(), x0, y0, x1, y1, true); } else if (down1X > focusX && down1Y < focusY && down0X < focusX && down0Y > focusY) { // Top right + Bottom left pinch to zoom. - mAngle = calculateRotationAngle(mLastResizeBounds.centerX(), + angle = calculateRotationAngle(mLastResizeBounds.centerX(), mLastResizeBounds.centerY(), x1, y1, x0, y0, true); } else if (down0X < focusX && down0Y < focusY && down1X > focusX && down1Y > focusY) { // Top left + bottom right pinch to zoom. - mAngle = calculateRotationAngle(mLastResizeBounds.centerX(), + angle = calculateRotationAngle(mLastResizeBounds.centerX(), mLastResizeBounds.centerY(), x0, y0, x1, y1, false); } else if (down1X < focusX && down1Y < focusY && down0X > focusX && down0Y > focusY) { // Top left + bottom right pinch to zoom. - mAngle = calculateRotationAngle(mLastResizeBounds.centerX(), + angle = calculateRotationAngle(mLastResizeBounds.centerX(), mLastResizeBounds.centerY(), x1, y1, x0, y0, false); } + mAngle = angle; mLastResizeBounds.set(PipPinchResizingAlgorithm.pinchResize(x0, y0, x1, y1, mDownPoint.x, mDownPoint.y, mDownSecondaryPoint.x, mDownSecondaryPoint.y, @@ -477,10 +481,40 @@ public class PipResizeGestureHandler { } // Calculate the percentage difference of [0, 90] compare to the base angle. - double diff0 = (Math.max(0, Math.min(angle0, 90)) - baseAngle) / 90; - double diff1 = (Math.max(0, Math.min(angle1, 90)) - baseAngle) / 90; + double diff0 = (Math.max(-90, Math.min(angle0, 90)) - baseAngle) / 90; + double diff1 = (Math.max(-90, Math.min(angle1, 90)) - baseAngle) / 90; - return (float) (diff0 + diff1) / 2 * PINCH_RESIZE_MAX_ANGLE_ROTATION * (positive ? 1 : -1); + final float angle = + (float) (diff0 + diff1) / 2 * PINCH_RESIZE_MAX_ANGLE_ROTATION * (positive ? 1 : -1); + + // Remove some degrees so that user doesn't immediately start rotating until a threshold + return angle / Math.abs(angle) + * Math.max(0, (Math.abs(dampedRotate(angle)) - ANGLE_THRESHOLD)); + } + + /** + * Given the current rotation angle, dampen it so that as it approaches the maximum angle, + * dampen it. + */ + private float dampedRotate(float amount) { + if (Float.compare(amount, 0) == 0) return 0; + + float f = amount / PINCH_RESIZE_MAX_ANGLE_ROTATION; + f = f / (Math.abs(f)) * (overRotateInfluenceCurve(Math.abs(f))); + + // Clamp this factor, f, to -1 < f < 1 + if (Math.abs(f) >= 1) { + f /= Math.abs(f); + } + return OVERROTATE_DAMP_FACTOR * f * PINCH_RESIZE_MAX_ANGLE_ROTATION; + } + + /** + * Returns a value that corresponds to y = (f - 1)^3 + 1. + */ + private float overRotateInfluenceCurve(float f) { + f -= 1.0f; + return f * f * f + 1.0f; } private void onDragCornerResize(MotionEvent ev) { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurface.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurface.java index 2c4ceffcb8f5..a594a9f31dde 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurface.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurface.java @@ -19,6 +19,7 @@ package com.android.wm.shell.startingsurface; import android.os.IBinder; import android.window.StartingWindowInfo; +import java.util.function.BiConsumer; /** * Interface to engage starting window feature. */ @@ -36,4 +37,11 @@ public interface StartingSurface { * @param taskId */ void copySplashScreenView(int taskId); + + /** + * Registers the starting window listener. + * + * @param listener The callback when need a starting window. + */ + void setStartingWindowListener(BiConsumer<Integer, Integer> listener); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java index 73bf8ac90c29..1ac05fbff9c4 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java @@ -25,6 +25,7 @@ import static android.window.StartingWindowInfo.TYPE_PARAMETER_NEW_TASK; import static android.window.StartingWindowInfo.TYPE_PARAMETER_PROCESS_RUNNING; import static android.window.StartingWindowInfo.TYPE_PARAMETER_TASK_SWITCH; +import android.app.ActivityManager.RunningTaskInfo; import android.app.ActivityTaskManager; import android.content.Context; import android.os.IBinder; @@ -36,6 +37,8 @@ import android.window.TaskSnapshot; import com.android.wm.shell.common.ShellExecutor; +import java.util.function.BiConsumer; + /** * Implementation to draw the starting window to an application, and remove the starting window * until the application displays its own window. @@ -53,6 +56,8 @@ public class StartingWindowController { private final StartingSurfaceDrawer mStartingSurfaceDrawer; private final StartingTypeChecker mStartingTypeChecker = new StartingTypeChecker(); + + private BiConsumer<Integer, Integer> mTaskLaunchingCallback; private final StartingSurfaceImpl mImpl = new StartingSurfaceImpl(); public StartingWindowController(Context context, ShellExecutor mainExecutor) { @@ -151,11 +156,24 @@ public class StartingWindowController { } } + /* + * Registers the starting window listener. + * + * @param listener The callback when need a starting window. + */ + void setStartingWindowListener(BiConsumer<Integer, Integer> listener) { + mTaskLaunchingCallback = listener; + } + /** * Called when a task need a starting window. */ void addStartingWindow(StartingWindowInfo windowInfo, IBinder appToken) { final int suggestionType = mStartingTypeChecker.estimateStartingWindowType(windowInfo); + final RunningTaskInfo runningTaskInfo = windowInfo.taskInfo; + if (mTaskLaunchingCallback != null) { + mTaskLaunchingCallback.accept(runningTaskInfo.taskId, suggestionType); + } if (suggestionType == STARTING_WINDOW_TYPE_SPLASH_SCREEN) { mStartingSurfaceDrawer.addSplashScreenStartingWindow(windowInfo, appToken); } else if (suggestionType == STARTING_WINDOW_TYPE_SNAPSHOT) { @@ -192,5 +210,10 @@ public class StartingWindowController { public void copySplashScreenView(int taskId) { StartingWindowController.this.copySplashScreenView(taskId); } + + @Override + public void setStartingWindowListener(BiConsumer<Integer, Integer> listener) { + StartingWindowController.this.setStartingWindowListener(listener); + } } } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedBackgroundPanelOrganizerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedBackgroundPanelOrganizerTest.java index b0f52cf656f8..d6bcf0375f32 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedBackgroundPanelOrganizerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedBackgroundPanelOrganizerTest.java @@ -69,7 +69,7 @@ public class OneHandedBackgroundPanelOrganizerTest extends OneHandedTestCase { mDisplayAreaInfo = new DisplayAreaInfo(mToken, DEFAULT_DISPLAY, FEATURE_ONE_HANDED_BACKGROUND_PANEL); - mBackgroundPanelOrganizer = new OneHandedBackgroundPanelOrganizer(mContext, + mBackgroundPanelOrganizer = new OneHandedBackgroundPanelOrganizer(mContext, mWindowManager, mMockDisplayController, Runnable::run); } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java index 1ad8fd3e7298..c5221dee9216 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java @@ -100,6 +100,7 @@ public class OneHandedControllerTest extends OneHandedTestCase { mSpiedOneHandedController = spy(new OneHandedController( mContext, + mWindowManager, mMockDisplayController, mMockBackgroundOrganizer, mMockDisplayAreaOrganizer, @@ -120,8 +121,8 @@ public class OneHandedControllerTest extends OneHandedTestCase { final OneHandedAnimationController animationController = new OneHandedAnimationController( mContext); OneHandedDisplayAreaOrganizer displayAreaOrganizer = new OneHandedDisplayAreaOrganizer( - mContext, mMockDisplayController, animationController, mMockTutorialHandler, - mMockBackgroundOrganizer, mMockShellMainExecutor); + mContext, mWindowManager, mMockDisplayController, animationController, + mMockTutorialHandler, mMockBackgroundOrganizer, mMockShellMainExecutor); assertThat(displayAreaOrganizer.isInOneHanded()).isFalse(); } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizerTest.java index 7a826c1be4d3..1fa1e2ff69b6 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizerTest.java @@ -121,6 +121,7 @@ public class OneHandedDisplayAreaOrganizerTest extends OneHandedTestCase { when(mMockLeash.getHeight()).thenReturn(DISPLAY_HEIGHT); mSpiedDisplayAreaOrganizer = spy(new OneHandedDisplayAreaOrganizer(mContext, + mWindowManager, mMockDisplayController, mMockAnimationController, mTutorialHandler, diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedGestureHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedGestureHandlerTest.java index b275b701f87a..f58affc60f0b 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedGestureHandlerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedGestureHandlerTest.java @@ -44,8 +44,9 @@ public class OneHandedGestureHandlerTest extends OneHandedTestCase { @Before public void setUp() { MockitoAnnotations.initMocks(this); - mGestureHandler = new OneHandedGestureHandler(mContext, mMockDisplayController, - ViewConfiguration.get(mTestContext), mMockShellMainExecutor); + mGestureHandler = new OneHandedGestureHandler(mContext, mWindowManager, + mMockDisplayController, ViewConfiguration.get(mTestContext), + mMockShellMainExecutor); } @Test diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedTestCase.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedTestCase.java index 32a188d02cf0..8b03dc58c3bf 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedTestCase.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedTestCase.java @@ -26,6 +26,7 @@ import android.content.Context; import android.hardware.display.DisplayManager; import android.os.SystemProperties; import android.testing.TestableContext; +import android.view.WindowManager; import androidx.test.platform.app.InstrumentationRegistry; @@ -45,6 +46,9 @@ public abstract class OneHandedTestCase { public TestableContext mTestContext = new TestableContext( InstrumentationRegistry.getInstrumentation().getTargetContext(), null); + @Mock(answer = Answers.RETURNS_DEEP_STUBS) + protected WindowManager mWindowManager; + @Before public void setUpContext() { assumeTrue(SystemProperties.getBoolean(SUPPORT_ONE_HANDED_MODE, false)); @@ -53,6 +57,12 @@ public abstract class OneHandedTestCase { mContext = getTestContext().createDisplayContext(dm.getDisplay(DEFAULT_DISPLAY)); } + @Before + public void setUpWindowManager() { + assumeTrue(SystemProperties.getBoolean(SUPPORT_ONE_HANDED_MODE, false)); + mWindowManager = getTestContext().getSystemService(WindowManager.class); + } + /** return testable context */ protected TestableContext getTestContext() { return mTestContext; 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 024cf7ffc1f3..69c537c2efbe 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 @@ -65,7 +65,6 @@ public class OneHandedTutorialHandlerTest extends OneHandedTestCase { @Mock OneHandedUiEventLogger mMockUiEventLogger; - @Before public void setUp() { MockitoAnnotations.initMocks(this); @@ -73,7 +72,8 @@ public class OneHandedTutorialHandlerTest extends OneHandedTestCase { when(mMockDisplayAreaOrganizer.getDisplayAreaTokenMap()).thenReturn(new ArrayMap<>()); mOneHandedController = new OneHandedController( - getContext(), + mContext, + mWindowManager, mMockDisplayController, mMockBackgroundOrganizer, mMockDisplayAreaOrganizer, diff --git a/libs/hwui/FrameMetricsObserver.h b/libs/hwui/FrameMetricsObserver.h index b93f07853242..ef1f5aabcbd8 100644 --- a/libs/hwui/FrameMetricsObserver.h +++ b/libs/hwui/FrameMetricsObserver.h @@ -24,6 +24,24 @@ namespace uirenderer { class FrameMetricsObserver : public VirtualLightRefBase { public: virtual void notify(const int64_t* buffer) = 0; + bool waitForPresentTime() const { return mWaitForPresentTime; }; + + /** + * Create a new metrics observer. An observer that watches present time gets notified at a + * different time than the observer that doesn't. + * + * The observer that doesn't want present time is notified about metrics just after the frame + * is completed. This is the default behaviour that's used by public API's. + * + * An observer that watches present time is notified about metrics after the actual display + * present time is known. + * WARNING! This observer may not receive metrics for the last several frames that the app + * produces. + */ + FrameMetricsObserver(bool waitForPresentTime) : mWaitForPresentTime(waitForPresentTime) {} + +private: + const bool mWaitForPresentTime; }; } // namespace uirenderer diff --git a/libs/hwui/FrameMetricsReporter.h b/libs/hwui/FrameMetricsReporter.h index 0643e790d00b..3f2dc1244085 100644 --- a/libs/hwui/FrameMetricsReporter.h +++ b/libs/hwui/FrameMetricsReporter.h @@ -55,13 +55,24 @@ public: return mObservers.size() > 0; } - void reportFrameMetrics(const int64_t* stats) { + /** + * Notify observers about the metrics contained in 'stats'. + * If an observer is waiting for present time, notify when 'stats' has present time. + * + * If an observer does not want present time, only notify when 'hasPresentTime' is false. + * Never notify both types of observers from the same callback, because the callback with + * 'hasPresentTime' is sent at a different time than the one without. + */ + void reportFrameMetrics(const int64_t* stats, bool hasPresentTime) { FatVector<sp<FrameMetricsObserver>, 10> copy; { std::lock_guard lock(mObserversLock); copy.reserve(mObservers.size()); for (size_t i = 0; i < mObservers.size(); i++) { - copy.push_back(mObservers[i]); + const bool wantsPresentTime = mObservers[i]->waitForPresentTime(); + if (hasPresentTime == wantsPresentTime) { + copy.push_back(mObservers[i]); + } } } for (size_t i = 0; i < copy.size(); i++) { diff --git a/libs/hwui/jni/android_graphics_HardwareRendererObserver.cpp b/libs/hwui/jni/android_graphics_HardwareRendererObserver.cpp index 5b3e65648981..e5d5e75d0f3b 100644 --- a/libs/hwui/jni/android_graphics_HardwareRendererObserver.cpp +++ b/libs/hwui/jni/android_graphics_HardwareRendererObserver.cpp @@ -35,7 +35,9 @@ static JNIEnv* getenv(JavaVM* vm) { return env; } -HardwareRendererObserver::HardwareRendererObserver(JavaVM *vm, jobject observer) : mVm(vm) { +HardwareRendererObserver::HardwareRendererObserver(JavaVM* vm, jobject observer, + bool waitForPresentTime) + : uirenderer::FrameMetricsObserver(waitForPresentTime), mVm(vm) { mObserverWeak = getenv(mVm)->NewWeakGlobalRef(observer); LOG_ALWAYS_FATAL_IF(mObserverWeak == nullptr, "unable to create frame stats observer reference"); @@ -86,14 +88,16 @@ void HardwareRendererObserver::notify(const int64_t* stats) { } static jlong android_graphics_HardwareRendererObserver_createObserver(JNIEnv* env, - jobject observerObj) { + jobject observerObj, + jboolean waitForPresentTime) { JavaVM* vm = nullptr; if (env->GetJavaVM(&vm) != JNI_OK) { LOG_ALWAYS_FATAL("Unable to get Java VM"); return 0; } - HardwareRendererObserver* observer = new HardwareRendererObserver(vm, observerObj); + HardwareRendererObserver* observer = + new HardwareRendererObserver(vm, observerObj, waitForPresentTime); return reinterpret_cast<jlong>(observer); } @@ -110,10 +114,10 @@ static jint android_graphics_HardwareRendererObserver_getNextBuffer(JNIEnv* env, } static const std::array gMethods = { - MAKE_JNI_NATIVE_METHOD("nCreateObserver", "()J", - android_graphics_HardwareRendererObserver_createObserver), - MAKE_JNI_NATIVE_METHOD("nGetNextBuffer", "(J[J)I", - android_graphics_HardwareRendererObserver_getNextBuffer), + MAKE_JNI_NATIVE_METHOD("nCreateObserver", "(Z)J", + android_graphics_HardwareRendererObserver_createObserver), + MAKE_JNI_NATIVE_METHOD("nGetNextBuffer", "(J[J)I", + android_graphics_HardwareRendererObserver_getNextBuffer), }; int register_android_graphics_HardwareRendererObserver(JNIEnv* env) { diff --git a/libs/hwui/jni/android_graphics_HardwareRendererObserver.h b/libs/hwui/jni/android_graphics_HardwareRendererObserver.h index 62111fd7d7a1..d3076140541b 100644 --- a/libs/hwui/jni/android_graphics_HardwareRendererObserver.h +++ b/libs/hwui/jni/android_graphics_HardwareRendererObserver.h @@ -26,7 +26,7 @@ namespace android { */ class HardwareRendererObserver : public uirenderer::FrameMetricsObserver { public: - HardwareRendererObserver(JavaVM *vm, jobject observer); + HardwareRendererObserver(JavaVM* vm, jobject observer, bool waitForPresentTime); ~HardwareRendererObserver(); /** diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp index f69ddacf7ca1..9793300b406d 100644 --- a/libs/hwui/renderthread/CanvasContext.cpp +++ b/libs/hwui/renderthread/CanvasContext.cpp @@ -599,10 +599,41 @@ void CanvasContext::finishFrame(FrameInfo* frameInfo) { // TODO (b/169858044): Move this into JankTracker to adjust deadline when queue is // double-stuffed. if (CC_UNLIKELY(mFrameMetricsReporter.get() != nullptr)) { - mFrameMetricsReporter->reportFrameMetrics(frameInfo->data()); + mFrameMetricsReporter->reportFrameMetrics(frameInfo->data(), false /*hasPresentTime*/); } } +void CanvasContext::reportMetricsWithPresentTime() { + if (mFrameMetricsReporter == nullptr) { + return; + } + if (mNativeSurface == nullptr) { + return; + } + FrameInfo* forthBehind; + int64_t frameNumber; + { // acquire lock + std::scoped_lock lock(mLast4FrameInfosMutex); + if (mLast4FrameInfos.size() != mLast4FrameInfos.capacity()) { + // Not enough frames yet + return; + } + // Surface object keeps stats for the last 8 frames. + std::tie(forthBehind, frameNumber) = mLast4FrameInfos.front(); + } // release lock + + nsecs_t presentTime = 0; + native_window_get_frame_timestamps( + mNativeSurface->getNativeWindow(), frameNumber, nullptr /*outRequestedPresentTime*/, + nullptr /*outAcquireTime*/, nullptr /*outLatchTime*/, + nullptr /*outFirstRefreshStartTime*/, nullptr /*outLastRefreshStartTime*/, + nullptr /*outGpuCompositionDoneTime*/, &presentTime, nullptr /*outDequeueReadyTime*/, + nullptr /*outReleaseTime*/); + + forthBehind->set(FrameInfoIndex::DisplayPresentTime) = presentTime; + mFrameMetricsReporter->reportFrameMetrics(forthBehind->data(), true /*hasPresentTime*/); +} + void CanvasContext::onSurfaceStatsAvailable(void* context, ASurfaceControl* control, ASurfaceControlStats* stats) { @@ -624,6 +655,9 @@ void CanvasContext::onSurfaceStatsAvailable(void* context, ASurfaceControl* cont } } } + + instance->reportMetricsWithPresentTime(); + if (frameInfo != nullptr) { if (gpuCompleteTime == -1) { gpuCompleteTime = frameInfo->get(FrameInfoIndex::SwapBuffersCompleted); diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h index 2e7b2f618a8a..74f426ead912 100644 --- a/libs/hwui/renderthread/CanvasContext.h +++ b/libs/hwui/renderthread/CanvasContext.h @@ -219,6 +219,12 @@ private: SkRect computeDirtyRect(const Frame& frame, SkRect* dirty); void finishFrame(FrameInfo* frameInfo); + /** + * Invoke 'reportFrameMetrics' on the last frame stored in 'mLast4FrameInfos'. + * Populate the 'presentTime' field before calling. + */ + void reportMetricsWithPresentTime(); + // The same type as Frame.mWidth and Frame.mHeight int32_t mLastFrameWidth = 0; int32_t mLastFrameHeight = 0; |