Loading services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java +5 −5 Original line number Diff line number Diff line Loading @@ -104,7 +104,7 @@ final class ImeInsetsSourceProvider extends InsetsSourceProvider { mGivenInsetsReady = true; ImeTracker.forLogging().onProgress(mStatsToken, ImeTracker.PHASE_WM_POST_LAYOUT_NOTIFY_CONTROLS_CHANGED); mStateController.notifyControlChanged(mControlTarget); mStateController.notifyControlChanged(mControlTarget, this); setImeShowing(true); } else if (wasServerVisible && mServerVisible && mGivenInsetsReady && givenInsetsPending) { Loading Loading @@ -132,15 +132,15 @@ final class ImeInsetsSourceProvider extends InsetsSourceProvider { } @Override protected boolean isLeashReadyForDispatching() { protected boolean isLeashReadyForDispatching(InsetsControlTarget target) { if (android.view.inputmethod.Flags.refactorInsetsController()) { final WindowState ws = mWindowContainer != null ? mWindowContainer.asWindowState() : null; final boolean isDrawn = ws != null && ws.isDrawn(); return super.isLeashReadyForDispatching() && mServerVisible && isDrawn && mGivenInsetsReady; return super.isLeashReadyForDispatching(target) && mServerVisible && isDrawn && mGivenInsetsReady; } else { return super.isLeashReadyForDispatching(); return super.isLeashReadyForDispatching(target); } } Loading services/core/java/com/android/server/wm/InsetsSourceProvider.java +32 −8 Original line number Diff line number Diff line Loading @@ -411,7 +411,7 @@ class InsetsSourceProvider { changed = true; } if (changed) { mStateController.notifyControlChanged(mControlTarget); mStateController.notifyControlChanged(mControlTarget, this); } } Loading Loading @@ -556,11 +556,37 @@ class InsetsSourceProvider { } mControl = new InsetsSourceControl(mSource.getId(), mSource.getType(), leash, initiallyVisible, surfacePosition, getInsetsHint()); mStateController.notifySurfaceTransactionReady(this, getSurfaceTransactionId(leash), true); ProtoLog.d(WM_DEBUG_WINDOW_INSETS, "InsetsSource Control %s for target %s", mControl, mControlTarget); } private long getSurfaceTransactionId(SurfaceControl leash) { // Here returns mNativeObject (long) as the ID instead of the leash itself so that // InsetsStateController won't keep referencing the leash unexpectedly. return leash != null ? leash.mNativeObject : 0; } /** * This is called when the surface transaction of the leash initialization has been committed. * * @param id Indicates which transaction is committed so that stale callbacks can be dropped. */ void onSurfaceTransactionCommitted(long id) { if (mIsLeashReadyForDispatching) { return; } if (mControl == null) { return; } if (id != getSurfaceTransactionId(mControl.getLeash())) { return; } mIsLeashReadyForDispatching = true; mStateController.notifySurfaceTransactionReady(this, 0, false); } void startSeamlessRotation() { if (!mSeamlessRotating) { mSeamlessRotating = true; Loading @@ -582,10 +608,6 @@ class InsetsSourceProvider { return true; } void onSurfaceTransactionApplied() { mIsLeashReadyForDispatching = true; } void setClientVisible(boolean clientVisible) { if (mClientVisible == clientVisible) { return; Loading @@ -612,8 +634,9 @@ class InsetsSourceProvider { mServerVisible, mClientVisible); } protected boolean isLeashReadyForDispatching() { return mIsLeashReadyForDispatching; protected boolean isLeashReadyForDispatching(InsetsControlTarget target) { // If the target is not the control target, we are ready for dispatching a null-leash to it. return target != mControlTarget || mIsLeashReadyForDispatching; } /** Loading @@ -626,7 +649,7 @@ class InsetsSourceProvider { @Nullable InsetsSourceControl getControl(InsetsControlTarget target) { if (target == mControlTarget) { if (!isLeashReadyForDispatching() && mControl != null) { if (!isLeashReadyForDispatching(target) && mControl != null) { // The surface transaction of preparing leash is not applied yet. We don't send it // to the client in case that the client applies its transaction sooner than ours // that we could unexpectedly overwrite the surface state. Loading Loading @@ -799,6 +822,7 @@ class InsetsSourceProvider { public void onAnimationCancelled(SurfaceControl animationLeash) { if (mAdapter == this) { mStateController.notifyControlRevoked(mControlTarget, InsetsSourceProvider.this); mStateController.notifySurfaceTransactionReady(InsetsSourceProvider.this, 0, false); mControl = null; mControlTarget = null; mAdapter = null; Loading services/core/java/com/android/server/wm/InsetsStateController.java +59 −18 Original line number Diff line number Diff line Loading @@ -34,6 +34,7 @@ import android.os.Trace; import android.util.ArrayMap; import android.util.ArraySet; import android.util.SparseArray; import android.util.SparseLongArray; import android.util.proto.ProtoOutputStream; import android.view.InsetsSource; import android.view.InsetsSourceControl; Loading @@ -59,13 +60,14 @@ class InsetsStateController { private final DisplayContent mDisplayContent; private final SparseArray<InsetsSourceProvider> mProviders = new SparseArray<>(); private final SparseLongArray mSurfaceTransactionIds = new SparseLongArray(); private final ArrayMap<InsetsControlTarget, ArrayList<InsetsSourceProvider>> mControlTargetProvidersMap = new ArrayMap<>(); private final ArrayMap<InsetsControlTarget, ArrayList<InsetsSourceProvider>> mPendingTargetProvidersMap = new ArrayMap<>(); private final SparseArray<InsetsControlTarget> mIdControlTargetMap = new SparseArray<>(); private final SparseArray<InsetsControlTarget> mIdFakeControlTargetMap = new SparseArray<>(); private final ArraySet<InsetsControlTarget> mPendingControlChanged = new ArraySet<>(); private final Consumer<WindowState> mDispatchInsetsChanged = w -> { if (w.isReadyToDispatchInsetsState()) { w.notifyInsetsChanged(); Loading Loading @@ -327,11 +329,11 @@ class InsetsStateController { } if (lastTarget != null) { removeFromControlMaps(lastTarget, provider, fake); mPendingControlChanged.add(lastTarget); addToPendingControlMaps(lastTarget, provider); } if (target != null) { addToControlMaps(target, provider, fake); mPendingControlChanged.add(target); addToPendingControlMaps(target, provider); } } Loading Loading @@ -364,8 +366,15 @@ class InsetsStateController { } } void notifyControlChanged(InsetsControlTarget target) { mPendingControlChanged.add(target); private void addToPendingControlMaps(@NonNull InsetsControlTarget target, InsetsSourceProvider provider) { final ArrayList<InsetsSourceProvider> array = mPendingTargetProvidersMap.computeIfAbsent(target, key -> new ArrayList<>()); array.add(provider); } void notifyControlChanged(InsetsControlTarget target, InsetsSourceProvider provider) { addToPendingControlMaps(target, provider); notifyPendingInsetsControlChanged(); if (android.view.inputmethod.Flags.refactorInsetsController()) { Loading @@ -376,26 +385,58 @@ class InsetsStateController { } } void notifySurfaceTransactionReady(InsetsSourceProvider provider, long id, boolean ready) { if (ready) { mSurfaceTransactionIds.put(provider.getSource().getId(), id); } else { mSurfaceTransactionIds.delete(provider.getSource().getId()); } } private void notifyPendingInsetsControlChanged() { if (mPendingControlChanged.isEmpty()) { if (mPendingTargetProvidersMap.isEmpty()) { return; } final int size = mSurfaceTransactionIds.size(); final SparseLongArray surfaceTransactionIds = new SparseLongArray(size); for (int i = 0; i < size; i++) { surfaceTransactionIds.append( mSurfaceTransactionIds.keyAt(i), mSurfaceTransactionIds.valueAt(i)); } mDisplayContent.mWmService.mAnimator.addAfterPrepareSurfacesRunnable(() -> { for (int i = mProviders.size() - 1; i >= 0; i--) { final InsetsSourceProvider provider = mProviders.valueAt(i); provider.onSurfaceTransactionApplied(); for (int i = 0; i < size; i++) { final int sourceId = surfaceTransactionIds.keyAt(i); final InsetsSourceProvider provider = mProviders.get(sourceId); if (provider == null) { continue; } provider.onSurfaceTransactionCommitted(surfaceTransactionIds.valueAt(i)); } final ArraySet<InsetsControlTarget> newControlTargets = new ArraySet<>(); int displayId = mDisplayContent.getDisplayId(); for (int i = mPendingControlChanged.size() - 1; i >= 0; i--) { final InsetsControlTarget controlTarget = mPendingControlChanged.valueAt(i); controlTarget.notifyInsetsControlChanged(displayId); if (mControlTargetProvidersMap.containsKey(controlTarget)) { final ArrayMap<InsetsControlTarget, ArrayList<InsetsSourceProvider>> pendingControlMap = mPendingTargetProvidersMap; for (int i = pendingControlMap.size() - 1; i >= 0; i--) { final InsetsControlTarget target = pendingControlMap.keyAt(i); final ArrayList<InsetsSourceProvider> providers = pendingControlMap.valueAt(i); for (int p = providers.size() - 1; p >= 0; p--) { final InsetsSourceProvider provider = providers.get(p); if (provider.isLeashReadyForDispatching(target)) { // Stop waiting for this provider. providers.remove(p); } } if (providers.isEmpty()) { pendingControlMap.removeAt(i); // All controls of this target are ready to be dispatched. target.notifyInsetsControlChanged(displayId); if (mControlTargetProvidersMap.containsKey(target)) { // We only collect targets who get controls, not lose controls. newControlTargets.add(controlTarget); newControlTargets.add(target); } } } mPendingControlChanged.clear(); // This updates the insets visibilities AFTER sending current insets state and controls // to the clients, so that the clients can change the current visibilities to the Loading Loading @@ -424,7 +465,7 @@ class InsetsStateController { * @param target the control target to check. */ boolean hasPendingControls(@NonNull InsetsControlTarget target) { return mPendingControlChanged.contains(target); return mPendingTargetProvidersMap.containsKey(target); } void dump(String prefix, PrintWriter pw) { Loading services/core/java/com/android/server/wm/WindowAnimator.java +19 −28 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; import android.content.Context; import android.os.HandlerExecutor; import android.os.Trace; import android.util.Slog; import android.util.TimeUtils; Loading Loading @@ -68,6 +69,8 @@ public class WindowAnimator { private Choreographer mChoreographer; private final HandlerExecutor mExecutor; /** * Indicates whether we have an animation frame callback scheduled, which will happen at * vsync-app and then schedule the animation tick at the right time (vsync-sf). Loading @@ -79,8 +82,7 @@ public class WindowAnimator { * A list of runnable that need to be run after {@link WindowContainer#prepareSurfaces} is * executed and the corresponding transaction is closed and applied. */ private final ArrayList<Runnable> mAfterPrepareSurfacesRunnables = new ArrayList<>(); private boolean mInExecuteAfterPrepareSurfacesRunnables; private ArrayList<Runnable> mAfterPrepareSurfacesRunnables = new ArrayList<>(); private final SurfaceControl.Transaction mTransaction; Loading @@ -91,6 +93,7 @@ public class WindowAnimator { mTransaction = service.mTransactionFactory.get(); service.mAnimationHandler.runWithScissors( () -> mChoreographer = Choreographer.getSfInstance(), 0 /* timeout */); mExecutor = new HandlerExecutor(service.mAnimationHandler); mAnimationFrameCallback = frameTimeNs -> { synchronized (mService.mGlobalLock) { Loading Loading @@ -198,6 +201,19 @@ public class WindowAnimator { updateRunningExpensiveAnimationsLegacy(); } final ArrayList<Runnable> afterPrepareSurfacesRunnables = mAfterPrepareSurfacesRunnables; if (!afterPrepareSurfacesRunnables.isEmpty()) { mAfterPrepareSurfacesRunnables = new ArrayList<>(); mTransaction.addTransactionCommittedListener(mExecutor, () -> { synchronized (mService.mGlobalLock) { // Traverse in order they were added. for (int i = 0, size = afterPrepareSurfacesRunnables.size(); i < size; i++) { afterPrepareSurfacesRunnables.get(i).run(); } afterPrepareSurfacesRunnables.clear(); } }); } Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "applyTransaction"); mTransaction.apply(); Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER); Loading @@ -205,7 +221,6 @@ public class WindowAnimator { ProtoLog.i(WM_SHOW_TRANSACTIONS, "<<< CLOSE TRANSACTION animate"); mService.mAtmService.mTaskOrganizerController.dispatchPendingEvents(); executeAfterPrepareSurfacesRunnables(); if (DEBUG_WINDOW_TRACE) { Slog.i(TAG, "!!! animate: exit" Loading Loading @@ -287,34 +302,10 @@ public class WindowAnimator { /** * Adds a runnable to be executed after {@link WindowContainer#prepareSurfaces} is called and * the corresponding transaction is closed and applied. * the corresponding transaction is closed, applied, and committed. */ void addAfterPrepareSurfacesRunnable(Runnable r) { // If runnables are already being handled in executeAfterPrepareSurfacesRunnable, then just // immediately execute the runnable passed in. if (mInExecuteAfterPrepareSurfacesRunnables) { r.run(); return; } mAfterPrepareSurfacesRunnables.add(r); scheduleAnimation(); } void executeAfterPrepareSurfacesRunnables() { // Don't even think about to start recursing! if (mInExecuteAfterPrepareSurfacesRunnables) { return; } mInExecuteAfterPrepareSurfacesRunnables = true; // Traverse in order they were added. final int size = mAfterPrepareSurfacesRunnables.size(); for (int i = 0; i < size; i++) { mAfterPrepareSurfacesRunnables.get(i).run(); } mAfterPrepareSurfacesRunnables.clear(); mInExecuteAfterPrepareSurfacesRunnables = false; } } services/tests/servicestests/utils/com/android/server/testutils/StubTransaction.java +10 −0 Original line number Diff line number Diff line Loading @@ -40,12 +40,19 @@ import java.util.concurrent.Executor; public class StubTransaction extends SurfaceControl.Transaction { private HashSet<Runnable> mWindowInfosReportedListeners = new HashSet<>(); private HashSet<SurfaceControl.TransactionCommittedListener> mTransactionCommittedListeners = new HashSet<>(); @Override public void apply() { for (Runnable listener : mWindowInfosReportedListeners) { listener.run(); } for (SurfaceControl.TransactionCommittedListener listener : mTransactionCommittedListeners) { listener.onTransactionCommitted(); } mTransactionCommittedListeners.clear(); } @Override Loading Loading @@ -239,6 +246,9 @@ public class StubTransaction extends SurfaceControl.Transaction { @Override public SurfaceControl.Transaction addTransactionCommittedListener(Executor executor, SurfaceControl.TransactionCommittedListener listener) { SurfaceControl.TransactionCommittedListener listenerInner = () -> executor.execute(listener::onTransactionCommitted); mTransactionCommittedListeners.add(listenerInner); return this; } Loading Loading
services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java +5 −5 Original line number Diff line number Diff line Loading @@ -104,7 +104,7 @@ final class ImeInsetsSourceProvider extends InsetsSourceProvider { mGivenInsetsReady = true; ImeTracker.forLogging().onProgress(mStatsToken, ImeTracker.PHASE_WM_POST_LAYOUT_NOTIFY_CONTROLS_CHANGED); mStateController.notifyControlChanged(mControlTarget); mStateController.notifyControlChanged(mControlTarget, this); setImeShowing(true); } else if (wasServerVisible && mServerVisible && mGivenInsetsReady && givenInsetsPending) { Loading Loading @@ -132,15 +132,15 @@ final class ImeInsetsSourceProvider extends InsetsSourceProvider { } @Override protected boolean isLeashReadyForDispatching() { protected boolean isLeashReadyForDispatching(InsetsControlTarget target) { if (android.view.inputmethod.Flags.refactorInsetsController()) { final WindowState ws = mWindowContainer != null ? mWindowContainer.asWindowState() : null; final boolean isDrawn = ws != null && ws.isDrawn(); return super.isLeashReadyForDispatching() && mServerVisible && isDrawn && mGivenInsetsReady; return super.isLeashReadyForDispatching(target) && mServerVisible && isDrawn && mGivenInsetsReady; } else { return super.isLeashReadyForDispatching(); return super.isLeashReadyForDispatching(target); } } Loading
services/core/java/com/android/server/wm/InsetsSourceProvider.java +32 −8 Original line number Diff line number Diff line Loading @@ -411,7 +411,7 @@ class InsetsSourceProvider { changed = true; } if (changed) { mStateController.notifyControlChanged(mControlTarget); mStateController.notifyControlChanged(mControlTarget, this); } } Loading Loading @@ -556,11 +556,37 @@ class InsetsSourceProvider { } mControl = new InsetsSourceControl(mSource.getId(), mSource.getType(), leash, initiallyVisible, surfacePosition, getInsetsHint()); mStateController.notifySurfaceTransactionReady(this, getSurfaceTransactionId(leash), true); ProtoLog.d(WM_DEBUG_WINDOW_INSETS, "InsetsSource Control %s for target %s", mControl, mControlTarget); } private long getSurfaceTransactionId(SurfaceControl leash) { // Here returns mNativeObject (long) as the ID instead of the leash itself so that // InsetsStateController won't keep referencing the leash unexpectedly. return leash != null ? leash.mNativeObject : 0; } /** * This is called when the surface transaction of the leash initialization has been committed. * * @param id Indicates which transaction is committed so that stale callbacks can be dropped. */ void onSurfaceTransactionCommitted(long id) { if (mIsLeashReadyForDispatching) { return; } if (mControl == null) { return; } if (id != getSurfaceTransactionId(mControl.getLeash())) { return; } mIsLeashReadyForDispatching = true; mStateController.notifySurfaceTransactionReady(this, 0, false); } void startSeamlessRotation() { if (!mSeamlessRotating) { mSeamlessRotating = true; Loading @@ -582,10 +608,6 @@ class InsetsSourceProvider { return true; } void onSurfaceTransactionApplied() { mIsLeashReadyForDispatching = true; } void setClientVisible(boolean clientVisible) { if (mClientVisible == clientVisible) { return; Loading @@ -612,8 +634,9 @@ class InsetsSourceProvider { mServerVisible, mClientVisible); } protected boolean isLeashReadyForDispatching() { return mIsLeashReadyForDispatching; protected boolean isLeashReadyForDispatching(InsetsControlTarget target) { // If the target is not the control target, we are ready for dispatching a null-leash to it. return target != mControlTarget || mIsLeashReadyForDispatching; } /** Loading @@ -626,7 +649,7 @@ class InsetsSourceProvider { @Nullable InsetsSourceControl getControl(InsetsControlTarget target) { if (target == mControlTarget) { if (!isLeashReadyForDispatching() && mControl != null) { if (!isLeashReadyForDispatching(target) && mControl != null) { // The surface transaction of preparing leash is not applied yet. We don't send it // to the client in case that the client applies its transaction sooner than ours // that we could unexpectedly overwrite the surface state. Loading Loading @@ -799,6 +822,7 @@ class InsetsSourceProvider { public void onAnimationCancelled(SurfaceControl animationLeash) { if (mAdapter == this) { mStateController.notifyControlRevoked(mControlTarget, InsetsSourceProvider.this); mStateController.notifySurfaceTransactionReady(InsetsSourceProvider.this, 0, false); mControl = null; mControlTarget = null; mAdapter = null; Loading
services/core/java/com/android/server/wm/InsetsStateController.java +59 −18 Original line number Diff line number Diff line Loading @@ -34,6 +34,7 @@ import android.os.Trace; import android.util.ArrayMap; import android.util.ArraySet; import android.util.SparseArray; import android.util.SparseLongArray; import android.util.proto.ProtoOutputStream; import android.view.InsetsSource; import android.view.InsetsSourceControl; Loading @@ -59,13 +60,14 @@ class InsetsStateController { private final DisplayContent mDisplayContent; private final SparseArray<InsetsSourceProvider> mProviders = new SparseArray<>(); private final SparseLongArray mSurfaceTransactionIds = new SparseLongArray(); private final ArrayMap<InsetsControlTarget, ArrayList<InsetsSourceProvider>> mControlTargetProvidersMap = new ArrayMap<>(); private final ArrayMap<InsetsControlTarget, ArrayList<InsetsSourceProvider>> mPendingTargetProvidersMap = new ArrayMap<>(); private final SparseArray<InsetsControlTarget> mIdControlTargetMap = new SparseArray<>(); private final SparseArray<InsetsControlTarget> mIdFakeControlTargetMap = new SparseArray<>(); private final ArraySet<InsetsControlTarget> mPendingControlChanged = new ArraySet<>(); private final Consumer<WindowState> mDispatchInsetsChanged = w -> { if (w.isReadyToDispatchInsetsState()) { w.notifyInsetsChanged(); Loading Loading @@ -327,11 +329,11 @@ class InsetsStateController { } if (lastTarget != null) { removeFromControlMaps(lastTarget, provider, fake); mPendingControlChanged.add(lastTarget); addToPendingControlMaps(lastTarget, provider); } if (target != null) { addToControlMaps(target, provider, fake); mPendingControlChanged.add(target); addToPendingControlMaps(target, provider); } } Loading Loading @@ -364,8 +366,15 @@ class InsetsStateController { } } void notifyControlChanged(InsetsControlTarget target) { mPendingControlChanged.add(target); private void addToPendingControlMaps(@NonNull InsetsControlTarget target, InsetsSourceProvider provider) { final ArrayList<InsetsSourceProvider> array = mPendingTargetProvidersMap.computeIfAbsent(target, key -> new ArrayList<>()); array.add(provider); } void notifyControlChanged(InsetsControlTarget target, InsetsSourceProvider provider) { addToPendingControlMaps(target, provider); notifyPendingInsetsControlChanged(); if (android.view.inputmethod.Flags.refactorInsetsController()) { Loading @@ -376,26 +385,58 @@ class InsetsStateController { } } void notifySurfaceTransactionReady(InsetsSourceProvider provider, long id, boolean ready) { if (ready) { mSurfaceTransactionIds.put(provider.getSource().getId(), id); } else { mSurfaceTransactionIds.delete(provider.getSource().getId()); } } private void notifyPendingInsetsControlChanged() { if (mPendingControlChanged.isEmpty()) { if (mPendingTargetProvidersMap.isEmpty()) { return; } final int size = mSurfaceTransactionIds.size(); final SparseLongArray surfaceTransactionIds = new SparseLongArray(size); for (int i = 0; i < size; i++) { surfaceTransactionIds.append( mSurfaceTransactionIds.keyAt(i), mSurfaceTransactionIds.valueAt(i)); } mDisplayContent.mWmService.mAnimator.addAfterPrepareSurfacesRunnable(() -> { for (int i = mProviders.size() - 1; i >= 0; i--) { final InsetsSourceProvider provider = mProviders.valueAt(i); provider.onSurfaceTransactionApplied(); for (int i = 0; i < size; i++) { final int sourceId = surfaceTransactionIds.keyAt(i); final InsetsSourceProvider provider = mProviders.get(sourceId); if (provider == null) { continue; } provider.onSurfaceTransactionCommitted(surfaceTransactionIds.valueAt(i)); } final ArraySet<InsetsControlTarget> newControlTargets = new ArraySet<>(); int displayId = mDisplayContent.getDisplayId(); for (int i = mPendingControlChanged.size() - 1; i >= 0; i--) { final InsetsControlTarget controlTarget = mPendingControlChanged.valueAt(i); controlTarget.notifyInsetsControlChanged(displayId); if (mControlTargetProvidersMap.containsKey(controlTarget)) { final ArrayMap<InsetsControlTarget, ArrayList<InsetsSourceProvider>> pendingControlMap = mPendingTargetProvidersMap; for (int i = pendingControlMap.size() - 1; i >= 0; i--) { final InsetsControlTarget target = pendingControlMap.keyAt(i); final ArrayList<InsetsSourceProvider> providers = pendingControlMap.valueAt(i); for (int p = providers.size() - 1; p >= 0; p--) { final InsetsSourceProvider provider = providers.get(p); if (provider.isLeashReadyForDispatching(target)) { // Stop waiting for this provider. providers.remove(p); } } if (providers.isEmpty()) { pendingControlMap.removeAt(i); // All controls of this target are ready to be dispatched. target.notifyInsetsControlChanged(displayId); if (mControlTargetProvidersMap.containsKey(target)) { // We only collect targets who get controls, not lose controls. newControlTargets.add(controlTarget); newControlTargets.add(target); } } } mPendingControlChanged.clear(); // This updates the insets visibilities AFTER sending current insets state and controls // to the clients, so that the clients can change the current visibilities to the Loading Loading @@ -424,7 +465,7 @@ class InsetsStateController { * @param target the control target to check. */ boolean hasPendingControls(@NonNull InsetsControlTarget target) { return mPendingControlChanged.contains(target); return mPendingTargetProvidersMap.containsKey(target); } void dump(String prefix, PrintWriter pw) { Loading
services/core/java/com/android/server/wm/WindowAnimator.java +19 −28 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; import android.content.Context; import android.os.HandlerExecutor; import android.os.Trace; import android.util.Slog; import android.util.TimeUtils; Loading Loading @@ -68,6 +69,8 @@ public class WindowAnimator { private Choreographer mChoreographer; private final HandlerExecutor mExecutor; /** * Indicates whether we have an animation frame callback scheduled, which will happen at * vsync-app and then schedule the animation tick at the right time (vsync-sf). Loading @@ -79,8 +82,7 @@ public class WindowAnimator { * A list of runnable that need to be run after {@link WindowContainer#prepareSurfaces} is * executed and the corresponding transaction is closed and applied. */ private final ArrayList<Runnable> mAfterPrepareSurfacesRunnables = new ArrayList<>(); private boolean mInExecuteAfterPrepareSurfacesRunnables; private ArrayList<Runnable> mAfterPrepareSurfacesRunnables = new ArrayList<>(); private final SurfaceControl.Transaction mTransaction; Loading @@ -91,6 +93,7 @@ public class WindowAnimator { mTransaction = service.mTransactionFactory.get(); service.mAnimationHandler.runWithScissors( () -> mChoreographer = Choreographer.getSfInstance(), 0 /* timeout */); mExecutor = new HandlerExecutor(service.mAnimationHandler); mAnimationFrameCallback = frameTimeNs -> { synchronized (mService.mGlobalLock) { Loading Loading @@ -198,6 +201,19 @@ public class WindowAnimator { updateRunningExpensiveAnimationsLegacy(); } final ArrayList<Runnable> afterPrepareSurfacesRunnables = mAfterPrepareSurfacesRunnables; if (!afterPrepareSurfacesRunnables.isEmpty()) { mAfterPrepareSurfacesRunnables = new ArrayList<>(); mTransaction.addTransactionCommittedListener(mExecutor, () -> { synchronized (mService.mGlobalLock) { // Traverse in order they were added. for (int i = 0, size = afterPrepareSurfacesRunnables.size(); i < size; i++) { afterPrepareSurfacesRunnables.get(i).run(); } afterPrepareSurfacesRunnables.clear(); } }); } Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "applyTransaction"); mTransaction.apply(); Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER); Loading @@ -205,7 +221,6 @@ public class WindowAnimator { ProtoLog.i(WM_SHOW_TRANSACTIONS, "<<< CLOSE TRANSACTION animate"); mService.mAtmService.mTaskOrganizerController.dispatchPendingEvents(); executeAfterPrepareSurfacesRunnables(); if (DEBUG_WINDOW_TRACE) { Slog.i(TAG, "!!! animate: exit" Loading Loading @@ -287,34 +302,10 @@ public class WindowAnimator { /** * Adds a runnable to be executed after {@link WindowContainer#prepareSurfaces} is called and * the corresponding transaction is closed and applied. * the corresponding transaction is closed, applied, and committed. */ void addAfterPrepareSurfacesRunnable(Runnable r) { // If runnables are already being handled in executeAfterPrepareSurfacesRunnable, then just // immediately execute the runnable passed in. if (mInExecuteAfterPrepareSurfacesRunnables) { r.run(); return; } mAfterPrepareSurfacesRunnables.add(r); scheduleAnimation(); } void executeAfterPrepareSurfacesRunnables() { // Don't even think about to start recursing! if (mInExecuteAfterPrepareSurfacesRunnables) { return; } mInExecuteAfterPrepareSurfacesRunnables = true; // Traverse in order they were added. final int size = mAfterPrepareSurfacesRunnables.size(); for (int i = 0; i < size; i++) { mAfterPrepareSurfacesRunnables.get(i).run(); } mAfterPrepareSurfacesRunnables.clear(); mInExecuteAfterPrepareSurfacesRunnables = false; } }
services/tests/servicestests/utils/com/android/server/testutils/StubTransaction.java +10 −0 Original line number Diff line number Diff line Loading @@ -40,12 +40,19 @@ import java.util.concurrent.Executor; public class StubTransaction extends SurfaceControl.Transaction { private HashSet<Runnable> mWindowInfosReportedListeners = new HashSet<>(); private HashSet<SurfaceControl.TransactionCommittedListener> mTransactionCommittedListeners = new HashSet<>(); @Override public void apply() { for (Runnable listener : mWindowInfosReportedListeners) { listener.run(); } for (SurfaceControl.TransactionCommittedListener listener : mTransactionCommittedListeners) { listener.onTransactionCommitted(); } mTransactionCommittedListeners.clear(); } @Override Loading Loading @@ -239,6 +246,9 @@ public class StubTransaction extends SurfaceControl.Transaction { @Override public SurfaceControl.Transaction addTransactionCommittedListener(Executor executor, SurfaceControl.TransactionCommittedListener listener) { SurfaceControl.TransactionCommittedListener listenerInner = () -> executor.execute(listener::onTransactionCommitted); mTransactionCommittedListeners.add(listenerInner); return this; } Loading