Fix bug 5045004 - onActionModeFinished happens well before the
ActionBar is actually gone

Defer calling onDestroyActionMode until the action bar UI has fully
transitioned out of the mode and any bar-hiding layout change is ready
to happen. This helps apps better respond to layout changes resulting
from action mode UI.

Change-Id: I8e560ec566f4c3fa4a701c4b3aeb531c16169168
diff --git a/core/java/com/android/internal/app/ActionBarImpl.java b/core/java/com/android/internal/app/ActionBarImpl.java
index f0a9441..95f1f98 100644
--- a/core/java/com/android/internal/app/ActionBarImpl.java
+++ b/core/java/com/android/internal/app/ActionBarImpl.java
@@ -76,7 +76,9 @@
     private TabImpl mSelectedTab;
     private int mSavedTabPosition = INVALID_POSITION;
     
-    private ActionMode mActionMode;
+    ActionModeImpl mActionMode;
+    ActionMode mDeferredDestroyActionMode;
+    ActionMode.Callback mDeferredModeDestroyCallback;
     
     private boolean mLastMenuVisibility;
     private ArrayList<OnMenuVisibilityListener> mMenuVisibilityListeners =
@@ -104,10 +106,12 @@
         public void onAnimationEnd(Animator animation) {
             if (mContentView != null) {
                 mContentView.setTranslationY(0);
+                mContainerView.setTranslationY(0);
             }
             mContainerView.setVisibility(View.GONE);
             mContainerView.setTransitioning(false);
             mCurrentShowAnim = null;
+            completeDeferredDestroyActionMode();
         }
     };
 
@@ -207,6 +211,14 @@
         mTabScrollView = tabScroller;
     }
 
+    void completeDeferredDestroyActionMode() {
+        if (mDeferredModeDestroyCallback != null) {
+            mDeferredModeDestroyCallback.onDestroyActionMode(mDeferredDestroyActionMode);
+            mDeferredDestroyActionMode = null;
+            mDeferredModeDestroyCallback = null;
+        }
+    }
+
     /**
      * Enables or disables animation between show/hide states.
      * If animation is disabled using this method, animations in progress
@@ -357,14 +369,16 @@
     }
 
     public ActionMode startActionMode(ActionMode.Callback callback) {
+        boolean wasHidden = false;
         if (mActionMode != null) {
+            wasHidden = mWasHiddenBeforeMode;
             mActionMode.finish();
         }
 
         mContextView.killMode();
         ActionModeImpl mode = new ActionModeImpl(callback);
         if (mode.dispatchOnCreate()) {
-            mWasHiddenBeforeMode = !isShowing();
+            mWasHiddenBeforeMode = !isShowing() || wasHidden;
             mode.invalidate();
             mContextView.initForMode(mode);
             animateToMode(true);
@@ -577,7 +591,9 @@
     }
 
     void animateToMode(boolean toActionMode) {
-        show(false);
+        if (toActionMode) {
+            show(false);
+        }
         if (mCurrentModeAnim != null) {
             mCurrentModeAnim.end();
         }
@@ -621,7 +637,16 @@
                 return;
             }
 
-            mCallback.onDestroyActionMode(this);
+            // If we were hidden before the mode was shown, defer the onDestroy
+            // callback until the animation is finished and associated relayout
+            // is about to happen. This lets apps better anticipate visibility
+            // and layout behavior.
+            if (mWasHiddenBeforeMode) {
+                mDeferredDestroyActionMode = this;
+                mDeferredModeDestroyCallback = mCallback;
+            } else {
+                mCallback.onDestroyActionMode(this);
+            }
             mCallback = null;
             animateToMode(false);