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
*/