Index: chrome/android/java/src/org/chromium/chrome/browser/tabmodel/document/AsyncDocumentLauncher.java |
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/document/AsyncDocumentLauncher.java b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/document/AsyncDocumentLauncher.java |
new file mode 100644 |
index 0000000000000000000000000000000000000000..98d7a188917678ca8837c74b63b43ccdfbb118a6 |
--- /dev/null |
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/document/AsyncDocumentLauncher.java |
@@ -0,0 +1,112 @@ |
+// Copyright 2015 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+package org.chromium.chrome.browser.tabmodel.document; |
+ |
+import android.app.Activity; |
+import android.os.Handler; |
+import android.os.SystemClock; |
+ |
+import org.chromium.base.ThreadUtils; |
+import org.chromium.chrome.browser.Tab; |
+import org.chromium.chrome.browser.document.ChromeLauncherActivity; |
+import org.chromium.chrome.browser.document.DocumentActivity; |
+import org.chromium.chrome.browser.document.IncognitoDocumentActivity; |
+import org.chromium.chrome.browser.tabmodel.document.DocumentTabModel.Entry; |
+ |
+import java.util.ArrayList; |
+ |
+/** |
+ * Fires an Intent to launch a new DocumentActivity. Waits for the ActivityManager to acknowledge |
+ * that our task exists before firing the next Intent. |
+ */ |
+public class AsyncDocumentLauncher { |
+ /** |
+ * Milliseconds to wait for Android to acknowledge that our Activity's task exists. |
+ * This value is empirically defined because Android doesn't let us know when it finishes |
+ * animating Activities, nor does it let us Observe the ActivityManager for when our task |
+ * exists (crbug.com/498920). |
+ */ |
+ private static final int MAX_WAIT_MS = 3000; |
+ |
+ /** Milliseconds to wait between polls of the ActivityManager. */ |
+ private static final int POLLING_DELAY_MS = 100; |
+ |
+ private class LaunchRunnable implements Runnable { |
+ private final int mParentId; |
+ private final AsyncTabCreationParams mAsyncParams; |
+ private int mLaunchedId; |
+ private long mLaunchTimestamp; |
+ |
+ public LaunchRunnable(int parentId, AsyncTabCreationParams asyncParams) { |
+ mParentId = parentId; |
+ mAsyncParams = asyncParams; |
+ mLaunchedId = Tab.INVALID_TAB_ID; |
+ } |
+ |
+ /** Starts an Activity to with the stored parameters. */ |
+ public void launch() { |
+ final Activity parentActivity = ActivityDelegate.getActivityForTabId(mParentId); |
+ mLaunchedId = ChromeLauncherActivity.launchDocumentInstance( |
+ parentActivity, mIsIncognito, mAsyncParams); |
+ mLaunchTimestamp = SystemClock.elapsedRealtime(); |
+ run(); |
+ } |
+ |
+ @Override |
+ public void run() { |
+ // Check if the Activity was already launched. |
+ for (Entry task : mActivityDelegate.getTasksFromRecents(mIsIncognito)) { |
+ if (task.tabId == mLaunchedId) { |
+ finishLaunch(); |
+ return; |
+ } |
+ } |
+ |
+ if (SystemClock.elapsedRealtime() - mLaunchTimestamp > MAX_WAIT_MS) { |
+ // Check if the launch is taking excessively long. This will likely make the |
+ // previous tab disappear, but it's better than making the user wait. |
+ finishLaunch(); |
+ } else { |
+ // Wait a bit longer. |
+ mHandler.postDelayed(this, POLLING_DELAY_MS); |
+ } |
+ } |
+ |
+ /** Start up the next tab. */ |
+ private void finishLaunch() { |
+ mCurrentRunnable = null; |
+ if (mQueue.size() != 0) { |
+ mCurrentRunnable = mQueue.remove(0); |
+ mCurrentRunnable.launch(); |
+ } |
+ } |
+ } |
+ |
+ private final boolean mIsIncognito; |
+ private final Handler mHandler; |
+ private final ActivityDelegate mActivityDelegate; |
+ private final ArrayList<LaunchRunnable> mQueue; |
+ private LaunchRunnable mCurrentRunnable; |
+ |
+ public AsyncDocumentLauncher(boolean incognito) { |
+ mIsIncognito = incognito; |
+ mHandler = new Handler(); |
+ mActivityDelegate = new ActivityDelegate( |
+ DocumentActivity.class, IncognitoDocumentActivity.class); |
+ mQueue = new ArrayList<LaunchRunnable>(); |
+ } |
+ |
+ /** Enqueues a tab to be launched asynchronously. */ |
+ public void enqueueLaunch(int parentId, AsyncTabCreationParams asyncParams) { |
+ ThreadUtils.assertOnUiThread(); |
+ LaunchRunnable runnable = new LaunchRunnable(parentId, asyncParams); |
+ if (mCurrentRunnable == null) { |
+ mCurrentRunnable = runnable; |
+ mCurrentRunnable.launch(); |
+ } else { |
+ mQueue.add(runnable); |
+ } |
+ } |
+} |