From 8d6ac26504ae3708732e0f5c0df02efb17937d9b Mon Sep 17 00:00:00 2001 From: Andrii Kulian Date: Wed, 8 Jun 2016 13:14:19 -0700 Subject: [PATCH] Reinflate primary action mode view after detach When app is resized in multi-window mode we preserve the window along with the decor view. If action mode view was shown before such config change, its view is detached, but the mPrimaryActionModeView variable is not cleared. So when action mode view is shown again after that it thinks that its view is still alive. This CL adds additional check to inflate new mPrimaryActionModeView if it is not attached to any window. Bug: 28971666 Change-Id: Ia8c24d4322be32e8b2c8967301beb3a4d889d501 --- .../android/internal/policy/DecorView.java | 29 +++++++++++++++---- 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java index 7e38d9bc742d1..3cf7a4e6b9ecc 100644 --- a/core/java/com/android/internal/policy/DecorView.java +++ b/core/java/com/android/internal/policy/DecorView.java @@ -1550,7 +1550,13 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind private ActionMode createStandaloneActionMode(ActionMode.Callback callback) { endOnGoingFadeAnimation(); cleanupPrimaryActionMode(); - if (mPrimaryActionModeView == null) { + // We want to create new mPrimaryActionModeView in two cases: if there is no existing + // instance at all, or if there is one, but it is detached from window. The latter case + // might happen when app is resized in multi-window mode and decor view is preserved + // along with the main app window. Keeping mPrimaryActionModeView reference doesn't cause + // app memory leaks because killMode() is called when the dismiss animation ends and from + // cleanupPrimaryActionMode() invocation above. + if (mPrimaryActionModeView == null || !mPrimaryActionModeView.isAttachedToWindow()) { if (mWindow.isFloating()) { // Use the action bar theme. final TypedValue outValue = new TypedValue(); @@ -1616,6 +1622,7 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind ViewStub stub = (ViewStub) findViewById(R.id.action_mode_bar_stub); if (stub != null) { mPrimaryActionModeView = (ActionBarContextView) stub.inflate(); + mPrimaryActionModePopup = null; } } } @@ -2278,9 +2285,14 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind } if (mPrimaryActionModeView != null) { endOnGoingFadeAnimation(); + // Store action mode view reference, so we can access it safely when animation + // ends. mPrimaryActionModePopup is set together with mPrimaryActionModeView, + // so no need to store reference to it in separate variable. + final ActionBarContextView lastActionModeView = mPrimaryActionModeView; mFadeAnim = ObjectAnimator.ofFloat(mPrimaryActionModeView, View.ALPHA, 1f, 0f); mFadeAnim.addListener(new Animator.AnimatorListener() { + @Override public void onAnimationStart(Animator animation) { @@ -2288,12 +2300,17 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind @Override public void onAnimationEnd(Animator animation) { - mPrimaryActionModeView.setVisibility(GONE); - if (mPrimaryActionModePopup != null) { - mPrimaryActionModePopup.dismiss(); + // If mPrimaryActionModeView has changed - it means that we've + // cleared the content while preserving decor view. We don't + // want to change the state of new instances accidentally here. + if (lastActionModeView == mPrimaryActionModeView) { + lastActionModeView.setVisibility(GONE); + if (mPrimaryActionModePopup != null) { + mPrimaryActionModePopup.dismiss(); + } + lastActionModeView.killMode(); + mFadeAnim = null; } - mPrimaryActionModeView.removeAllViews(); - mFadeAnim = null; } @Override