diff options
3 files changed, 92 insertions, 19 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 91fad4fb6dc2..56d85ab8aca0 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 @@ -107,7 +107,7 @@ public class OriginRemoteTransition extends IRemoteTransition.Stub { IBinder mergeTarget, IRemoteTransitionFinishedCallback finishCallback) { logD("mergeAnimation - " + info); - mHandler.post(this::cancel); + cancel(); } @Override @@ -129,7 +129,7 @@ public class OriginRemoteTransition extends IRemoteTransition.Stub { @Override public void onTransitionConsumed(IBinder transition, boolean aborted) { logD("onTransitionConsumed - aborted: " + aborted); - mHandler.post(this::cancel); + cancel(); } private void startAnimationInternal( @@ -342,11 +342,14 @@ public class OriginRemoteTransition extends IRemoteTransition.Stub { mFinishCallback = null; } - private void cancel() { + public void cancel() { logD("cancel()"); - if (mAnimator != null) { - mAnimator.cancel(); - } + mHandler.post( + () -> { + if (mAnimator != null) { + mAnimator.cancel(); + } + }); } private static void logD(String msg) { diff --git a/packages/SystemUI/animation/lib/src/com/android/systemui/animation/OriginTransitionSession.java b/packages/SystemUI/animation/lib/src/com/android/systemui/animation/OriginTransitionSession.java index 6d6aa8895ed0..cb3dfb9e78e7 100644 --- a/packages/SystemUI/animation/lib/src/com/android/systemui/animation/OriginTransitionSession.java +++ b/packages/SystemUI/animation/lib/src/com/android/systemui/animation/OriginTransitionSession.java @@ -43,6 +43,7 @@ import java.util.function.Supplier; /** * A session object that holds origin transition states for starting an activity from an on-screen * UI component and smoothly transitioning back from the activity to the same UI component. + * * @hide */ public class OriginTransitionSession { @@ -143,6 +144,12 @@ public class OriginTransitionSession { logE("Unable to cancel origin transition!", e); } } + if (mEntryTransition instanceof OriginRemoteTransition) { + ((OriginRemoteTransition) mEntryTransition).cancel(); + } + if (mExitTransition instanceof OriginRemoteTransition) { + ((OriginRemoteTransition) mExitTransition).cancel(); + } } private boolean hasEntryTransition() { @@ -182,6 +189,7 @@ public class OriginTransitionSession { /** * A builder to build a {@link OriginTransitionSession}. + * * @hide */ public static class Builder { 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 7c219c6ca921..2e8f92839fa6 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 @@ -24,13 +24,15 @@ import android.graphics.PorterDuff; import android.graphics.Rect; import android.graphics.RectF; import android.os.Build; +import android.os.Handler; +import android.os.Looper; import android.util.Log; 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 android.view.ViewTreeObserver; import java.util.ArrayList; import java.util.List; @@ -51,8 +53,9 @@ public class ViewUIComponent implements UIComponent { private final Path mClippingPath = new Path(); private final Outline mClippingOutline = new Outline(); - private final OnDrawListener mOnDrawListener = this::postDraw; + private final LifecycleListener mLifecycleListener = new LifecycleListener(); private final View mView; + private final Handler mMainHandler; @Nullable private SurfaceControl mSurfaceControl; @Nullable private Surface mSurface; @@ -62,6 +65,7 @@ public class ViewUIComponent implements UIComponent { public ViewUIComponent(View view) { mView = view; + mMainHandler = new Handler(Looper.getMainLooper()); } /** @@ -110,11 +114,11 @@ public class ViewUIComponent implements UIComponent { t.reparent(mSurfaceControl, transitionLeash).show(mSurfaceControl); // Make sure view draw triggers surface draw. - mView.getViewTreeObserver().addOnDrawListener(mOnDrawListener); + mLifecycleListener.register(); // Make the view invisible AFTER the surface is shown. t.addTransactionCommittedListener( - mView::post, + this::post, () -> { logD("Surface attached!"); forceDraw(); @@ -129,14 +133,14 @@ public class ViewUIComponent implements UIComponent { SurfaceControl sc = mSurfaceControl; mSurface = null; mSurfaceControl = null; - mView.getViewTreeObserver().removeOnDrawListener(mOnDrawListener); + mLifecycleListener.unregister(); // Restore view visibility mView.setVisibility(mVisibleOverride ? View.VISIBLE : View.INVISIBLE); // Clean up surfaces. SurfaceControl.Transaction t = new SurfaceControl.Transaction(); t.reparent(sc, null) .addTransactionCommittedListener( - mView::post, + this::post, () -> { s.release(); sc.release(); @@ -269,7 +273,66 @@ public class ViewUIComponent implements UIComponent { return; } mDirty = true; - mView.post(this::draw); + post(this::draw); + } + + private void post(Runnable r) { + if (mView.isAttachedToWindow()) { + mView.post(r); + } else { + // If the view is detached from window, {@code View.post()} will postpone the action + // until the view is attached again. However, we don't know if the view will be attached + // again, so we post the action to the main thread in this case. This could lead to race + // condition if the attachment change caused a thread switching, and it's the caller's + // responsibility to ensure the window attachment state doesn't change unexpectedly. + if (DEBUG) { + Log.w(TAG, mView + " is not attached. Posting action to main thread!"); + } + mMainHandler.post(r); + } + } + + /** A listener for monitoring view life cycles. */ + private class LifecycleListener + implements ViewTreeObserver.OnDrawListener, View.OnAttachStateChangeListener { + private boolean mRegistered; + + @Override + public void onDraw() { + // View draw should trigger surface draw. + postDraw(); + } + + @Override + public void onViewAttachedToWindow(View v) { + // empty + } + + @Override + public void onViewDetachedFromWindow(View v) { + Log.w( + TAG, + v + " is detached from the window. Unregistering the life cycle listener ..."); + unregister(); + } + + public void register() { + if (mRegistered) { + return; + } + mRegistered = true; + mView.getViewTreeObserver().addOnDrawListener(this); + mView.addOnAttachStateChangeListener(this); + } + + public void unregister() { + if (!mRegistered) { + return; + } + mRegistered = false; + mView.getViewTreeObserver().removeOnDrawListener(this); + mView.removeOnAttachStateChangeListener(this); + } } /** @hide */ @@ -278,34 +341,33 @@ public class ViewUIComponent implements UIComponent { @Override public Transaction setAlpha(ViewUIComponent ui, float alpha) { - mChanges.add(() -> ui.mView.post(() -> ui.setAlpha(alpha))); + mChanges.add(() -> ui.post(() -> ui.setAlpha(alpha))); return this; } @Override public Transaction setVisible(ViewUIComponent ui, boolean visible) { - mChanges.add(() -> ui.mView.post(() -> ui.setVisible(visible))); + mChanges.add(() -> ui.post(() -> ui.setVisible(visible))); return this; } @Override public Transaction setBounds(ViewUIComponent ui, Rect bounds) { - mChanges.add(() -> ui.mView.post(() -> ui.setBounds(bounds))); + mChanges.add(() -> ui.post(() -> ui.setBounds(bounds))); return this; } @Override public Transaction attachToTransitionLeash( ViewUIComponent ui, SurfaceControl transitionLeash, int w, int h) { - mChanges.add( - () -> ui.mView.post(() -> ui.attachToTransitionLeash(transitionLeash, w, h))); + mChanges.add(() -> ui.post(() -> ui.attachToTransitionLeash(transitionLeash, w, h))); return this; } @Override public Transaction detachFromTransitionLeash( ViewUIComponent ui, Executor executor, Runnable onDone) { - mChanges.add(() -> ui.mView.post(() -> ui.detachFromTransitionLeash(executor, onDone))); + mChanges.add(() -> ui.post(() -> ui.detachFromTransitionLeash(executor, onDone))); return this; } |