diff options
3 files changed, 102 insertions, 22 deletions
diff --git a/core/java/android/os/Looper.java b/core/java/android/os/Looper.java index b58ff1fd4755..d299672ea1d5 100644 --- a/core/java/android/os/Looper.java +++ b/core/java/android/os/Looper.java @@ -147,7 +147,7 @@ public final class Looper { } final long traceTag = me.mTraceTag; - if (traceTag != 0) { + if (traceTag != 0 && Trace.isTagEnabled(traceTag)) { Trace.traceBegin(traceTag, msg.target.getTraceName(msg)); } try { diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java index 998f50f205d7..cb77d7b29c9f 100644 --- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java +++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java @@ -31,6 +31,7 @@ import android.graphics.Region.Op; import android.hardware.display.DisplayManager; import android.os.Bundle; import android.os.Handler; +import android.os.Message; import android.util.AttributeSet; import android.view.Display; import android.view.DisplayInfo; @@ -106,6 +107,11 @@ public class DividerView extends FrameLayout implements OnTouchListener, private static final Interpolator IME_ADJUST_INTERPOLATOR = new PathInterpolator(0.2f, 0f, 0.1f, 1f); + private static final long ONE_MS_IN_NS = 1000000; + private static final long ONE_S_IN_NS = ONE_MS_IN_NS * 1000; + + private static final int MSG_RESIZE_STACK = 0; + private DividerHandleView mHandle; private View mBackground; private MinimizedDockShadow mMinimizedShadow; @@ -150,7 +156,25 @@ public class DividerView extends FrameLayout implements OnTouchListener, private boolean mDockedStackMinimized; private boolean mAdjustedForIme; private DividerState mState; - private final Handler mHandler = new Handler(); + + /** + * The offset between vsync-app and vsync-surfaceflinger. See + * {@link #calculateAppSurfaceFlingerVsyncOffsetMs} why this is necessary. + */ + private long mSurfaceFlingerOffsetMs; + + private final Handler mHandler = new Handler() { + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case MSG_RESIZE_STACK: + resizeStack(msg.arg1, msg.arg2, (SnapTarget) msg.obj); + break; + default: + super.handleMessage(msg); + } + } + }; private final AccessibilityDelegate mHandleDelegate = new AccessibilityDelegate() { @Override @@ -290,6 +314,7 @@ public class DividerView extends FrameLayout implements OnTouchListener, protected void onAttachedToWindow() { super.onAttachedToWindow(); EventBus.getDefault().register(this); + mSurfaceFlingerOffsetMs = calculateAppSurfaceFlingerVsyncOffsetMs(); } @Override @@ -298,6 +323,25 @@ public class DividerView extends FrameLayout implements OnTouchListener, EventBus.getDefault().unregister(this); } + /** + * This method calculates the offset between vsync-surfaceflinger and vsync-app. If vsync-app + * is a couple of milliseconds before vsync-sf, a touch or animation event that causes the + * stacks to be resized are sometimes processed before the vsync-sf tick, and sometimes after, + * which leads to jank. Figure out this difference here and then post all the touch/animation + * events to start being processed at vsync-sf. + * + * @return The offset between vsync-app and vsync-sf, or 0 if vsync app happens after vsync-sf. + */ + private long calculateAppSurfaceFlingerVsyncOffsetMs() { + Display display = getDisplay(); + + // Calculate vsync offset from SurfaceFlinger. + // See frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp:getDisplayConfigs + long vsyncPeriod = (long) (ONE_S_IN_NS / display.getRefreshRate()); + long sfVsyncOffset = vsyncPeriod - (display.getPresentationDeadlineNanos() - ONE_MS_IN_NS); + return Math.max(0, (sfVsyncOffset - display.getAppVsyncOffsetNanos()) / ONE_MS_IN_NS); + } + @Override public WindowInsets onApplyWindowInsets(WindowInsets insets) { if (mStableInsets.left != insets.getStableInsetLeft() @@ -453,7 +497,7 @@ public class DividerView extends FrameLayout implements OnTouchListener, if (mMoving && mDockSide != WindowManager.DOCKED_INVALID) { SnapTarget snapTarget = mSnapAlgorithm.calculateSnapTarget( mStartPosition, 0 /* velocity */, false /* hardDismiss */); - resizeStack(calculatePosition(x, y), mStartPosition, snapTarget); + resizeStackDelayed(calculatePosition(x, y), mStartPosition, snapTarget); } break; case MotionEvent.ACTION_UP: @@ -532,10 +576,11 @@ public class DividerView extends FrameLayout implements OnTouchListener, final long endDelay) { final boolean taskPositionSameAtEnd = snapTarget.flag == SnapTarget.FLAG_NONE; ValueAnimator anim = ValueAnimator.ofInt(position, snapTarget.position); - anim.addUpdateListener(animation -> resizeStack((Integer) animation.getAnimatedValue(), + anim.addUpdateListener(animation -> resizeStackDelayed((int) animation.getAnimatedValue(), taskPositionSameAtEnd && animation.getAnimatedFraction() == 1f ? TASK_POSITION_SAME - : snapTarget.taskPosition, snapTarget)); + : snapTarget.taskPosition, + snapTarget)); Runnable endAction = () -> { commitSnapFlags(snapTarget); mWindowManagerProxy.setResizing(false); @@ -551,15 +596,24 @@ public class DividerView extends FrameLayout implements OnTouchListener, @Override public void onAnimationCancel(Animator animation) { + mHandler.removeMessages(MSG_RESIZE_STACK); mCancelled = true; } @Override public void onAnimationEnd(Animator animation) { - if (endDelay == 0 || mCancelled) { + long delay = 0; + if (endDelay != 0) { + delay = endDelay; + } else if (mCancelled) { + delay = 0; + } else if (mSurfaceFlingerOffsetMs != 0) { + delay = mSurfaceFlingerOffsetMs; + } + if (delay == 0) { endAction.run(); } else { - mHandler.postDelayed(endAction, endDelay); + mHandler.postDelayed(endAction, delay); } } }); @@ -793,6 +847,17 @@ public class DividerView extends FrameLayout implements OnTouchListener, mDisplayHeight, mDividerSize); } + public void resizeStackDelayed(int position, int taskPosition, SnapTarget taskSnapTarget) { + if (mSurfaceFlingerOffsetMs != 0) { + Message message = mHandler.obtainMessage(MSG_RESIZE_STACK, position, taskPosition, + taskSnapTarget); + message.setAsynchronous(true); + mHandler.sendMessageDelayed(message, mSurfaceFlingerOffsetMs); + } else { + resizeStack(position, taskPosition, taskSnapTarget); + } + } + public void resizeStack(int position, int taskPosition, SnapTarget taskSnapTarget) { calculateBoundsForPosition(position, mDockSide, mDockedRect); diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java index c9283b2283b9..4bc148bef290 100644 --- a/services/core/java/com/android/server/am/UserController.java +++ b/services/core/java/com/android/server/am/UserController.java @@ -279,6 +279,7 @@ final class UserController { */ private void finishUserUnlocking(final UserState uss) { final int userId = uss.mHandle.getIdentifier(); + boolean proceedWithUnlock = false; synchronized (mService) { // Bail if we ended up with a stale user if (mStartedUsers.get(uss.mHandle.getIdentifier()) != uss) return; @@ -288,20 +289,24 @@ final class UserController { if (uss.setState(STATE_RUNNING_LOCKED, STATE_RUNNING_UNLOCKING)) { getUserManagerInternal().setUserState(userId, uss.state); - uss.mUnlockProgress.start(); - - // Prepare app storage before we go any further - uss.mUnlockProgress.setProgress(5, - mService.mContext.getString(R.string.android_start_title)); - mUserManager.onBeforeUnlockUser(userId); - uss.mUnlockProgress.setProgress(20); - - // Dispatch unlocked to system services; when fully dispatched, - // that calls through to the next "unlocked" phase - mHandler.obtainMessage(SYSTEM_USER_UNLOCK_MSG, userId, 0, uss) - .sendToTarget(); + proceedWithUnlock = true; } } + + if (proceedWithUnlock) { + uss.mUnlockProgress.start(); + + // Prepare app storage before we go any further + uss.mUnlockProgress.setProgress(5, + mService.mContext.getString(R.string.android_start_title)); + mUserManager.onBeforeUnlockUser(userId); + uss.mUnlockProgress.setProgress(20); + + // Dispatch unlocked to system services; when fully dispatched, + // that calls through to the next "unlocked" phase + mHandler.obtainMessage(SYSTEM_USER_UNLOCK_MSG, userId, 0, uss) + .sendToTarget(); + } } /** @@ -962,6 +967,7 @@ final class UserController { boolean unlockUserCleared(final int userId, byte[] token, byte[] secret, IProgressListener listener) { + UserState uss; synchronized (mService) { // TODO Move this block outside of synchronized if it causes lock contention if (!StorageManager.isUserKeyUnlocked(userId)) { @@ -976,7 +982,7 @@ final class UserController { } // Bail if user isn't actually running, otherwise register the given // listener to watch for unlock progress - final UserState uss = mStartedUsers.get(userId); + uss = mStartedUsers.get(userId); if (uss == null) { notifyFinished(userId, listener); return false; @@ -984,8 +990,12 @@ final class UserController { uss.mUnlockProgress.addListener(listener); uss.tokenProvided = (token != null); } + } - finishUserUnlocking(uss); + finishUserUnlocking(uss); + + final ArraySet<Integer> childProfilesToUnlock = new ArraySet<>(); + synchronized (mService) { // We just unlocked a user, so let's now attempt to unlock any // managed profiles under that user. @@ -995,11 +1005,16 @@ final class UserController { if (parent != null && parent.id == userId && testUserId != userId) { Slog.d(TAG, "User " + testUserId + " (parent " + parent.id + "): attempting unlock because parent was just unlocked"); - maybeUnlockUser(testUserId); + childProfilesToUnlock.add(testUserId); } } } + final int size = childProfilesToUnlock.size(); + for (int i = 0; i < size; i++) { + maybeUnlockUser(childProfilesToUnlock.valueAt(i)); + } + return true; } |