Postpone hiding old tab during tab switch until new tab is ready

When switching tabs, postpone hiding the old tab until the
new tab is ready.  Also postpone destroying a tab if it is
waiting to be hidden.

Change-Id: I0989c7b28f928829bd95ef9d0679493e25be0d83
diff --git a/src/com/android/browser/BaseUi.java b/src/com/android/browser/BaseUi.java
index 2b4b170..45bd656 100644
--- a/src/com/android/browser/BaseUi.java
+++ b/src/com/android/browser/BaseUi.java
@@ -267,11 +267,14 @@
     @Override
     public void setActiveTab(final Tab tab) {
         if (tab == null) return;
+        Tab tabToRemove = null;
+        BrowserWebView webViewToWaitFor = null;
+
         // block unnecessary focus change animations during tab switch
         mBlockFocusAnimations = true;
         mHandler.removeMessages(MSG_HIDE_TITLEBAR);
         if ((tab != mActiveTab) && (mActiveTab != null)) {
-            removeTabFromContentView(mActiveTab);
+            tabToRemove = mActiveTab;
             WebView web = mActiveTab.getWebView();
             if (web != null) {
                 web.setOnTouchListener(null);
@@ -291,6 +294,7 @@
                 web.setTitleBar(mTitleBar);
                 mTitleBar.onScrollChanged();
             }
+            webViewToWaitFor = web;
         }
         mTitleBar.bringToFront();
         tab.getTopWindow().requestFocus();
@@ -299,6 +303,63 @@
         onProgressChanged(tab);
         mNavigationBar.setIncognitoMode(tab.isPrivateBrowsingEnabled());
         mBlockFocusAnimations = false;
+
+        scheduleRemoveTab(tabToRemove, webViewToWaitFor);
+    }
+
+    Tab mTabToRemove = null;
+    BrowserWebView mWebViewToWaitFor = null;
+    int mNumRemoveTries = 0;
+
+    protected void scheduleRemoveTab(Tab tab, BrowserWebView webview) {
+        //remove previously scehduled tab
+        if (mTabToRemove != null) {
+            removeTabFromContentView(mTabToRemove);
+            mTabToRemove.performPostponedDestroy();
+        }
+        mTabToRemove = tab;
+        mWebViewToWaitFor = webview;
+        mNumRemoveTries = 0;
+
+        if (mTabToRemove != null) {
+            mTabToRemove.postponeDestroy();
+            android.os.Handler handler = mTitleBar.getHandler();
+            handler.postDelayed(new Runnable() {
+                public void run() {
+                    tryRemoveTab();
+                }
+            }, 33); /*we know at this point for sure that the new tab is not ready
+                      since it's just getting created.  It'll be at least 1 frame's
+                      time that the new tab will painting something, and another 1
+                      frame's time that we're sure the swap is done.  It is possible
+                      that the swap is finish right the way, but unless use use EGL
+                      fence we can never be sure.  So wait for 2 frames before trying
+                      to remove the tab.  It is possible that the tab is still not
+                      ready after 2 frames, but this is good enough.*/
+        }
+    }
+
+    protected void tryRemoveTab() {
+        mNumRemoveTries++;
+        if (mNumRemoveTries < 20 && mWebViewToWaitFor != null) {
+            if (!mWebViewToWaitFor.isReady()) {
+                android.os.Handler handler = mTitleBar.getHandler();
+                handler.postDelayed(new Runnable() {
+                    public void run() {
+                        tryRemoveTab();
+                    }
+                }, 33); /*if the new tab is still not ready, wait another 2 frames
+                          before trying again.  1 frame for the tab to render the first
+                          frame, another 1 frame to make sure the swap is done*/
+                return;
+            }
+        }
+        if (mTabToRemove != null) {
+            removeTabFromContentView(mTabToRemove);
+            mTabToRemove.performPostponedDestroy();
+        }
+        mTabToRemove = null;
+        mWebViewToWaitFor = null;
     }
 
     protected void updateUrlBarAutoShowManagerTarget() {
diff --git a/src/com/android/browser/Tab.java b/src/com/android/browser/Tab.java
index 4889efe..26f9152 100644
--- a/src/com/android/browser/Tab.java
+++ b/src/com/android/browser/Tab.java
@@ -1360,6 +1360,11 @@
      * Destroy the tab's main WebView and subWindow if any
      */
     void destroy() {
+        if (mPostponeDestroy) {
+            mShouldDestroy = true;
+            return;
+        }
+        mShouldDestroy = false;
         if (mMainView != null) {
             dismissSubWindow();
             // save the WebView to call destroy() after detach it from the tab
@@ -1369,6 +1374,20 @@
         }
     }
 
+    private boolean mPostponeDestroy = false;
+    private boolean mShouldDestroy = false;
+
+    public void postponeDestroy() {
+        mPostponeDestroy = true;
+    }
+
+    public void performPostponedDestroy() {
+        mPostponeDestroy = false;
+        if (mShouldDestroy) {
+            destroy();
+        }
+    }
+
     /**
      * Remove the tab from the parent
      */