From 2408b1e62c0facac74545ad97705ca4386323956 Mon Sep 17 00:00:00 2001 From: Matt Casey Date: Tue, 22 Aug 2023 19:58:56 +0000 Subject: Defer finish() to onStop() when doing shared transition We used to immediately finish() after starting the shared element transition. In high-latency situations, this transition took a while to start and resulted in some broken UI in window manager. Instead of finishing immediately, we finish onStop() such that we can wait for the transition to actually begin. Bug: 292158050 Test: Share an image that has high latency to load. Validate that the UI looks normal (albeit slow) when the edit transition happens (see bug). Change-Id: I66686398781aeea630c500c48198c5febc1e8fc2 --- .../android/intentresolver/ChooserActivity.java | 106 +++------------------ 1 file changed, 14 insertions(+), 92 deletions(-) (limited to 'java/src') diff --git a/java/src/com/android/intentresolver/ChooserActivity.java b/java/src/com/android/intentresolver/ChooserActivity.java index 8edbba08..b5899e5c 100644 --- a/java/src/com/android/intentresolver/ChooserActivity.java +++ b/java/src/com/android/intentresolver/ChooserActivity.java @@ -27,7 +27,6 @@ import static android.stats.devicepolicy.nano.DevicePolicyEnums.RESOLVER_EMPTY_S import static com.android.internal.util.LatencyTracker.ACTION_LOAD_SHARE_SHEET; import android.annotation.IntDef; -import android.annotation.NonNull; import android.annotation.Nullable; import android.app.Activity; import android.app.ActivityManager; @@ -66,9 +65,6 @@ import android.view.ViewGroup; import android.view.ViewGroup.LayoutParams; import android.view.ViewTreeObserver; import android.view.WindowInsets; -import android.view.animation.AlphaAnimation; -import android.view.animation.Animation; -import android.view.animation.LinearInterpolator; import android.widget.TextView; import androidx.annotation.MainThread; @@ -238,6 +234,13 @@ public class ChooserActivity extends ResolverActivity implements private final SparseArray mProfileRecords = new SparseArray<>(); private boolean mExcludeSharedText = false; + /** + * When we intend to finish the activity with a shared element transition, we can't immediately + * finish() when the transition is invoked, as the receiving end may not be able to start the + * animation and the UI breaks if this takes too long. Instead we defer finishing until onStop + * in order to wait for the transition to begin. + */ + private boolean mFinishWhenStopped = false; @Inject public ChooserActivity(ViewModelComponent.Builder builder) { @@ -645,8 +648,7 @@ public class ChooserActivity extends ResolverActivity implements protected void onResume() { super.onResume(); Log.d(TAG, "onResume: " + getComponentName().flattenToShortString()); - maybeCancelFinishAnimation(); - + mFinishWhenStopped = false; mRefinementManager.onActivityResume(); } @@ -747,7 +749,8 @@ public class ChooserActivity extends ResolverActivity implements super.onStop(); mRefinementManager.onActivityStop(isChangingConfigurations()); - if (maybeCancelFinishAnimation()) { + if (mFinishWhenStopped) { + mFinishWhenStopped = false; finish(); } } @@ -1363,7 +1366,10 @@ public class ChooserActivity extends ResolverActivity implements ChooserActivity.this, sharedElement, sharedElementName); safelyStartActivityAsUser( targetInfo, getPersonalProfileUserHandle(), options.toBundle()); - startFinishAnimation(); + // Can't finish right away because the shared element transition may not + // be ready to start. + mFinishWhenStopped = true; + } }, (status) -> { @@ -1748,25 +1754,6 @@ public class ChooserActivity extends ResolverActivity implements contentPreviewContainer.setVisibility(View.GONE); } - private void startFinishAnimation() { - View rootView = findRootView(); - if (rootView != null) { - rootView.startAnimation(new FinishAnimation(this, rootView)); - } - } - - private boolean maybeCancelFinishAnimation() { - View rootView = findRootView(); - Animation animation = (rootView == null) ? null : rootView.getAnimation(); - if (animation instanceof FinishAnimation) { - boolean hasEnded = animation.hasEnded(); - animation.cancel(); - rootView.clearAnimation(); - return !hasEnded; - } - return false; - } - private View findRootView() { if (mContentView == null) { mContentView = findViewById(android.R.id.content); @@ -1847,71 +1834,6 @@ public class ChooserActivity extends ResolverActivity implements } } - /** - * Used in combination with the scene transition when launching the image editor - */ - private static class FinishAnimation extends AlphaAnimation implements - Animation.AnimationListener { - @Nullable - private Activity mActivity; - @Nullable - private View mRootView; - private final float mFromAlpha; - - FinishAnimation(@NonNull Activity activity, @NonNull View rootView) { - super(rootView.getAlpha(), 0.0f); - mActivity = activity; - mRootView = rootView; - mFromAlpha = rootView.getAlpha(); - setInterpolator(new LinearInterpolator()); - long duration = activity.getWindow().getTransitionBackgroundFadeDuration(); - setDuration(duration); - // The scene transition animation looks better when it's not overlapped with this - // fade-out animation thus the delay. - // It is most likely that the image editor will cause this activity to stop and this - // animation will be cancelled in the background without running (i.e. we'll animate - // only when this activity remains partially visible after the image editor launch). - setStartOffset(duration); - super.setAnimationListener(this); - } - - @Override - public void setAnimationListener(AnimationListener listener) { - throw new UnsupportedOperationException(); - } - - @Override - public void cancel() { - if (mRootView != null) { - mRootView.setAlpha(mFromAlpha); - } - cleanup(); - super.cancel(); - } - - @Override - public void onAnimationStart(Animation animation) { - } - - @Override - public void onAnimationEnd(Animation animation) { - Activity activity = mActivity; - cleanup(); - if (activity != null) { - activity.finish(); - } - } - - @Override - public void onAnimationRepeat(Animation animation) { - } - - private void cleanup() { - mActivity = null; - mRootView = null; - } - } - @Override protected void maybeLogProfileChange() { getEventLog().logSharesheetProfileChanged(); -- cgit v1.2.3-59-g8ed1b