OLD | NEW |
(Empty) | |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 package org.chromium.chrome.browser.tabmodel; |
| 6 |
| 7 import android.content.Intent; |
| 8 import android.text.TextUtils; |
| 9 |
| 10 import org.chromium.base.SysUtils; |
| 11 import org.chromium.base.TraceEvent; |
| 12 import org.chromium.chrome.browser.ChromeActivity; |
| 13 import org.chromium.chrome.browser.Tab; |
| 14 import org.chromium.chrome.browser.TabState; |
| 15 import org.chromium.chrome.browser.UrlConstants; |
| 16 import org.chromium.chrome.browser.UrlUtilities; |
| 17 import org.chromium.chrome.browser.WarmupManager; |
| 18 import org.chromium.chrome.browser.compositor.layouts.content.TabContentManager; |
| 19 import org.chromium.chrome.browser.tab.ChromeTab; |
| 20 import org.chromium.chrome.browser.tabmodel.TabModel.TabLaunchType; |
| 21 import org.chromium.components.service_tab_launcher.ServiceTabLauncher; |
| 22 import org.chromium.content_public.browser.LoadUrlParams; |
| 23 import org.chromium.content_public.browser.WebContents; |
| 24 import org.chromium.ui.base.PageTransition; |
| 25 import org.chromium.ui.base.WindowAndroid; |
| 26 |
| 27 /** |
| 28 * This class creates various kinds of new tabs and adds them to the right {@lin
k TabModel}. |
| 29 */ |
| 30 public class ChromeTabCreator implements TabCreatorManager.TabCreator { |
| 31 |
| 32 private final ChromeActivity mActivity; |
| 33 private final WindowAndroid mNativeWindow; |
| 34 private final TabModelOrderController mOrderController; |
| 35 private final TabPersistentStore mTabSaver; |
| 36 private final boolean mIncognito; |
| 37 |
| 38 private TabModel mTabModel; |
| 39 private TabContentManager mTabContentManager; |
| 40 |
| 41 public ChromeTabCreator(ChromeActivity activity, WindowAndroid nativeWindow, |
| 42 TabModelOrderController orderController, TabPersistentStore tabSaver
, |
| 43 boolean incognito) { |
| 44 mActivity = activity; |
| 45 mNativeWindow = nativeWindow; |
| 46 mOrderController = orderController; |
| 47 mTabSaver = tabSaver; |
| 48 mIncognito = incognito; |
| 49 } |
| 50 |
| 51 /** |
| 52 * Creates a new tab and posts to UI. |
| 53 * @param loadUrlParams parameters of the url load. |
| 54 * @param type Information about how the tab was launched. |
| 55 * @param parent the parent tab, if present. |
| 56 * @return The new tab. |
| 57 */ |
| 58 public ChromeTab createNewTab(LoadUrlParams loadUrlParams, TabModel.TabLaunc
hType type, |
| 59 Tab parent) { |
| 60 return createNewTab(loadUrlParams, type, parent, null); |
| 61 } |
| 62 |
| 63 /** |
| 64 * Creates a new tab and posts to UI. |
| 65 * @param loadUrlParams parameters of the url load. |
| 66 * @param type Information about how the tab was launched. |
| 67 * @param parent the parent tab, if present. |
| 68 * @param intent the source of the url if it isn't null. |
| 69 * @return The new tab. |
| 70 */ |
| 71 public ChromeTab createNewTab(LoadUrlParams loadUrlParams, TabModel.TabLaunc
hType type, |
| 72 Tab parent, Intent intent) { |
| 73 // If parent is in the same tab model, place the new tab next to it. |
| 74 int index = mTabModel.indexOf(parent); |
| 75 if (index != TabModel.INVALID_TAB_INDEX) { |
| 76 return createNewTab(loadUrlParams, type, parent, index + 1, intent); |
| 77 } |
| 78 return createNewTab(loadUrlParams, type, parent, TabModel.INVALID_TAB_IN
DEX, intent); |
| 79 } |
| 80 |
| 81 /** |
| 82 * Creates a new tab and posts to UI. |
| 83 * @param loadUrlParams parameters of the url load. |
| 84 * @param type Information about how the tab was launched. |
| 85 * @param parent the parent tab, if present. |
| 86 * @param position the requested position (index in the tab model) |
| 87 * @return The new tab. |
| 88 */ |
| 89 public ChromeTab createNewTab(LoadUrlParams loadUrlParams, TabModel.TabLaunc
hType type, |
| 90 Tab parent, int position) { |
| 91 return createNewTab(loadUrlParams, type, parent, position, null); |
| 92 } |
| 93 |
| 94 /** |
| 95 * Creates a new tab and posts to UI. |
| 96 * @param loadUrlParams parameters of the url load. |
| 97 * @param type Information about how the tab was launched. |
| 98 * @param parent the parent tab, if present. |
| 99 * @param position the requested position (index in the tab model) |
| 100 * @param intent the source of the url if it isn't null. |
| 101 * @return The new tab. |
| 102 */ |
| 103 public ChromeTab createNewTab(LoadUrlParams loadUrlParams, TabModel.TabLaunc
hType type, |
| 104 Tab parent, int position, Intent intent) { |
| 105 try { |
| 106 TraceEvent.begin("ChromeTabCreator.createNewTab"); |
| 107 int parentId = parent != null ? parent.getId() : Tab.INVALID_TAB_ID; |
| 108 // Sanitize the url. |
| 109 loadUrlParams.setUrl(UrlUtilities.fixupUrl(loadUrlParams.getUrl())); |
| 110 loadUrlParams.setTransitionType(getTransitionType(type)); |
| 111 |
| 112 boolean openInForeground = mOrderController.willOpenInForeground(typ
e, mIncognito); |
| 113 ChromeTab tab; |
| 114 // On low memory devices the tabs opened in background are not loade
d automatically to |
| 115 // preserve resources (cpu, memory, strong renderer binding) for the
foreground tab. |
| 116 if (!openInForeground && SysUtils.isLowEndDevice()) { |
| 117 tab = ChromeTab.createTabForLazyLoad(mActivity, mIncognito, mNat
iveWindow, type, |
| 118 parentId, loadUrlParams); |
| 119 tab.initialize(null, mTabContentManager, !openInForeground); |
| 120 mTabSaver.addTabToSaveQueue(tab); |
| 121 tab.getTabRedirectHandler().updateIntent(intent); |
| 122 } else { |
| 123 tab = ChromeTab.createLiveTab(Tab.INVALID_TAB_ID, mActivity, mIn
cognito, |
| 124 mNativeWindow, type, parentId, !openInForeground); |
| 125 |
| 126 WebContents webContents = |
| 127 WarmupManager.getInstance().hasPrerenderedUrl(loadUrlPar
ams.getUrl()) |
| 128 ? WarmupManager.getInstance().takePrerenderedWebContents
() : null; |
| 129 tab.initialize(webContents, mTabContentManager, !openInForegroun
d); |
| 130 tab.getTabRedirectHandler().updateIntent(intent); |
| 131 tab.loadUrl(loadUrlParams); |
| 132 } |
| 133 |
| 134 if (intent != null && intent.hasExtra(ServiceTabLauncher.LAUNCH_REQU
EST_ID_EXTRA)) { |
| 135 ServiceTabLauncher.onWebContentsForRequestAvailable( |
| 136 intent.getIntExtra(ServiceTabLauncher.LAUNCH_REQUEST_ID_
EXTRA, 0), |
| 137 tab.getWebContents()); |
| 138 } |
| 139 |
| 140 mTabModel.addTab(tab, position, type); |
| 141 |
| 142 return tab; |
| 143 } finally { |
| 144 TraceEvent.end("ChromeTabCreator.createNewTab"); |
| 145 } |
| 146 } |
| 147 |
| 148 /** |
| 149 * Creates a tab around the native web contents pointer. |
| 150 * @param webContents The web contents to create a tab around. |
| 151 * @param parentId The id of the parent tab. |
| 152 * @param type The TabLaunchType describing how this tab was created. |
| 153 * @return The created tab. |
| 154 */ |
| 155 public ChromeTab createTabWithWebContents(WebContents webContents, int paren
tId, |
| 156 TabLaunchType type) { |
| 157 TabModel model = mTabModel; |
| 158 |
| 159 // The parent tab was already closed. Do not open child tabs. |
| 160 if (model.isClosurePending(parentId)) return null; |
| 161 |
| 162 int index = TabModelUtils.getTabIndexById(model, parentId); |
| 163 |
| 164 // If we have a valid parent index increment by one so we add this tab d
irectly after |
| 165 // the parent tab. |
| 166 if (index >= 0) index++; |
| 167 |
| 168 boolean selectTab = mOrderController.willOpenInForeground(type, mIncogni
to); |
| 169 ChromeTab tab = ChromeTab.createLiveTab(Tab.INVALID_TAB_ID, mActivity, m
Incognito, |
| 170 mNativeWindow, type, parentId, !selectTab); |
| 171 tab.initialize(webContents, mTabContentManager, !selectTab); |
| 172 model.addTab(tab, index, type); |
| 173 return tab; |
| 174 } |
| 175 |
| 176 @Override |
| 177 public Tab launchNTP() { |
| 178 try { |
| 179 TraceEvent.begin("ChromeTabCreator.launchNTP"); |
| 180 ChromeTab tab = launchUrl(UrlConstants.NTP_URL, |
| 181 TabModel.TabLaunchType.FROM_MENU_OR_OVERVIEW); |
| 182 return tab; |
| 183 } finally { |
| 184 TraceEvent.end("ChromeTabCreator.launchNTP"); |
| 185 } |
| 186 } |
| 187 |
| 188 /** |
| 189 * Creates a new tab and loads the specified URL in it. This is a convenienc
e method for |
| 190 * {@link #createNewTab} with the default {@link LoadUrlParams} and no paren
t tab. |
| 191 * |
| 192 * @param url the URL to open. |
| 193 * @param type the type of action that triggered that launch. Determines how
the tab is opened |
| 194 * (for example, in the foreground or background). |
| 195 * @return the created tab. |
| 196 */ |
| 197 public ChromeTab launchUrl(String url, TabModel.TabLaunchType type) { |
| 198 return launchUrl(url, type, null, 0); |
| 199 } |
| 200 |
| 201 /** |
| 202 * Creates a new tab and loads the specified URL in it. This is a convenienc
e method for |
| 203 * {@link #createNewTab} with the default {@link LoadUrlParams} and no paren
t tab. |
| 204 * |
| 205 * @param url the URL to open. |
| 206 * @param type the type of action that triggered that launch. Determines how
the tab is opened |
| 207 * (for example, in the foreground or background). |
| 208 * @param intent the source of url if it isn't null. |
| 209 * @param intentTimestamp the time the intent was received. |
| 210 * @return the created tab. |
| 211 */ |
| 212 public ChromeTab launchUrl(String url, TabModel.TabLaunchType type, Intent i
ntent, |
| 213 long intentTimestamp) { |
| 214 LoadUrlParams loadUrlParams = new LoadUrlParams(url); |
| 215 loadUrlParams.setIntentReceivedTimestamp(intentTimestamp); |
| 216 return createNewTab(loadUrlParams, type, null, intent); |
| 217 } |
| 218 |
| 219 /** |
| 220 * Opens the specified URL into a tab, potentially reusing a tab. Typically
if a user opens |
| 221 * several link from the same application, we reuse the same tab so as to no
t open too many |
| 222 * tabs. |
| 223 * @param url the URL to open |
| 224 * @param headers HTTP headers to send alongside the URL. |
| 225 * @param appId the ID of the application that triggered that URL navigation
. |
| 226 * @param forceNewTab whether the URL should be opened in a new tab. If fals
e, an existing tab |
| 227 * already opened by the same app will be reused. |
| 228 * @param intent the source of url if it isn't null. |
| 229 * @param intentTimestamp the time the intent was received. |
| 230 * @return the tab the URL was opened in, could be a new tab or a reused one
. |
| 231 */ |
| 232 public ChromeTab launchUrlFromExternalApp(String url, String headers, String
appId, |
| 233 boolean forceNewTab, Intent intent, long intentTimestamp) { |
| 234 assert !mIncognito; |
| 235 boolean isLaunchedFromChrome = TextUtils.equals(appId, mActivity.getPack
ageName()); |
| 236 if (forceNewTab && !isLaunchedFromChrome) { |
| 237 // We don't associate the tab with that app ID, as it is assumed tha
t if the |
| 238 // application wanted to open this tab as a new tab, it probably doe
s not want it |
| 239 // reused either. |
| 240 LoadUrlParams loadUrlParams = new LoadUrlParams(url); |
| 241 loadUrlParams.setIntentReceivedTimestamp(intentTimestamp); |
| 242 loadUrlParams.setVerbatimHeaders(headers); |
| 243 return createNewTab(loadUrlParams, TabLaunchType.FROM_EXTERNAL_APP,
null, intent); |
| 244 } |
| 245 |
| 246 if (appId == null) { |
| 247 // If we have no application ID, we use a made-up one so that these
tabs can be |
| 248 // reused. |
| 249 appId = TabModelImpl.UNKNOWN_APP_ID; |
| 250 } |
| 251 // Let's try to find an existing tab that was started by that app. |
| 252 for (int i = 0; i < mTabModel.getCount(); i++) { |
| 253 Tab tab = mTabModel.getTabAt(i); |
| 254 if (appId.equals(tab.getAppAssociatedWith())) { |
| 255 // We don't reuse the tab, we create a new one at the same index
instead. |
| 256 // Reusing a tab would require clearing the navigation history a
nd clearing the |
| 257 // contents (we would not want the previous content to show). |
| 258 LoadUrlParams loadUrlParams = new LoadUrlParams(url); |
| 259 loadUrlParams.setIntentReceivedTimestamp(intentTimestamp); |
| 260 ChromeTab newTab = createNewTab( |
| 261 loadUrlParams, TabLaunchType.FROM_EXTERNAL_APP, null, i,
intent); |
| 262 newTab.setAppAssociatedWith(appId); |
| 263 mTabModel.closeTab(tab, false, false, false); |
| 264 return newTab; |
| 265 } |
| 266 } |
| 267 |
| 268 // No tab for that app, we'll have to create a new one. |
| 269 ChromeTab tab = launchUrl(url, TabLaunchType.FROM_EXTERNAL_APP, intent,
intentTimestamp); |
| 270 tab.setAppAssociatedWith(appId); |
| 271 return tab; |
| 272 } |
| 273 |
| 274 @Override |
| 275 public void createFrozenTab(TabState state, int id, int index) { |
| 276 ChromeTab tab = ChromeTab.createFrozenTabFromState( |
| 277 id, mActivity, state.isIncognito(), mNativeWindow, state.parentI
d, state); |
| 278 boolean selectTab = mOrderController.willOpenInForeground(TabLaunchType.
FROM_RESTORE, |
| 279 state.isIncognito()); |
| 280 tab.initialize(null, mTabContentManager, !selectTab); |
| 281 assert state.isIncognito() == mIncognito; |
| 282 mTabModel.addTab(tab, index, TabLaunchType.FROM_RESTORE); |
| 283 } |
| 284 |
| 285 /** |
| 286 * @param type Type of the tab launch. |
| 287 * @return The page transition type constant. |
| 288 */ |
| 289 private static int getTransitionType(TabLaunchType type) { |
| 290 switch (type) { |
| 291 case FROM_LINK: |
| 292 case FROM_EXTERNAL_APP: |
| 293 return PageTransition.LINK | PageTransition.FROM_API; |
| 294 case FROM_MENU_OR_OVERVIEW: |
| 295 case FROM_LONGPRESS_FOREGROUND: |
| 296 case FROM_LONGPRESS_BACKGROUND: |
| 297 case FROM_KEYBOARD: |
| 298 return PageTransition.AUTO_TOPLEVEL; |
| 299 default: |
| 300 assert false; |
| 301 return PageTransition.LINK; |
| 302 } |
| 303 } |
| 304 |
| 305 /** |
| 306 * Sets the tab model and tab content manager to use. |
| 307 * @param model The new {@link TabModel} to use. |
| 308 * @param manager The new {@link TabContentManager} to use. |
| 309 */ |
| 310 public void setTabModel(TabModel model, TabContentManager manager) { |
| 311 mTabModel = model; |
| 312 mTabContentManager = manager; |
| 313 } |
| 314 |
| 315 } |
OLD | NEW |