summaryrefslogtreecommitdiff
path: root/libs
diff options
context:
space:
mode:
Diffstat (limited to 'libs')
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java5
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedBackgroundPanelOrganizer.java15
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java40
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java21
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedGestureHandler.java22
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedTutorialHandler.java27
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java48
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurface.java8
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java23
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedBackgroundPanelOrganizerTest.java2
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java5
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizerTest.java1
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedGestureHandlerTest.java5
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedTestCase.java10
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedTutorialHandlerTest.java4
-rw-r--r--libs/hwui/FrameMetricsObserver.h18
-rw-r--r--libs/hwui/FrameMetricsReporter.h15
-rw-r--r--libs/hwui/jni/android_graphics_HardwareRendererObserver.cpp18
-rw-r--r--libs/hwui/jni/android_graphics_HardwareRendererObserver.h2
-rw-r--r--libs/hwui/renderthread/CanvasContext.cpp36
-rw-r--r--libs/hwui/renderthread/CanvasContext.h6
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;