diff options
| author | 2025-01-03 12:17:45 -0800 | |
|---|---|---|
| committer | 2025-01-03 12:25:00 -0800 | |
| commit | efee0571730e4cfeb6902d232d02f7883f40292e (patch) | |
| tree | 66fc03ead0009e9aa39e40ba230abf19b3e87911 | |
| parent | 6d8ad4dbec052d6327b5c96e82b58d6da8a5ed64 (diff) | |
Add a 100ms timeout when waiting for animation finish.
Also improve ViewUIComponent's detach flow.
Flag: EXEMPTED - bug fix
Test: manual test
Change-Id: Iedf747f1a039bfb06be36cc0c3ebaa9125943a51
2 files changed, 52 insertions, 12 deletions
diff --git a/packages/SystemUI/animation/lib/src/com/android/systemui/animation/OriginRemoteTransition.java b/packages/SystemUI/animation/lib/src/com/android/systemui/animation/OriginRemoteTransition.java index 7d27a562f536..91fad4fb6dc2 100644 --- a/packages/SystemUI/animation/lib/src/com/android/systemui/animation/OriginRemoteTransition.java +++ b/packages/SystemUI/animation/lib/src/com/android/systemui/animation/OriginRemoteTransition.java @@ -43,6 +43,7 @@ import com.android.wm.shell.shared.TransitionUtil; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; /** * An implementation of {@link IRemoteTransition} that accepts a {@link UIComponent} as the origin @@ -52,6 +53,7 @@ import java.util.List; */ public class OriginRemoteTransition extends IRemoteTransition.Stub { private static final String TAG = "OriginRemoteTransition"; + private static final long FINISH_ANIMATION_TIMEOUT_MS = 100; private final Context mContext; private final boolean mIsEntry; @@ -248,23 +250,20 @@ public class OriginRemoteTransition extends IRemoteTransition.Stub { if (mIsEntry) { if (!closingSurfaces.isEmpty()) { - tmpTransaction - .setRelativeLayer(mOriginLeash, closingSurfaces.get(0), 1); + tmpTransaction.setRelativeLayer(mOriginLeash, closingSurfaces.get(0), 1); } else { logW("Missing closing surface is entry transition"); } if (!openingSurfaces.isEmpty()) { - tmpTransaction - .setRelativeLayer( - openingSurfaces.get(openingSurfaces.size() - 1), mOriginLeash, 1); + tmpTransaction.setRelativeLayer( + openingSurfaces.get(openingSurfaces.size() - 1), mOriginLeash, 1); } else { logW("Missing opening surface is entry transition"); } } else { if (!openingSurfaces.isEmpty()) { - tmpTransaction - .setRelativeLayer(mOriginLeash, openingSurfaces.get(0), 1); + tmpTransaction.setRelativeLayer(mOriginLeash, openingSurfaces.get(0), 1); } else { logW("Missing opening surface is exit transition"); } @@ -293,12 +292,26 @@ public class OriginRemoteTransition extends IRemoteTransition.Stub { private void finishAnimation(boolean finished) { logD("finishAnimation: finished=" + finished); + OneShotRunnable finishInternalRunnable = new OneShotRunnable(this::finishInternal); + Runnable timeoutRunnable = + () -> { + Log.w(TAG, "Timeout waiting for surface transaction!"); + finishInternalRunnable.run(); + }; + Runnable committedRunnable = + () -> { + // Remove the timeout runnable. + mHandler.removeCallbacks(timeoutRunnable); + finishInternalRunnable.run(); + }; if (mAnimator == null) { // The transition didn't start. Ensure we apply the start transaction and report // finish afterwards. mStartTransaction - .addTransactionCommittedListener(mHandler::post, this::finishInternal) + .addTransactionCommittedListener(mHandler::post, committedRunnable::run) .apply(); + // Call finishInternal() anyway after the timeout. + mHandler.postDelayed(timeoutRunnable, FINISH_ANIMATION_TIMEOUT_MS); return; } mAnimator = null; @@ -306,8 +319,10 @@ public class OriginRemoteTransition extends IRemoteTransition.Stub { mPlayer.onEnd(finished); // Detach the origin from the transition leash and report finish after it's done. mOriginTransaction - .detachFromTransitionLeash(mOrigin, mHandler::post, this::finishInternal) + .detachFromTransitionLeash(mOrigin, mHandler::post, committedRunnable) .commit(); + // Call finishInternal() anyway after the timeout. + mHandler.postDelayed(timeoutRunnable, FINISH_ANIMATION_TIMEOUT_MS); } private void finishInternal() { @@ -423,6 +438,23 @@ public class OriginRemoteTransition extends IRemoteTransition.Stub { return out; } + /** A {@link Runnable} that will only run once. */ + private static class OneShotRunnable implements Runnable { + private final AtomicBoolean mDone = new AtomicBoolean(); + private final Runnable mRunnable; + + OneShotRunnable(Runnable runnable) { + this.mRunnable = runnable; + } + + @Override + public void run() { + if (!mDone.getAndSet(true)) { + mRunnable.run(); + } + } + } + /** * An interface that represents an origin transitions. * diff --git a/packages/SystemUI/animation/lib/src/com/android/systemui/animation/ViewUIComponent.java b/packages/SystemUI/animation/lib/src/com/android/systemui/animation/ViewUIComponent.java index d0404ec02306..7c219c6ca921 100644 --- a/packages/SystemUI/animation/lib/src/com/android/systemui/animation/ViewUIComponent.java +++ b/packages/SystemUI/animation/lib/src/com/android/systemui/animation/ViewUIComponent.java @@ -29,6 +29,7 @@ import android.view.Surface; import android.view.SurfaceControl; import android.view.View; import android.view.ViewGroup; +import android.view.ViewRootImpl; import android.view.ViewTreeObserver.OnDrawListener; import java.util.ArrayList; @@ -131,7 +132,6 @@ public class ViewUIComponent implements UIComponent { mView.getViewTreeObserver().removeOnDrawListener(mOnDrawListener); // Restore view visibility mView.setVisibility(mVisibleOverride ? View.VISIBLE : View.INVISIBLE); - mView.invalidate(); // Clean up surfaces. SurfaceControl.Transaction t = new SurfaceControl.Transaction(); t.reparent(sc, null) @@ -142,8 +142,16 @@ public class ViewUIComponent implements UIComponent { sc.release(); executor.execute(onDone); }); - // Apply transaction AFTER the view is drawn. - mView.getRootSurfaceControl().applyTransactionOnDraw(t); + ViewRootImpl viewRoot = mView.getViewRootImpl(); + if (viewRoot == null) { + t.apply(); + } else { + // Apply transaction AFTER the view is drawn. + viewRoot.applyTransactionOnDraw(t); + // Request layout to force redrawing the entire view tree, so that the transaction is + // guaranteed to be applied. + viewRoot.requestLayout(); + } } @Override |