Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(420)

Side by Side Diff: chrome/android/java_staging/src/org/chromium/chrome/browser/ChromeTabbedActivity.java

Issue 1141283003: Upstream oodles of Chrome for Android code into Chromium. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: final patch? Created 5 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(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;
6
7 import android.app.ActivityManager;
8 import android.app.SearchManager;
9 import android.content.Context;
10 import android.content.Intent;
11 import android.content.res.Configuration;
12 import android.graphics.Rect;
13 import android.os.Build;
14 import android.os.Bundle;
15 import android.os.SystemClock;
16 import android.text.TextUtils;
17 import android.util.Log;
18 import android.view.KeyEvent;
19 import android.view.View;
20 import android.view.View.OnClickListener;
21 import android.view.ViewGroup;
22 import android.view.Window;
23 import android.view.WindowManager;
24 import android.widget.FrameLayout;
25 import android.widget.Toast;
26
27 import com.google.android.apps.chrome.R;
28
29 import org.chromium.base.CommandLine;
30 import org.chromium.base.MemoryPressureListener;
31 import org.chromium.base.TraceEvent;
32 import org.chromium.base.VisibleForTesting;
33 import org.chromium.base.library_loader.LibraryLoader;
34 import org.chromium.base.metrics.RecordHistogram;
35 import org.chromium.base.metrics.RecordUserAction;
36 import org.chromium.chrome.browser.ContextualMenuBar.ActionBarDelegate;
37 import org.chromium.chrome.browser.IntentHandler.IntentHandlerDelegate;
38 import org.chromium.chrome.browser.IntentHandler.TabOpenType;
39 import org.chromium.chrome.browser.appmenu.AppMenuHandler;
40 import org.chromium.chrome.browser.appmenu.AppMenuObserver;
41 import org.chromium.chrome.browser.appmenu.ChromeAppMenuPropertiesDelegate;
42 import org.chromium.chrome.browser.compositor.CompositorViewHolder;
43 import org.chromium.chrome.browser.compositor.layouts.Layout;
44 import org.chromium.chrome.browser.compositor.layouts.LayoutManagerChrome;
45 import org.chromium.chrome.browser.compositor.layouts.LayoutManagerChrome.Overvi ewLayoutFactoryDelegate;
46 import org.chromium.chrome.browser.compositor.layouts.LayoutManagerChromePhone;
47 import org.chromium.chrome.browser.compositor.layouts.LayoutManagerChromeTablet;
48 import org.chromium.chrome.browser.compositor.layouts.LayoutRenderHost;
49 import org.chromium.chrome.browser.compositor.layouts.LayoutUpdateHost;
50 import org.chromium.chrome.browser.compositor.layouts.OverviewModeBehavior.Overv iewModeObserver;
51 import org.chromium.chrome.browser.compositor.layouts.eventfilter.EventFilter;
52 import org.chromium.chrome.browser.compositor.layouts.phone.StackLayout;
53 import org.chromium.chrome.browser.cookies.CookiesFetcher;
54 import org.chromium.chrome.browser.device.DeviceClassManager;
55 import org.chromium.chrome.browser.document.DocumentUma;
56 import org.chromium.chrome.browser.enhancedbookmarks.EnhancedBookmarkUtils;
57 import org.chromium.chrome.browser.firstrun.FirstRunActivity;
58 import org.chromium.chrome.browser.firstrun.FirstRunFlowSequencer;
59 import org.chromium.chrome.browser.firstrun.FirstRunSignInProcessor;
60 import org.chromium.chrome.browser.firstrun.FirstRunStatus;
61 import org.chromium.chrome.browser.metrics.LaunchMetrics;
62 import org.chromium.chrome.browser.metrics.UmaUtils;
63 import org.chromium.chrome.browser.ntp.NativePageAssassin;
64 import org.chromium.chrome.browser.omaha.OmahaClient;
65 import org.chromium.chrome.browser.omnibox.AutocompleteController;
66 import org.chromium.chrome.browser.partnercustomizations.HomepageManager;
67 import org.chromium.chrome.browser.partnercustomizations.PartnerBrowserCustomiza tions;
68 import org.chromium.chrome.browser.preferences.ChromePreferenceManager;
69 import org.chromium.chrome.browser.preferences.ConnectionChangeReceiver;
70 import org.chromium.chrome.browser.preferences.PrefServiceBridge;
71 import org.chromium.chrome.browser.preferences.bandwidth.BandwidthReductionPrefe rences;
72 import org.chromium.chrome.browser.preferences.bandwidth.DataReductionPromoScree n;
73 import org.chromium.chrome.browser.signin.SigninPromoScreen;
74 import org.chromium.chrome.browser.snackbar.undo.UndoBarPopupController;
75 import org.chromium.chrome.browser.sync.SyncController;
76 import org.chromium.chrome.browser.tab.ChromeTab;
77 import org.chromium.chrome.browser.tabmodel.EmptyTabModelObserver;
78 import org.chromium.chrome.browser.tabmodel.TabModel;
79 import org.chromium.chrome.browser.tabmodel.TabModel.TabLaunchType;
80 import org.chromium.chrome.browser.tabmodel.TabModelObserver;
81 import org.chromium.chrome.browser.tabmodel.TabModelSelectorImpl;
82 import org.chromium.chrome.browser.tabmodel.TabModelSelectorTabObserver;
83 import org.chromium.chrome.browser.tabmodel.TabModelUtils;
84 import org.chromium.chrome.browser.tabmodel.TabWindowManager;
85 import org.chromium.chrome.browser.toolbar.ToolbarControlContainer;
86 import org.chromium.chrome.browser.toolbar.ToolbarHelper;
87 import org.chromium.chrome.browser.util.FeatureUtilities;
88 import org.chromium.chrome.browser.widget.emptybackground.EmptyBackgroundViewWra pper;
89 import org.chromium.chrome.browser.widget.findinpage.FindToolbarManager;
90 import org.chromium.content.browser.ContentVideoView;
91 import org.chromium.content.browser.ContentViewCore;
92 import org.chromium.content.browser.crypto.CipherFactory;
93 import org.chromium.content.common.ContentSwitches;
94 import org.chromium.content_public.browser.LoadUrlParams;
95 import org.chromium.ui.base.DeviceFormFactor;
96 import org.chromium.ui.base.PageTransition;
97
98 /**
99 * This is the main activity for ChromeMobile when not running in document mode. All the tabs
100 * are accessible via a chrome specific tab switching UI.
101 */
102 public class ChromeTabbedActivity extends CompositorChromeActivity implements Ac tionBarDelegate,
103 OverviewModeObserver {
104
105 private static final int FIRST_RUN_EXPERIENCE_RESULT = 101;
106
107 private static final String TAG = "ChromeTabbedActivity";
108
109 private static final String HELP_URL_PREFIX = "https://support.google.com/ch rome/";
110
111 private static final String FRE_RUNNING = "First run is running";
112
113 private static final String WINDOW_INDEX = "window_index";
114
115 // How long to delay closing the current tab when our app is minimized. Hav e to delay this
116 // so that we don't show the contents of the next tab while minimizing.
117 private static final long CLOSE_TAB_ON_MINIMIZE_DELAY_MS = 500;
118
119 // Maximum delay for initial tab creation. This is for homepage and NTP, not previous tabs
120 // restore. This is needed because we do not know when reading PartnerBrowse rCustomizations
121 // provider will be finished.
122 private static final int INITIAL_TAB_CREATION_TIMEOUT_MS = 500;
123
124 /**
125 * Sending an intent with this extra sets the app into single process mode.
126 * This is only used for testing, when certain tests want to force this beha viour.
127 */
128 public static final String INTENT_EXTRA_TEST_RENDER_PROCESS_LIMIT = "render_ process_limit";
129
130 /**
131 * Sending an intent with this extra disable uploading of minidumps.
132 * This is only used for testing, when certain tests want to force this beha viour.
133 */
134 public static final String INTENT_EXTRA_DISABLE_CRASH_DUMP_UPLOADING =
135 "disable_crash_dump_uploading";
136
137 /**
138 * Sending an intent with this action to Chrome will cause it to close all t abs
139 * (iff the --enable-test-intents command line flag is set). If a URL is sup plied in the
140 * intent data, this will be loaded and unaffected by the close all action.
141 */
142 private static final String ACTION_CLOSE_TABS =
143 "com.google.android.apps.chrome.ACTION_CLOSE_TABS";
144
145 private ToolbarHelper mToolbarHelper;
146
147 private FindToolbarManager mFindToolbarManager;
148
149 private UndoBarPopupController mUndoBarPopupController;
150
151 private LayoutManagerChrome mLayoutManager;
152
153 private ChromeAppMenuPropertiesDelegate mChromeAppMenuPropertiesDelegate;
154 private AppMenuHandler mAppMenuHandler;
155
156 private View mMenuAnchor;
157
158 private ViewGroup mContentContainer;
159
160 private ToolbarControlContainer mControlContainer;
161
162 private TabModelSelectorImpl mTabModelSelectorImpl;
163 private TabModelSelectorTabObserver mTabModelSelectorTabObserver;
164 private TabModelObserver mTabModelObserver;
165
166 private ConnectionChangeReceiver mConnectionChangeReceiver;
167
168 private boolean mUIInitialized = false;
169
170 private boolean mIsOnFirstRun = false;
171
172 /**
173 * Keeps track of whether or not a specific tab was created based on the sta rtup intent.
174 */
175 private boolean mCreatedTabOnStartup = false;
176
177 // Whether or not chrome was launched with an intent to open a tab.
178 private boolean mIntentWithEffect = false;
179
180 // Time at which an intent was received and handled.
181 private long mIntentHandlingTimeMs = 0;
182
183 @Override
184 public void initializeCompositor() {
185 try {
186 TraceEvent.begin("ChromeTabbedActivity.initializeCompositor");
187 super.initializeCompositor();
188
189 mTabModelSelectorImpl.onNativeLibraryReady(getTabContentManager());
190
191 mTabModelObserver = new EmptyTabModelObserver() {
192 @Override
193 public void didCloseTab(Tab tab) {
194 closeIfNoTabsAndHomepageEnabled();
195 }
196
197 @Override
198 public void tabPendingClosure(Tab tab) {
199 closeIfNoTabsAndHomepageEnabled();
200 }
201
202 private void closeIfNoTabsAndHomepageEnabled() {
203 // If the last tab is closed, and homepage is enabled, then exit Chrome.
204 if (HomepageManager.isHomepageEnabled(getApplicationContext( ))
205 && getTabModelSelector().getTotalTabCount() == 0) {
206 finish();
207 }
208 }
209
210 @Override
211 public void didAddTab(Tab tab, TabLaunchType type) {
212 if (type == TabLaunchType.FROM_LONGPRESS_BACKGROUND
213 && !DeviceClassManager.enableAnimations(getApplicati onContext())) {
214 Toast.makeText(getBaseContext(),
215 R.string.open_in_new_tab_toast,
216 Toast.LENGTH_SHORT).show();
217 }
218 }
219 };
220 for (TabModel model : mTabModelSelectorImpl.getModels()) {
221 model.addObserver(mTabModelObserver);
222 }
223
224 Bundle state = getSavedInstanceState();
225 if (state != null && state.containsKey(FRE_RUNNING)) {
226 mIsOnFirstRun = state.getBoolean(FRE_RUNNING);
227 }
228 } finally {
229 TraceEvent.end("ChromeTabbedActivity.initializeCompositor");
230 }
231 }
232
233 private void refreshSignIn() {
234 if (mIsOnFirstRun) return;
235 android.util.Log.i(TAG, "in refreshSignIn before starting the sign-in pr ocessor");
236 FirstRunSignInProcessor.start(this);
237 }
238
239 @Override
240 public void onNewIntent(Intent intent) {
241 mIntentHandlingTimeMs = SystemClock.uptimeMillis();
242 super.onNewIntent(intent);
243 }
244
245 @Override
246 public void finishNativeInitialization() {
247 try {
248 TraceEvent.begin("ChromeTabbedActivity.finishNativeInitialization");
249
250 launchFirstRunExperience();
251
252 ChromePreferenceManager preferenceManager = ChromePreferenceManager. getInstance(this);
253 // Promos can only be shown when we start with ACTION_MAIN intent an d
254 // after FRE is complete.
255 if (!mIntentWithEffect && FirstRunStatus.getFirstRunFlowComplete(thi s)) {
256 // Only show promos on the second oppurtunity. This is because w e show FRE on the
257 // first oppurtunity, and we don't want to show such content bac k to back.
258 if (preferenceManager.getPromosSkippedOnFirstStart()) {
259 // Data reduction promo should be temporarily suppressed if the sign in promo is
260 // shown to avoid nagging users too much.
261 if (!SigninPromoScreen.launchSigninPromoIfNeeded(this)) {
262 DataReductionPromoScreen.launchDataReductionPromo(this);
263 }
264 } else {
265 preferenceManager.setPromosSkippedOnFirstStart(true);
266 }
267 }
268
269 refreshSignIn();
270
271 initializeUI();
272
273 // The dataset has already been created, we need to initialize our s tate.
274 mTabModelSelectorImpl.notifyChanged();
275
276 getWindow().setFeatureInt(Window.FEATURE_INDETERMINATE_PROGRESS,
277 Window.PROGRESS_VISIBILITY_OFF);
278
279 super.finishNativeInitialization();
280
281 if (getActivityTab() != null) {
282 BandwidthReductionPreferences.launchDataReductionSSLInfoBar(
283 this, getActivityTab().getWebContents());
284 }
285 } finally {
286 TraceEvent.end("ChromeTabbedActivity.finishNativeInitialization");
287 }
288 }
289
290 @Override
291 public void onResumeWithNative() {
292 super.onResumeWithNative();
293 CookiesFetcher.restoreCookies(this);
294 }
295
296 @Override
297 public void onPauseWithNative() {
298 mTabModelSelectorImpl.commitAllTabClosures();
299 CookiesFetcher.persistCookies(this);
300 super.onPauseWithNative();
301 }
302
303 @Override
304 public void onStopWithNative() {
305 super.onStopWithNative();
306 mTabModelSelectorImpl.saveState();
307 try {
308 getConnectionChangeReceiver().unregisterReceiver(ChromeTabbedActivit y.this);
309 } catch (IllegalArgumentException e) {
310 // This may happen when onStop get called very early in UI test.
311 }
312
313 // Dismiss the popup menu if it is showing.
314 hideMenus();
315 }
316
317 @Override
318 public void onStartWithNative() {
319 super.onStartWithNative();
320 // If we don't have a current tab, show the overview mode.
321 if (getActivityTab() == null) mLayoutManager.showOverview(false);
322
323 getConnectionChangeReceiver().registerReceiver(ChromeTabbedActivity.this );
324
325 resetSavedInstanceState();
326
327 if (FeatureUtilities.isDocumentModeEligible(this)) {
328 DocumentUma.recordInDocumentMode(false);
329 }
330 }
331
332 @Override
333 public void onNewIntentWithNative(Intent intent) {
334 try {
335 TraceEvent.begin("ChromeTabbedActivity.onNewIntentWithNative");
336
337 super.onNewIntentWithNative(intent);
338 if (CommandLine.getInstance().hasSwitch(ContentSwitches.ENABLE_TEST_ INTENTS)) {
339 handleDebugIntent(intent);
340 }
341 } finally {
342 TraceEvent.end("ChromeTabbedActivity.onNewIntentWithNative");
343 }
344 }
345
346 private void handleDebugIntent(Intent intent) {
347 if (ACTION_CLOSE_TABS.equals(intent.getAction())) {
348 getTabModelSelector().closeAllTabs();
349 } else if (MemoryPressureListener.handleDebugIntent(ChromeTabbedActivity .this,
350 intent.getAction())) {
351 // Handled.
352 }
353 }
354
355 private static class StackLayoutFactory implements OverviewLayoutFactoryDele gate {
356 @Override
357 public Layout createOverviewLayout(Context context, LayoutUpdateHost upd ateHost,
358 LayoutRenderHost renderHost, EventFilter eventFilter) {
359 return new StackLayout(context, updateHost, renderHost, eventFilter) ;
360 }
361 }
362
363 private void initializeUI() {
364 try {
365 TraceEvent.begin("ChromeTabbedActivity.initializeUI");
366
367 CommandLine commandLine = CommandLine.getInstance();
368
369 commandLine.appendSwitch(ContentSwitches.ENABLE_INSTANT_EXTENDED_API );
370
371 CompositorViewHolder compositorViewHolder = getCompositorViewHolder( );
372 if (DeviceFormFactor.isTablet(this)) {
373 boolean enableTabSwitcher =
374 CommandLine.getInstance().hasSwitch(ChromeSwitches.ENABL E_TABLET_TAB_STACK);
375 mLayoutManager = new LayoutManagerChromeTablet(compositorViewHol der,
376 enableTabSwitcher ? new StackLayoutFactory() : null);
377 } else {
378 mLayoutManager = new LayoutManagerChromePhone(compositorViewHold er,
379 new StackLayoutFactory());
380 }
381
382 mLayoutManager.addOverviewModeObserver(this);
383
384 // TODO(yusufo): get rid of findViewById(R.id.url_bar).
385 initializeCompositorContent(mLayoutManager, findViewById(R.id.url_ba r),
386 mContentContainer, mControlContainer);
387
388 mTabModelSelectorImpl.setOverviewModeBehavior(mLayoutManager);
389
390 mUndoBarPopupController.initialize();
391
392 // Adjust the content container if we're not entering fullscreen mod e.
393 if (getFullscreenManager() == null) {
394 float controlHeight = getResources().getDimension(R.dimen.contro l_container_height);
395 ((FrameLayout.LayoutParams) mContentContainer.getLayoutParams()) .topMargin =
396 (int) controlHeight;
397 }
398
399 // Bootstrap the first tab as it may have been created before initia lizing the
400 // fullscreen manager.
401 if (mTabModelSelectorImpl != null && mTabModelSelectorImpl.getCurren tTab() != null) {
402 mTabModelSelectorImpl.getCurrentTab().setFullscreenManager(getFu llscreenManager());
403 }
404
405 mAppMenuHandler.addObserver(new AppMenuObserver() {
406 @Override
407 public void onMenuVisibilityChanged(boolean isVisible) {
408 if (!isVisible) {
409 mChromeAppMenuPropertiesDelegate.onMenuDismissed();
410 }
411 }
412 });
413
414 mFindToolbarManager = new FindToolbarManager(this, getTabModelSelect or(),
415 mToolbarHelper.getContextualMenuBar().getCustomSelectionActi onModeCallback());
416 mControlContainer.setFindToolbarManager(mFindToolbarManager);
417 if (getContextualSearchManager() != null) {
418 getContextualSearchManager().setFindToolbarManager(mFindToolbarM anager);
419 }
420
421 OnClickListener tabSwitcherClickHandler = new OnClickListener() {
422 @Override
423 public void onClick(View v) {
424 toggleOverview();
425 }
426 };
427 OnClickListener newTabClickHandler = new OnClickListener() {
428 @Override
429 public void onClick(View v) {
430 // This assumes that the keyboard can not be seen at the sam e time as the
431 // newtab button on the toolbar.
432 getCurrentTabCreator().launchNTP();
433 }
434 };
435 OnClickListener bookmarkClickHandler = new OnClickListener() {
436 @Override
437 public void onClick(View v) {
438 addOrEditBookmark(getActivityTab());
439 }
440 };
441
442 mToolbarHelper.initializeControls(mFindToolbarManager, mLayoutManage r, mLayoutManager,
443 tabSwitcherClickHandler, newTabClickHandler, bookmarkClickHa ndler, null);
444
445 mMenuAnchor = findViewById(R.id.menu_anchor_stub);
446
447 removeWindowBackground();
448
449 if (mIsTablet) {
450 EmptyBackgroundViewWrapper bgViewWrapper = new EmptyBackgroundVi ewWrapper(
451 getTabModelSelector(), getTabCreator(false), ChromeTabbe dActivity.this,
452 mAppMenuHandler, mLayoutManager);
453 bgViewWrapper.initialize();
454 }
455
456 mLayoutManager.hideOverview(false);
457
458 mUIInitialized = true;
459 } finally {
460 TraceEvent.end("ChromeTabbedActivity.initializeUI");
461 }
462 }
463
464 @Override
465 public void initializeState() {
466 // This method goes through 3 steps:
467 // 1. Load the saved tab state (but don't start restoring the tabs yet).
468 // 2. Process the Intent that this activity received and if that should result in any
469 // new tabs, create them. This is done after step 1 so that the new tab gets
470 // created after previous tab state was restored.
471 // 3. If no tabs were created in any of the above steps, create an NTP, otherwise
472 // start asynchronous tab restore (loading the previously active tab synchronously
473 // if no new tabs created in step 2).
474
475 // Only look at the original intent if this is not a "restoration" and w e are allowed to
476 // process intents. Any subsequent intents are carried through onNewInte nt.
477 try {
478 TraceEvent.begin("ChromeTabbedActivity.initializeState");
479
480 super.initializeState();
481
482 Intent intent = getIntent();
483
484 if (!CipherFactory.getInstance().restoreFromBundle(getSavedInstanceS tate())) {
485 mTabModelSelectorImpl.clearEncryptedState();
486 }
487
488 boolean noRestoreState =
489 CommandLine.getInstance().hasSwitch(ChromeSwitches.NO_RESTOR E_STATE);
490 if (noRestoreState) {
491 // Clear the state files because they are inconsistent and usele ss from now on.
492 mTabModelSelectorImpl.clearState();
493 } else if (!mIsOnFirstRun) {
494 // State should be clear when we start first run and hence we do not need to load
495 // a previous state. This may change the current Model, watch ou t for initialization
496 // based on the model.
497 mTabModelSelectorImpl.loadState();
498 }
499
500 mIntentWithEffect = false;
501 if ((mIsOnFirstRun || getSavedInstanceState() == null) && intent != null
502 && !mIntentHandler.shouldIgnoreIntent(ChromeTabbedActivity.t his, intent)) {
503 mIntentWithEffect = mIntentHandler.onNewIntent(intent);
504 }
505
506 mCreatedTabOnStartup = getCurrentTabModel().getCount() > 0
507 || mTabModelSelectorImpl.getRestoredTabCount() > 0
508 || mIntentWithEffect;
509
510 // We always need to try to restore tabs. The set of tabs might be e mpty, but at least
511 // it will trigger the notification that tab restore is complete whi ch is needed by
512 // other parts of Chrome such as sync.
513 boolean activeTabBeingRestored = !mIntentWithEffect;
514 mTabModelSelectorImpl.restoreTabs(activeTabBeingRestored);
515
516 // Only create an initial tab if no tabs were restored and no intent was handled.
517 // Also, check whether the active tab was supposed to be restored an d that the total
518 // tab count is now non zero. If this is not the case, tab restore failed and we need
519 // to create a new tab as well.
520 if (!mCreatedTabOnStartup
521 || (activeTabBeingRestored && getTabModelSelector().getTotal TabCount() == 0)) {
522 // If homepage URI is not determined, due to PartnerBrowserCusto mizations provider
523 // async reading, then create a tab at the async reading finishe d. If it takes
524 // too long, just create NTP.
525 PartnerBrowserCustomizations.setOnInitializeAsyncFinished(
526 new Runnable() {
527 @Override
528 public void run() {
529 createInitialTab();
530 }
531 }, INITIAL_TAB_CREATION_TIMEOUT_MS);
532 }
533
534 RecordHistogram.recordBooleanHistogram(
535 "MobileStartup.ColdStartupIntent", mIntentWithEffect);
536 } finally {
537 TraceEvent.end("ChromeTabbedActivity.initializeState");
538 }
539 }
540
541 /**
542 * Create an initial tab for cold start without restored tabs.
543 */
544 private void createInitialTab() {
545 String url = HomepageManager.getHomepageUri(getApplicationContext());
546 if (TextUtils.isEmpty(url)) url = UrlConstants.NTP_URL;
547 getTabCreator(false).createNewTab(
548 new LoadUrlParams(url), TabLaunchType.FROM_MENU_OR_OVERVIEW, nul l);
549 }
550
551 @Override
552 public boolean onActivityResultWithNative(int requestCode, int resultCode, I ntent data) {
553 if (super.onActivityResultWithNative(requestCode, resultCode, data)) ret urn true;
554
555 if (requestCode == FIRST_RUN_EXPERIENCE_RESULT) {
556 mIsOnFirstRun = false;
557 if (resultCode == RESULT_OK) {
558 refreshSignIn();
559 } else {
560 if (data != null && data.getBooleanExtra(
561 FirstRunActivity.RESULT_CLOSE_APP, false)) {
562 getTabModelSelector().closeAllTabs(true);
563 finish();
564 } else {
565 launchFirstRunExperience();
566 }
567 }
568 return true;
569 }
570 return false;
571 }
572
573 @Override
574 public void onOrientationChange(int orientation) {
575 super.onOrientationChange(orientation);
576 mToolbarHelper.onOrientationChange();
577 }
578
579 @Override
580 public void onAccessibilityModeChanged(boolean enabled) {
581 super.onAccessibilityModeChanged(enabled);
582 if (mToolbarHelper != null) mToolbarHelper.onAccessibilityStatusChanged( enabled);
583
584 if (mLayoutManager != null) {
585 mLayoutManager.setEnableAnimations(
586 DeviceClassManager.enableAnimations(getApplicationContext()) );
587 }
588 if (mIsTablet) {
589 if (getCompositorViewHolder() != null) {
590 getCompositorViewHolder().onAccessibilityStatusChanged(enabled);
591 }
592 }
593 if (mLayoutManager != null && mLayoutManager.overviewVisible()) {
594 mLayoutManager.hideOverview(false);
595 }
596 }
597
598 /**
599 * Internal class which performs the intent handling operations delegated by IntentHandler.
600 */
601 private class InternalIntentDelegate implements IntentHandler.IntentHandlerD elegate {
602
603 /**
604 * Processes a url view intent.
605 *
606 * @param url The url from the intent.
607 */
608 @Override
609 public void processUrlViewIntent(String url, String headers, TabOpenType tabOpenType,
610 String externalAppId, int tabIdToBringToFront, Intent intent) {
611 TabModel tabModel = getCurrentTabModel();
612 switch (tabOpenType) {
613 case REUSE_URL_MATCHING_TAB_ELSE_NEW_TAB:
614 // Used by the bookmarks application.
615 if (tabModel.getCount() > 0 && mUIInitialized
616 && mLayoutManager.overviewVisible()) {
617 mLayoutManager.hideOverview(true);
618 }
619 mTabModelSelectorImpl.tryToRestoreTabStateForUrl(url);
620 int tabToBeClobberedIndex = TabModelUtils.getTabIndexByUrl(t abModel, url);
621 Tab tabToBeClobbered = tabModel.getTabAt(tabToBeClobberedInd ex);
622 if (tabToBeClobbered != null) {
623 TabModelUtils.setIndex(tabModel, tabToBeClobberedIndex);
624 tabToBeClobbered.reload();
625 RecordUserAction.record("MobileTabClobbered");
626 } else {
627 launchIntent(url, headers, externalAppId, true, intent);
628 }
629 RecordUserAction.record("MobileReceivedExternalIntent");
630 LaunchMetrics.recordHomeScreenLaunchIntoTab(url);
631 break;
632 case REUSE_APP_ID_MATCHING_TAB_ELSE_NEW_TAB:
633 launchIntent(url, headers, externalAppId, false, intent);
634 RecordUserAction.record("MobileReceivedExternalIntent");
635 break;
636 case BRING_TAB_TO_FRONT:
637 mTabModelSelectorImpl.tryToRestoreTabStateForId(tabIdToBring ToFront);
638
639 int tabIndex = TabModelUtils.getTabIndexById(tabModel, tabId ToBringToFront);
640 if (tabIndex == TabModel.INVALID_TAB_INDEX) {
641 TabModel otherModel =
642 getTabModelSelector().getModel(!tabModel.isIncog nito());
643 tabIndex = TabModelUtils.getTabIndexById(otherModel, tab IdToBringToFront);
644 if (tabIndex != TabModel.INVALID_TAB_INDEX) {
645 getTabModelSelector().selectModel(otherModel.isIncog nito());
646 TabModelUtils.setIndex(otherModel, tabIndex);
647 }
648 } else {
649 TabModelUtils.setIndex(tabModel, tabIndex);
650 }
651 RecordUserAction.record("MobileReceivedExternalIntent");
652 break;
653 case CLOBBER_CURRENT_TAB:
654 // The browser triggered the intent. This happens when click ing links which
655 // can be handled by other applications (e.g. www.youtube.co m links).
656 ChromeTab currentTab = ChromeTab.fromTab(getActivityTab());
657 if (currentTab != null) {
658 currentTab.getTabRedirectHandler().updateIntent(intent);
659 int transitionType = PageTransition.LINK | PageTransitio n.FROM_API;
660 LoadUrlParams loadUrlParams = new LoadUrlParams(url, tra nsitionType);
661 loadUrlParams.setIntentReceivedTimestamp(mIntentHandling TimeMs);
662 currentTab.loadUrl(loadUrlParams);
663 RecordUserAction.record("MobileTabClobbered");
664 } else {
665 launchIntent(url, headers, externalAppId, true, intent);
666 }
667 break;
668 case OPEN_NEW_TAB:
669 launchIntent(url, headers, externalAppId, true, intent);
670 RecordUserAction.record("MobileReceivedExternalIntent");
671 break;
672 case OPEN_NEW_INCOGNITO_TAB:
673 if (url == null || url.equals(UrlConstants.NTP_URL)) {
674 if (TextUtils.equals(externalAppId, getPackageName())) {
675 // Used by the Account management screen to open a n ew incognito tab.
676 // Account management screen collects its metrics se parately.
677 getTabCreator(true).launchUrl(
678 UrlConstants.NTP_URL, TabLaunchType.FROM_MEN U_OR_OVERVIEW);
679 } else {
680 getTabCreator(true).launchUrl(
681 UrlConstants.NTP_URL, TabLaunchType.FROM_EXT ERNAL_APP);
682 RecordUserAction.record("MobileReceivedExternalInten t");
683 }
684 } else {
685 if (TextUtils.equals(externalAppId, getPackageName())) {
686 getTabCreator(true).launchUrl(
687 url, TabLaunchType.FROM_LINK, intent, mInten tHandlingTimeMs);
688 } else {
689 getTabCreator(true).launchUrlFromExternalApp(url, he aders,
690 externalAppId, true, intent, mIntentHandling TimeMs);
691 RecordUserAction.record("MobileReceivedExternalInten t");
692 }
693 }
694 break;
695 default:
696 assert false : "Unknown TabOpenType: " + tabOpenType;
697 break;
698 }
699 mToolbarHelper.setUrlBarFocus(false);
700 }
701
702 @Override
703 public void processWebSearchIntent(String query) {
704 Intent searchIntent = new Intent(Intent.ACTION_WEB_SEARCH);
705 searchIntent.putExtra(SearchManager.QUERY, query);
706 startActivity(searchIntent);
707 }
708 }
709
710 @Override
711 public boolean isStartedUpCorrectly(Intent intent) {
712 if (FeatureUtilities.isDocumentMode(this)) {
713 Log.e(TAG, "Discarding Intent: Starting ChromeTabbedActivity in Docu ment mode");
714 return false;
715 }
716 return true;
717 }
718
719 @Override
720 public void preInflationStartup() {
721 super.preInflationStartup();
722
723 // Decide whether to record startup UMA histograms. This is done early in the main
724 // Activity.onCreate() to avoid recording navigation delays when they re quire user input to
725 // proceed. For example, FRE (First Run Experience) happens before the a ctivity is created,
726 // and triggers initialization of the native library. At the moment it s eems safe to assume
727 // that uninitialized native library is an indication of an application start that is
728 // followed by navigation immediately without user input.
729 if (!LibraryLoader.isInitialized()) {
730 UmaUtils.setRunningApplicationStart(true);
731 }
732
733 CommandLine commandLine = CommandLine.getInstance();
734 if (commandLine.hasSwitch(ContentSwitches.ENABLE_TEST_INTENTS)
735 && getIntent() != null
736 && getIntent().hasExtra(
737 ChromeTabbedActivity.INTENT_EXTRA_TEST_RENDER_PROCESS_LI MIT)) {
738 int value = getIntent().getIntExtra(
739 ChromeTabbedActivity.INTENT_EXTRA_TEST_RENDER_PROCESS_LIMIT, -1);
740 if (value != -1) {
741 String[] args = new String[1];
742 args[0] = "--" + ChromeSwitches.RENDER_PROCESS_LIMIT
743 + "=" + Integer.toString(value);
744 commandLine.appendSwitchesAndArguments(args);
745 }
746 }
747
748 commandLine.appendSwitch(ChromeSwitches.ENABLE_HIGH_END_UI_UNDO);
749
750 supportRequestWindowFeature(Window.FEATURE_ACTION_MODE_OVERLAY);
751
752 // We are starting from history with a URL after data has been cleared. On Samsung this
753 // can happen after user clears data and clicks on a recents item on pre -L devices.
754 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP
755 && getIntent().getData() != null
756 && (getIntent().getFlags() & Intent.FLAG_ACTIVITY_LAUNCHED_FROM_ HISTORY) != 0
757 && OmahaClient.isFreshInstallOrDataHasBeenCleared(getApplication Context())) {
758 getIntent().setData(null);
759 }
760 }
761
762 @Override
763 protected int getControlContainerLayoutId() {
764 return R.layout.control_container;
765 }
766
767 @Override
768 public void postInflationStartup() {
769 super.postInflationStartup();
770
771 // Critical path for startup. Create the minimum objects needed
772 // to allow a blank screen draw (without depending on any native code)
773 // and then yield ASAP.
774 createTabModelSelectorImpl(getSavedInstanceState());
775
776 if (isFinishing()) return;
777
778 // Don't show the keyboard until user clicks in.
779 getWindow().setSoftInputMode(
780 WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN
781 | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
782
783 mContentContainer = (ViewGroup) findViewById(android.R.id.content);
784 mControlContainer = (ToolbarControlContainer) findViewById(R.id.control_ container);
785
786 mUndoBarPopupController = new UndoBarPopupController(this, mTabModelSele ctorImpl,
787 getSnackbarManager());
788
789 mChromeAppMenuPropertiesDelegate = new ChromeAppMenuPropertiesDelegate(t his);
790 mAppMenuHandler = new AppMenuHandler(ChromeTabbedActivity.this,
791 mChromeAppMenuPropertiesDelegate, R.menu.main_menu);
792 mToolbarHelper = new ToolbarHelper(this, mControlContainer, mAppMenuHand ler,
793 mChromeAppMenuPropertiesDelegate, getCompositorViewHolder().getI nvalidator());
794 }
795
796 /**
797 * Launch the First Run flow to set up Chrome.
798 * There are two different pathways that can occur:
799 * 1) The First Run Experience activity is run, which walks the user through the ToS, signing
800 * in, and turning on UMA reporting. This happens in most cases.
801 * 2) We automatically try to sign-in the user and skip the FRE activity, th en ask the user to
802 * turn on UMA reporting some time later using an InfoBar. This happens if Chrome is opened
803 * with an Intent to view a URL, or if we're on a Nexus device where the use r has already
804 * been exposed to the ToS and Privacy Notice.
805 */
806 private void launchFirstRunExperience() {
807 SyncController.get(this).setDelaySync(false);
808 if (mIsOnFirstRun) {
809 mTabModelSelectorImpl.clearState();
810 return;
811 }
812
813 final boolean isIntentActionMain = getIntent() != null
814 && TextUtils.equals(getIntent().getAction(), Intent.ACTION_MAIN) ;
815 android.util.Log.i(TAG, "begin FirstRunFlowSequencer.checkIfFirstRunIsNe cessary");
816 final Intent freIntent = FirstRunFlowSequencer.checkIfFirstRunIsNecessar y(
817 this, getIntent(), isIntentActionMain);
818 android.util.Log.i(TAG, "end FirstRunFlowSequencer.checkIfFirstRunIsNece ssary");
819 if (freIntent == null) return;
820
821 mIsOnFirstRun = true;
822
823 // TODO(dtrainor): Investigate this further and revert once Android push es fix?
824 // Posting this due to Android bug where we apparently are stopping a
825 // non-resumed activity. That statement looks incorrect, but need to no t hit
826 // the runtime exception here.
827 mHandler.post(new Runnable() {
828 @Override
829 public void run() {
830 startActivityForResult(freIntent, FIRST_RUN_EXPERIENCE_RESULT);
831 }
832 });
833 }
834
835 @Override
836 protected void onDeferredStartup() {
837 try {
838 TraceEvent.begin("ChromeTabbedActivity.onDeferredStartup");
839 super.onDeferredStartup();
840
841 mToolbarHelper.onDeferredStartup();
842
843 ActivityManager am = (ActivityManager) getSystemService(Context.ACTI VITY_SERVICE);
844 RecordHistogram.recordSparseSlowlyHistogram(
845 "MemoryAndroid.DeviceMemoryClass", am.getMemoryClass());
846
847 AutocompleteController.nativePrefetchZeroSuggestResults();
848 } finally {
849 TraceEvent.end("ChromeTabbedActivity.onDeferredStartup");
850 }
851 }
852
853 private void createTabModelSelectorImpl(Bundle savedInstanceState) {
854 // We determine the model as soon as possible so every systems get initi alized coherently.
855 boolean startIncognito = savedInstanceState != null
856 && savedInstanceState.getBoolean("is_incognito_selected", false) ;
857 int index = savedInstanceState != null ? savedInstanceState.getInt(WINDO W_INDEX, 0) : 0;
858 mTabModelSelectorImpl = (TabModelSelectorImpl)
859 TabWindowManager.getInstance().requestSelector(this, getWindowAn droid(), index);
860 if (mTabModelSelectorImpl == null) {
861 Toast.makeText(this, getString(R.string.unsupported_number_of_window s),
862 Toast.LENGTH_LONG).show();
863 finish();
864 return;
865 }
866 mTabModelSelectorTabObserver = new TabModelSelectorTabObserver(mTabModel SelectorImpl) {
867
868 private boolean mIsFirstPageLoadStart = true;
869
870 @Override
871 public void onPageLoadStarted(Tab tab) {
872 // Discard startup navigation measurements when the user interfe red and started the
873 // 2nd navigation (in activity lifetime) in parallel.
874 if (!mIsFirstPageLoadStart) {
875 UmaUtils.setRunningApplicationStart(false);
876 } else {
877 mIsFirstPageLoadStart = false;
878 }
879 }
880 };
881
882 if (startIncognito) mTabModelSelectorImpl.selectModel(true);
883 setTabModelSelector(mTabModelSelectorImpl);
884 }
885
886 @Override
887 public void terminateIncognitoSession() {
888 getTabModelSelector().getModel(true).closeAllTabs();
889 }
890
891 @Override
892 public void onConfigurationChanged(Configuration newConfig) {
893 hideMenus();
894 super.onConfigurationChanged(newConfig);
895 }
896
897 @Override
898 public boolean onMenuOrKeyboardAction(final int id, boolean fromMenu) {
899 final Tab currentTab = getActivityTab();
900 if (id == R.id.new_tab_menu_id) {
901 Tab launchedTab = getTabCreator(false).launchUrl(
902 UrlConstants.NTP_URL,
903 fromMenu ? TabLaunchType.FROM_MENU_OR_OVERVIEW : TabLaunchTy pe.FROM_KEYBOARD);
904 RecordUserAction.record("MobileMenuNewTab");
905 RecordUserAction.record("MobileNewTabOpened");
906 if (mIsTablet && !fromMenu && !launchedTab.isHidden()) {
907 mToolbarHelper.setUrlBarFocus(true);
908 }
909 } else if (id == R.id.new_incognito_tab_menu_id) {
910 if (PrefServiceBridge.getInstance().isIncognitoModeEnabled()) {
911 // This action must be recorded before opening the incognito tab since UMA actions
912 // are dropped when an incognito tab is open.
913 RecordUserAction.record("MobileMenuNewIncognitoTab");
914 RecordUserAction.record("MobileNewTabOpened");
915 Tab launchedTab = getTabCreator(true).launchUrl(
916 UrlConstants.NTP_URL,
917 fromMenu ? TabLaunchType.FROM_MENU_OR_OVERVIEW
918 : TabLaunchType.FROM_KEYBOARD);
919 if (mIsTablet && !fromMenu && !launchedTab.isHidden()) {
920 mToolbarHelper.setUrlBarFocus(true);
921 }
922 }
923 } else if (id == R.id.all_bookmarks_menu_id) {
924 if (currentTab != null) {
925 getCompositorViewHolder().hideKeyboard(new Runnable() {
926 @Override
927 public void run() {
928 if (!EnhancedBookmarkUtils.showEnhancedBookmarkIfEnabled (
929 ChromeTabbedActivity.this)) {
930 currentTab.loadUrl(new LoadUrlParams(
931 UrlConstants.BOOKMARKS_URL,
932 PageTransition.AUTO_BOOKMARK));
933 }
934 }
935 });
936 RecordUserAction.record("MobileMenuAllBookmarks");
937 }
938 } else if (id == R.id.recent_tabs_menu_id) {
939 if (currentTab != null) {
940 currentTab.loadUrl(new LoadUrlParams(
941 UrlConstants.RECENT_TABS_URL,
942 PageTransition.AUTO_BOOKMARK));
943 RecordUserAction.record("MobileMenuOpenTabs");
944 }
945 } else if (id == R.id.close_all_tabs_menu_id) {
946 // Close both incognito and normal tabs
947 getTabModelSelector().closeAllTabs();
948 RecordUserAction.record("MobileMenuCloseAllTabs");
949 } else if (id == R.id.close_all_incognito_tabs_menu_id) {
950 // Close only incognito tabs
951 getTabModelSelector().getModel(true).closeAllTabs();
952 // TODO(nileshagrawal) Record unique action for this. See bug http:/ /b/5542946.
953 RecordUserAction.record("MobileMenuCloseAllTabs");
954 } else if (id == R.id.find_in_page_id) {
955 mFindToolbarManager.showToolbar();
956 if (fromMenu) {
957 RecordUserAction.record("MobileMenuFindInPage");
958 } else {
959 RecordUserAction.record("MobileShortcutFindInPage");
960 }
961 } else if (id == R.id.show_menu) {
962 showMenu();
963 } else if (id == R.id.focus_url_bar) {
964 boolean isUrlBarVisible = !mLayoutManager.overviewVisible()
965 && (!mIsTablet || getCurrentTabModel().getCount() != 0);
966 if (isUrlBarVisible) {
967 mToolbarHelper.setUrlBarFocus(true);
968 }
969 } else {
970 return super.onMenuOrKeyboardAction(id, fromMenu);
971 }
972 return true;
973 }
974
975 @Override
976 public boolean handleBackPressed() {
977 if (!mUIInitialized) return false;
978 final Tab currentTab = getActivityTab();
979
980 if (currentTab == null) {
981 if (mToolbarHelper.back()) {
982 RecordUserAction.record("SystemBackForNavigation");
983 RecordUserAction.record("MobileTabClobbered");
984 } else {
985 moveTaskToBack(true);
986 }
987 RecordUserAction.record("SystemBack");
988 return true;
989 }
990
991 // If we are in overview mode and not a tablet, then leave overview mode on back.
992 if (mLayoutManager.overviewVisible() && !mIsTablet) {
993 mLayoutManager.hideOverview(true);
994 // TODO(benm): Record any user metrics in this case?
995 return true;
996 }
997
998 if (isFullscreenVideoPlaying()) {
999 ContentVideoView.getContentVideoView().exitFullscreen(false);
1000 return true;
1001 }
1002
1003 if (getFullscreenManager().getPersistentFullscreenMode()) {
1004 getFullscreenManager().setPersistentFullscreenMode(false);
1005 return true;
1006 }
1007
1008 if (!mToolbarHelper.back()) {
1009 final TabLaunchType type = currentTab.getLaunchType();
1010 final String associatedApp = currentTab.getAppAssociatedWith();
1011 final int parentId = currentTab.getParentId();
1012 final boolean helpUrl = currentTab.getUrl().startsWith(HELP_URL_PREF IX);
1013
1014 // If the current tab url is HELP_URL, then the back button should c lose the tab to
1015 // get back to the previous state. The reason for startsWith check i s that the
1016 // actual redirected URL is a different system language based help u rl.
1017 if (type == TabLaunchType.FROM_MENU_OR_OVERVIEW && helpUrl) {
1018 getCurrentTabModel().closeTab(currentTab);
1019 return true;
1020 }
1021
1022 // [true]: Reached the bottom of the back stack on a tab the user di d not explicitly
1023 // create (i.e. it was created by an external app or opening a link in background, etc).
1024 // [false]: Reached the bottom of the back stack on a tab that the u ser explicitly
1025 // created (e.g. selecting "new tab" from menu).
1026 final boolean shouldCloseTab = type == TabLaunchType.FROM_LINK
1027 || type == TabLaunchType.FROM_EXTERNAL_APP
1028 || type == TabLaunchType.FROM_LONGPRESS_FOREGROUND
1029 || type == TabLaunchType.FROM_LONGPRESS_BACKGROUND
1030 || (type == TabLaunchType.FROM_RESTORE && parentId != Tab.IN VALID_TAB_ID);
1031
1032 // Minimize the app if either:
1033 // - we decided not to close the tab
1034 // - we decided to close the tab, but it was opened by an external a pp, so we will go
1035 // exit Chrome on top of closing the tab
1036 final boolean minimizeApp = !shouldCloseTab || (type == TabLaunchTyp e.FROM_EXTERNAL_APP
1037 && !TextUtils.equals(associatedApp, getPackageName()));
1038
1039 if (minimizeApp) {
1040 moveTaskToBack(true);
1041 if (shouldCloseTab) {
1042 // In the case of closing a tab upon minimalization, don't a llow the close
1043 // action to happen until after our app is minimized to make sure we don't get a
1044 // brief glimpse of the newly active tab before we exit Chro me.
1045 mHandler.postDelayed(new Runnable() {
1046 @Override
1047 public void run() {
1048 getCurrentTabModel().closeTab(currentTab, false, tru e, false);
1049 }
1050 }, CLOSE_TAB_ON_MINIMIZE_DELAY_MS);
1051 }
1052 } else if (shouldCloseTab) {
1053 getCurrentTabModel().closeTab(currentTab, true, false, false);
1054 }
1055 } else {
1056 RecordUserAction.record("SystemBackForNavigation");
1057 RecordUserAction.record("MobileTabClobbered");
1058 }
1059 RecordUserAction.record("SystemBack");
1060
1061 return true;
1062 }
1063
1064 /**
1065 * Launch a URL from an intent.
1066 *
1067 * @param url The url from the intent.
1068 * @param headers Optional headers to be sent when opening the URL.
1069 * @param externalAppId External app id.
1070 * @param forceNewTab Whether to force the URL to be launched in a new tab or to fall
1071 * back to the default behavior for making that determi nation.
1072 * @param intent The original intent.
1073 */
1074 private void launchIntent(String url, String headers, String externalAppId,
1075 boolean forceNewTab, Intent intent) {
1076 if (mUIInitialized) {
1077 mLayoutManager.hideOverview(false);
1078 mToolbarHelper.finishAnimations();
1079 }
1080 if (TextUtils.equals(externalAppId, getPackageName())) {
1081 // If the intent was launched by chrome, open the new tab in the cur rent model.
1082 // Using FROM_LINK ensures the tab is parented to the current tab, w hich allows
1083 // the back button to close these tabs and restore selection to the previous tab.
1084 getCurrentTabCreator().launchUrl(url, TabLaunchType.FROM_LINK, inten t,
1085 mIntentHandlingTimeMs);
1086 } else {
1087 getTabCreator(false).launchUrlFromExternalApp(url, headers, external AppId,
1088 forceNewTab, intent, mIntentHandlingTimeMs);
1089 }
1090 }
1091
1092 private void toggleOverview() {
1093 Tab currentTab = getActivityTab();
1094 ContentViewCore contentViewCore =
1095 currentTab != null ? currentTab.getContentViewCore() : null;
1096
1097 if (!mLayoutManager.overviewVisible()) {
1098 getCompositorViewHolder().hideKeyboard(new Runnable() {
1099 @Override
1100 public void run() {
1101 mLayoutManager.showOverview(true);
1102 }
1103 });
1104 if (contentViewCore != null) {
1105 contentViewCore.setAccessibilityState(false);
1106 }
1107 } else if (getCurrentTabModel().getCount() != 0) {
1108 // Don't hide overview if current tab stack is empty()
1109 mLayoutManager.hideOverview(true);
1110
1111 // hideOverview could change the current tab. Update the local vari ables.
1112 currentTab = getActivityTab();
1113 contentViewCore = currentTab != null ? currentTab.getContentViewCore () : null;
1114
1115 if (contentViewCore != null) {
1116 contentViewCore.setAccessibilityState(true);
1117 }
1118 }
1119 }
1120
1121 @Override
1122 public void onSaveInstanceState(Bundle outState) {
1123 super.onSaveInstanceState(outState);
1124 CipherFactory.getInstance().saveToBundle(outState);
1125 outState.putBoolean("is_incognito_selected", getCurrentTabModel().isInco gnito());
1126 outState.putBoolean(FRE_RUNNING, mIsOnFirstRun);
1127 outState.putInt(WINDOW_INDEX,
1128 TabWindowManager.getInstance().getIndexForWindow(this));
1129 }
1130
1131 @Override
1132 public void onDestroyInternal() {
1133 if (mLayoutManager != null) mLayoutManager.removeOverviewModeObserver(th is);
1134 if (mTabModelSelectorTabObserver != null) mTabModelSelectorTabObserver.d estroy();
1135 if (mTabModelObserver != null) {
1136 for (TabModel model : mTabModelSelectorImpl.getModels()) {
1137 model.removeObserver(mTabModelObserver);
1138 }
1139 }
1140 if (mToolbarHelper != null) mToolbarHelper.destroy();
1141 if (mUndoBarPopupController != null) mUndoBarPopupController.destroy();
1142 super.onDestroyInternal();
1143 }
1144
1145 @Override
1146 public void onTrimMemory(int level) {
1147 super.onTrimMemory(level);
1148 // The conditions are expressed using ranges to capture intermediate lev els possibly added
1149 // to the API in the future.
1150 if ((level >= TRIM_MEMORY_RUNNING_LOW && level < TRIM_MEMORY_UI_HIDDEN)
1151 || level >= TRIM_MEMORY_MODERATE) {
1152 NativePageAssassin.getInstance().freezeAllHiddenPages();
1153 }
1154 }
1155
1156 @Override
1157 public boolean dispatchKeyEvent(KeyEvent event) {
1158 Boolean result = KeyboardShortcuts.dispatchKeyEvent(event, this, mUIInit ialized);
1159 return result != null ? result : super.dispatchKeyEvent(event);
1160 }
1161
1162 @Override
1163 public boolean onKeyDown(int keyCode, KeyEvent event) {
1164 if (!mUIInitialized) return false;
1165 boolean isCurrentTabVisible = !mLayoutManager.overviewVisible()
1166 && (!mIsTablet || getCurrentTabModel().getCount() != 0);
1167 return KeyboardShortcuts.onKeyDown(event, this, isCurrentTabVisible, tru e)
1168 || super.onKeyDown(keyCode, event);
1169 }
1170
1171 private void hideMenus() {
1172 if (mAppMenuHandler != null) mAppMenuHandler.hideAppMenu();
1173 }
1174
1175 private ConnectionChangeReceiver getConnectionChangeReceiver() {
1176 if (mConnectionChangeReceiver == null) {
1177 mConnectionChangeReceiver = new ConnectionChangeReceiver();
1178 }
1179 return mConnectionChangeReceiver;
1180 }
1181
1182 /**
1183 * Sets the top margin of the control container.
1184 *
1185 * @param margin The new top margin of the control container.
1186 */
1187 @Override
1188 public void setControlTopMargin(int margin) {
1189 FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams)
1190 mControlContainer.getLayoutParams();
1191 lp.topMargin = margin;
1192 mControlContainer.setLayoutParams(lp);
1193 }
1194
1195 /**
1196 * @return The top margin of the control container.
1197 */
1198 @Override
1199 public int getControlTopMargin() {
1200 FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams)
1201 mControlContainer.getLayoutParams();
1202 return lp.topMargin;
1203 }
1204
1205 @Override
1206 public void setActionBarBackgroundVisibility(boolean visible) {
1207 int visibility = visible ? View.VISIBLE : View.GONE;
1208 findViewById(R.id.action_bar_black_background).setVisibility(visibility) ;
1209 }
1210
1211 @VisibleForTesting
1212 public View getTabsView() {
1213 return getCompositorViewHolder();
1214 }
1215
1216 @VisibleForTesting
1217 public LayoutManagerChrome getLayoutManager() {
1218 return (LayoutManagerChrome) getCompositorViewHolder().getLayoutManager( );
1219 }
1220
1221 @VisibleForTesting
1222 public Layout getOverviewListLayout() {
1223 return getLayoutManager().getOverviewListLayout();
1224 }
1225
1226 @Override
1227 public boolean isOverlayVisible() {
1228 return getCompositorViewHolder() != null && !getCompositorViewHolder().i sTabInteractive();
1229 }
1230
1231 @Override
1232 public boolean mayShowUpdateInfoBar() {
1233 return !isOverlayVisible();
1234 }
1235
1236 // App Menu related code --------------------------------------------------- --------------------
1237
1238 @Override
1239 @VisibleForTesting
1240 public AppMenuHandler getAppMenuHandler() {
1241 return mAppMenuHandler;
1242 }
1243
1244 @Override
1245 public boolean shouldShowAppMenu() {
1246 // The popup menu relies on the model created during the full UI initial ization, so do not
1247 // attempt to show the menu until the UI creation has finished.
1248 if (!mUIInitialized) return false;
1249
1250 // Do not show the menu if we are in find in page view.
1251 if (mFindToolbarManager != null && mFindToolbarManager.isShowing() && !m IsTablet) {
1252 return false;
1253 }
1254
1255 return super.shouldShowAppMenu();
1256 }
1257
1258 private boolean showMenu() {
1259 if (!mUIInitialized || isFullscreenVideoPlaying()) return false;
1260
1261 // The following will deduct the status bar height from the screen heigh t and this
1262 // is used as the height for the menu anchor. This fixes the bug where c licking
1263 // inside a search box on google.com causes the menu to appear on top as keyboard
1264 // reduces the view height.
1265 int displayHeight = getResources().getDisplayMetrics().heightPixels;
1266
1267 Rect rect = new Rect();
1268 this.getWindow().getDecorView().getWindowVisibleDisplayFrame(rect);
1269 int statusBarHeight = rect.top;
1270 mMenuAnchor.setY((displayHeight - statusBarHeight));
1271 mAppMenuHandler.showAppMenu(mMenuAnchor, true, false);
1272 return true;
1273 }
1274
1275 private boolean isFullscreenVideoPlaying() {
1276 View view = ContentVideoView.getContentVideoView();
1277 return view != null && view.getContext() == this;
1278 }
1279
1280 @Override
1281 public boolean isInOverviewMode() {
1282 return mLayoutManager.overviewVisible();
1283 }
1284
1285 @Override
1286 public boolean hasDoneFirstDraw() {
1287 return mToolbarHelper.hasDoneFirstDraw();
1288 }
1289
1290 @Override
1291 protected IntentHandlerDelegate createIntentHandlerDelegate() {
1292 return new InternalIntentDelegate();
1293 }
1294
1295 @Override
1296 public void onOverviewModeStartedShowing(boolean showToolbar) {
1297 if (mFindToolbarManager != null) mFindToolbarManager.hideToolbar();
1298 }
1299
1300 @Override
1301 public void onSceneChange(Layout layout) {
1302 super.onSceneChange(layout);
1303 if (!layout.shouldDisplayContentOverlay()) mTabModelSelectorImpl.onTabsV iewShown();
1304 }
1305
1306 @Override
1307 public void onOverviewModeFinishedShowing() { }
1308
1309 @Override
1310 public void onOverviewModeStartedHiding(boolean showToolbar, boolean delayAn imation) {}
1311
1312 @Override
1313 public void onOverviewModeFinishedHiding() {}
1314 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698