// 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.webapps; import android.content.Intent; import android.util.Pair; import android.view.View; import android.view.ViewGroup; import org.chromium.base.annotations.SuppressFBWarnings; import org.chromium.chrome.R; import org.chromium.chrome.browser.ChromeActivity; import org.chromium.chrome.browser.TabState; import org.chromium.chrome.browser.compositor.layouts.LayoutManagerDocument; import org.chromium.chrome.browser.tab.EmptyTabObserver; import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.tab.TabDelegateFactory; import org.chromium.chrome.browser.tab.TabUma.TabCreationState; import org.chromium.chrome.browser.tabmodel.SingleTabModelSelector; import org.chromium.chrome.browser.tabmodel.TabModel.TabLaunchType; import org.chromium.chrome.browser.tabmodel.TabModel.TabSelectionType; import org.chromium.chrome.browser.tabmodel.TabModelSelector; import org.chromium.chrome.browser.tabmodel.document.TabDelegate; import org.chromium.chrome.browser.widget.ControlContainer; import org.chromium.content.browser.ContentViewCore; import org.chromium.content_public.browser.LoadUrlParams; import org.chromium.content_public.browser.WebContents; import org.chromium.content_public.browser.WebContentsObserver; import java.io.File; /** * Base class for task-focused activities that need to display web content in a nearly UI-less * Chrome (InfoBars still appear). * * This is vaguely analogous to a WebView, but in Chrome. Example applications that might use this * Activity would be webapps and streaming media activities - anything where user interaction with * the regular browser's UI is either unnecessary or undesirable. * Subclasses can override {@link #createUI()} if they need something more exotic. */ @SuppressFBWarnings("URF_UNREAD_FIELD") public abstract class FullScreenActivity extends ChromeActivity { protected static final String BUNDLE_TAB_ID = "tabId"; protected static final String BUNDLE_TAB_URL = "tabUrl"; private static final String TAG = "FullScreenActivity"; private WebContents mWebContents; @SuppressWarnings("unused") // Reference needed to prevent GC. private WebContentsObserver mWebContentsObserver; @Override protected void onNewIntent(Intent intent) { super.onNewIntent(intent); setIntent(intent); } @Override protected TabModelSelector createTabModelSelector() { return new SingleTabModelSelector(this, false, false) { @Override public Tab openNewTab(LoadUrlParams loadUrlParams, TabLaunchType type, Tab parent, boolean incognito) { getTabCreator(incognito).createNewTab(loadUrlParams, type, parent); return null; } }; } @Override protected Pair<TabDelegate, TabDelegate> createTabCreators() { return Pair.create(createTabDelegate(false), createTabDelegate(true)); } /** Creates TabDelegates for opening new Tabs. */ protected TabDelegate createTabDelegate(boolean incognito) { return new TabDelegate(incognito); } @Override public void initializeState() { super.initializeState(); Tab tab = createTab(); getTabModelSelector().setTab(tab); handleTabContentChanged(); tab.show(TabSelectionType.FROM_NEW); } @Override public void finishNativeInitialization() { ControlContainer controlContainer = (ControlContainer) findViewById(R.id.control_container); initializeCompositorContent(new LayoutManagerDocument(getCompositorViewHolder()), (View) controlContainer, (ViewGroup) findViewById(android.R.id.content), controlContainer); if (getFullscreenManager() != null) getFullscreenManager().setTab(getActivityTab()); super.finishNativeInitialization(); } @Override protected void initializeToolbar() { } @Override public SingleTabModelSelector getTabModelSelector() { return (SingleTabModelSelector) super.getTabModelSelector(); } /** * Creates the {@link Tab} used by the FullScreenActivity. * If the {@code savedInstanceState} exists, then the user did not intentionally close the app * by swiping it away in the recent tasks list. In that case, we try to restore the tab from * disk. */ protected Tab createTab() { Tab tab = null; boolean unfreeze = false; int tabId = Tab.INVALID_TAB_ID; String tabUrl = null; if (getSavedInstanceState() != null) { tabId = getSavedInstanceState().getInt(BUNDLE_TAB_ID, Tab.INVALID_TAB_ID); tabUrl = getSavedInstanceState().getString(BUNDLE_TAB_URL); } if (tabId != Tab.INVALID_TAB_ID && tabUrl != null && getActivityDirectory() != null) { // Restore the tab. TabState tabState = TabState.restoreTabState(getActivityDirectory(), tabId); tab = new Tab(tabId, Tab.INVALID_TAB_ID, false, this, getWindowAndroid(), TabLaunchType.FROM_RESTORE, TabCreationState.FROZEN_ON_RESTORE, tabState); unfreeze = true; } if (tab == null) { tab = new Tab(Tab.INVALID_TAB_ID, Tab.INVALID_TAB_ID, false, this, getWindowAndroid(), TabLaunchType.FROM_CHROME_UI, null, null); } tab.initialize(null, getTabContentManager(), createTabDelegateFactory(), false, unfreeze); tab.addObserver(new EmptyTabObserver() { @Override public void onContentChanged(Tab tab) { assert tab == getActivityTab(); handleTabContentChanged(); } }); return tab; } private void handleTabContentChanged() { final Tab tab = getActivityTab(); assert tab != null; WebContents webContents = tab.getWebContents(); if (mWebContents == webContents) return; // Clean up any old references to the previous WebContents. if (mWebContentsObserver != null) { mWebContentsObserver.destroy(); mWebContentsObserver = null; } mWebContents = webContents; if (mWebContents == null) return; ContentViewCore.fromWebContents(webContents).setFullscreenRequiredForOrientationLock(false); mWebContentsObserver = new WebContentsObserver(webContents) { @Override public void didFinishNavigation(String url, boolean isInMainFrame, boolean isErrorPage, boolean hasCommitted, boolean isSameDocument, boolean isFragmentNavigation, Integer pageTransition, int errorCode, String errorDescription, int httpStatusCode) { if (hasCommitted && isInMainFrame) { // Notify the renderer to permanently hide the top controls since they do // not apply to fullscreen content views. tab.updateBrowserControlsState(tab.getBrowserControlsStateConstraints(), true); } } }; } /** * @return {@link TabDelegateFactory} to be used while creating the associated {@link Tab}. */ protected TabDelegateFactory createTabDelegateFactory() { return new FullScreenDelegateFactory(); } /** * @return {@link File} pointing at a directory specific for this class. */ protected File getActivityDirectory() { return null; } @Override protected boolean handleBackPressed() { Tab tab = getActivityTab(); if (tab == null) return false; if (exitFullscreenIfShowing()) return true; if (tab.canGoBack()) { tab.goBack(); return true; } return false; } @Override public void onCheckForUpdate(boolean updateAvailable) { } }