// Copyright 2014 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.content.ComponentName;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.provider.Browser;
import org.chromium.base.ApiCompatibilityUtils;
import org.chromium.base.ContextUtils;
import org.chromium.chrome.browser.IntentHandler;
import org.chromium.chrome.browser.ServiceTabLauncher;
import org.chromium.chrome.browser.TabState;
import org.chromium.chrome.browser.document.ChromeLauncherActivity;
import org.chromium.chrome.browser.multiwindow.MultiWindowUtils;
import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.browser.tab.TabIdManager;
import org.chromium.chrome.browser.tabmodel.AsyncTabParamsManager;
import org.chromium.chrome.browser.tabmodel.TabCreatorManager.TabCreator;
import org.chromium.chrome.browser.tabmodel.TabModel.TabLaunchType;
import org.chromium.content_public.browser.LoadUrlParams;
import org.chromium.content_public.browser.WebContents;
import org.chromium.ui.base.PageTransition;
import java.util.Map;
/**
* Asynchronously creates Tabs by creating/starting up Activities.
*/
public class TabDelegate extends TabCreator {
private final boolean mIsIncognito;
/**
* Creates a TabDelegate.
* @param incognito Whether or not the TabDelegate handles the creation of incognito tabs.
*/
public TabDelegate(boolean incognito) {
mIsIncognito = incognito;
}
@Override
public boolean createsTabsAsynchronously() {
return true;
}
/**
* Creates a frozen Tab. This Tab is not meant to be used or unfrozen -- it is only used as a
* placeholder until the real Tab can be created.
* The index is ignored in DocumentMode because Android handles the ordering of Tabs.
*/
@Override
public Tab createFrozenTab(TabState state, int id, int index) {
return Tab.createFrozenTabFromState(id, null, state.isIncognito(), null,
Tab.INVALID_TAB_ID, state);
}
@Override
public boolean createTabWithWebContents(Tab parent, WebContents webContents, int parentId,
TabLaunchType type, String url) {
if (url == null) url = "";
AsyncTabCreationParams asyncParams =
new AsyncTabCreationParams(
new LoadUrlParams(url, PageTransition.AUTO_TOPLEVEL), webContents);
createNewTab(asyncParams, type, parentId);
return true;
}
/**
* Creates a tab in the "other" window in multi-window mode. This will only work if
* {@link MultiWindowUtils#isOpenInOtherWindowSupported} is true for the given activity.
*
* @param loadUrlParams Parameters specifying the URL to load and other navigation details.
* @param activity The current {@link Activity}
* @param parentId The ID of the parent tab, or {@link Tab#INVALID_TAB_ID}.
*/
public void createTabInOtherWindow(LoadUrlParams loadUrlParams, Activity activity,
int parentId) {
Intent intent = createNewTabIntent(
new AsyncTabCreationParams(loadUrlParams), parentId, false);
Class<? extends Activity> targetActivity =
MultiWindowUtils.getInstance().getOpenInOtherWindowActivity(activity);
if (targetActivity == null) return;
MultiWindowUtils.setOpenInOtherWindowIntentExtras(intent, activity, targetActivity);
IntentHandler.addTrustedIntentExtras(intent, activity);
MultiWindowUtils.onMultiInstanceModeStarted();
activity.startActivity(intent);
}
@Override
public Tab launchUrl(String url, TabLaunchType type) {
return createNewTab(new LoadUrlParams(url), type, null);
}
@Override
public Tab createNewTab(LoadUrlParams loadUrlParams, TabLaunchType type, Tab parent) {
AsyncTabCreationParams asyncParams = new AsyncTabCreationParams(loadUrlParams);
createNewTab(asyncParams, type, parent == null ? Tab.INVALID_TAB_ID : parent.getId());
return null;
}
/**
* Creates a Tab to host the given WebContents asynchronously.
* @param asyncParams Parameters to create the Tab with, including the URL.
* @param type Information about how the tab was launched.
* @param parentId ID of the parent tab, if it exists.
*/
public void createNewTab(
AsyncTabCreationParams asyncParams, TabLaunchType type, int parentId) {
assert asyncParams != null;
// Tabs should't be launched in affiliated mode when a webcontents exists.
assert !(type == TabLaunchType.FROM_LONGPRESS_BACKGROUND
&& asyncParams.getWebContents() != null);
Intent intent = createNewTabIntent(
asyncParams, parentId, type == TabLaunchType.FROM_CHROME_UI);
IntentHandler.startActivityForTrustedIntent(intent, ContextUtils.getApplicationContext());
}
private Intent createNewTabIntent(
AsyncTabCreationParams asyncParams, int parentId, boolean isChromeUI) {
int assignedTabId = TabIdManager.getInstance().generateValidId(Tab.INVALID_TAB_ID);
AsyncTabParamsManager.add(assignedTabId, asyncParams);
Intent intent = new Intent(
Intent.ACTION_VIEW, Uri.parse(asyncParams.getLoadUrlParams().getUrl()));
ComponentName componentName = asyncParams.getComponentName();
if (componentName == null) {
intent.setClass(ContextUtils.getApplicationContext(), ChromeLauncherActivity.class);
} else {
intent.setComponent(componentName);
}
Map<String, String> extraHeaders = asyncParams.getLoadUrlParams().getExtraHeaders();
if (extraHeaders != null && !extraHeaders.isEmpty()) {
Bundle bundle = new Bundle();
for (Map.Entry<String, String> header : extraHeaders.entrySet()) {
bundle.putString(header.getKey(), header.getValue());
}
intent.putExtra(Browser.EXTRA_HEADERS, bundle);
}
intent.putExtra(IntentHandler.EXTRA_TAB_ID, assignedTabId);
intent.putExtra(IntentHandler.EXTRA_OPEN_NEW_INCOGNITO_TAB, mIsIncognito);
intent.putExtra(IntentHandler.EXTRA_PARENT_TAB_ID, parentId);
if (isChromeUI) {
intent.putExtra(Browser.EXTRA_APPLICATION_ID,
ContextUtils.getApplicationContext().getPackageName());
intent.putExtra(Browser.EXTRA_CREATE_NEW_TAB, true);
}
Activity parentActivity = ActivityDelegate.getActivityForTabId(parentId);
if (parentActivity != null && parentActivity.getIntent() != null) {
intent.putExtra(IntentHandler.EXTRA_PARENT_INTENT, parentActivity.getIntent());
}
if (asyncParams.getRequestId() != null) {
intent.putExtra(ServiceTabLauncher.LAUNCH_REQUEST_ID_EXTRA,
asyncParams.getRequestId().intValue());
}
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
return intent;
}
/**
* Passes the supplied web app launch intent to the IntentHandler.
* @param intent Web app launch intent.
*/
public void createNewStandaloneFrame(Intent intent) {
assert intent != null;
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
| ApiCompatibilityUtils.getActivityNewDocumentFlag());
IntentHandler.startActivityForTrustedIntent(intent,
ContextUtils.getApplicationContext());
}
}