blob: ed7b84592e46830a95cde78cc8056ca56cdd08d3 [file] [log] [blame]
// Copyright 2017 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;
import android.content.ComponentName;
import android.content.Intent;
import android.os.Bundle;
import android.provider.Browser;
import android.util.SparseArray;
import android.view.ViewGroup;
import org.chromium.base.ActivityState;
import org.chromium.base.ApplicationStatus;
import org.chromium.base.Log;
import org.chromium.chrome.browser.compositor.layouts.LayoutManager;
import org.chromium.chrome.browser.fullscreen.ChromeFullscreenManager;
import org.chromium.chrome.browser.fullscreen.FullscreenOptions;
import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.browser.util.IntentUtils;
import org.chromium.content_public.browser.ScreenOrientationProvider;
import org.chromium.content_public.browser.WebContentsObserver;
/**
* An Activity used to display fullscreen WebContents.
*
* This Activity used to be called FullscreenWebContentsActivity and extended FullScreenActivity.
* When FullScreenActivity was renamed to SingleTabActivity, this was changed to FullscreenActivity.
*/
public class FullscreenActivity extends SingleTabActivity {
private static final String TAG = "FullscreenActivity";
private static final SparseArray<Tab> sTabsToSteal = new SparseArray<>();
private WebContentsObserver mWebContentsObserver;
@Override
protected Tab createTab() {
assert getIntent().hasExtra(IntentHandler.EXTRA_TAB_ID);
final Tab tab = getTabToSteal(IntentUtils.safeGetIntExtra(
getIntent(), IntentHandler.EXTRA_TAB_ID, Tab.INVALID_TAB_ID));
FullscreenOptions options = IntentUtils.safeGetParcelableExtra(
getIntent(), IntentHandler.EXTRA_FULLSCREEN_OPTIONS);
tab.reparent(this, createTabDelegateFactory());
tab.getFullscreenManager().setTab(tab);
tab.enterFullscreenMode(options);
mWebContentsObserver = new WebContentsObserver(tab.getWebContents()) {
@Override
public void didFinishNavigation(String url, boolean isInMainFrame, boolean isErrorPage,
boolean hasCommitted, boolean isSameDocument, boolean isFragmentNavigation,
boolean isRendererInitiated, boolean isDownload, 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 tab;
}
@Override
public void finishNativeInitialization() {
initializeCompositorContent(new LayoutManager(getCompositorViewHolder()), null /* urlBar */,
(ViewGroup) findViewById(android.R.id.content), null /* controlContainer */);
if (getFullscreenManager() != null) getFullscreenManager().setTab(getActivityTab());
super.finishNativeInitialization();
}
@Override
protected void initializeToolbar() {}
@Override
protected ChromeFullscreenManager createFullscreenManager() {
// Create a Fullscreen manager that won't change the Tab's fullscreen state when the
// Activity ends - we handle leaving fullscreen ourselves.
return new ChromeFullscreenManager(
this, ChromeFullscreenManager.ControlsPosition.NONE, false);
}
@Override
public boolean supportsFullscreenActivity() {
return true;
}
public static void enterFullscreenMode(final Tab tab, FullscreenOptions options) {
if (tab.getFullscreenManager() == null) {
Log.w(TAG, "Cannot toggle fullscreen, manager is null.");
return;
}
if (tab.getFullscreenManager().getTab() == tab) {
tab.getFullscreenManager().setTab(null);
}
launchFullscreenActivityThenStealTab(tab, options);
}
public static void exitFullscreenMode(final Tab tab) {
if (tab.getFullscreenManager() == null) {
Log.w(TAG, "Cannot toggle fullscreen, manager is null.");
return;
}
if (tab.getFullscreenManager().getTab() == tab) {
tab.getFullscreenManager().setTab(null);
}
reparentTabToOriginalOwner(tab);
}
private static void reparentTabToOriginalOwner(final Tab tab) {
ChromeActivity activity = tab.getActivity();
// On Android O, if you return to a portrait Activity from one locked in landscape, the
// Activity gets config changes signalling it has been changed to landscape and back again.
// I believe this is a bug. Since the FullscreenActivity may have had its orientation locked
// to landscape for the video, we unlock it so it doesn't trigger an erroneous config change
// in the receiving Activity.
ScreenOrientationProvider.unlockOrientation(activity.getWindowAndroid());
// If reparenting is triggered by the back button, this has already been called. If not we
// must call it to restore everything to a good state before sending the Tab back.
activity.exitFullscreenIfShowing();
Intent intent = new Intent();
intent.putExtra(Browser.EXTRA_APPLICATION_ID, activity.getPackageName());
// By default Intents from Chrome open in the current tab. We add this extra to prevent
// clobbering the top tab.
intent.putExtra(Browser.EXTRA_CREATE_NEW_TAB, true);
// Send back to the Activity it came from.
ComponentName parent = IntentUtils.safeGetParcelableExtra(
activity.getIntent(), IntentHandler.EXTRA_PARENT_COMPONENT);
if (parent != null) {
intent.setComponent(parent);
} else {
Log.d(TAG, "Cannot return fullscreen tab to parent Activity.");
// Tab.detachAndStartReparenting will give the intent a default component if it
// has none.
}
// TODO(peconn): Can we not put this in onStop?
ChromeActivity tabActivity = tab.getActivity();
if (tabActivity instanceof FullscreenActivity) {
FullscreenActivity fullscreenActivity = (FullscreenActivity) tabActivity;
if (fullscreenActivity.mWebContentsObserver != null) {
fullscreenActivity.mWebContentsObserver.destroy();
fullscreenActivity.mWebContentsObserver = null;
}
}
tab.detachAndStartReparenting(intent, null, () -> {
// The Tab's FullscreenManager changes when it is moved.
tab.getFullscreenManager().setTab(tab);
// TODO(peconn): Will this not already happen?
tab.exitFullscreenMode();
});
}
private static void launchFullscreenActivityThenStealTab(Tab tab, FullscreenOptions options) {
ChromeActivity activity = tab.getActivity();
sTabsToSteal.put(tab.getId(), tab);
Intent intent = new Intent();
intent.setClass(activity, FullscreenActivity.class);
intent.putExtra(IntentHandler.EXTRA_TAB_ID, tab.getId());
intent.putExtra(IntentHandler.EXTRA_FULLSCREEN_OPTIONS, options);
intent.putExtra(IntentHandler.EXTRA_PARENT_COMPONENT, activity.getComponentName());
intent.putExtra(Browser.EXTRA_APPLICATION_ID, activity.getPackageName());
// In multiwindow mode we want both activities to be able to launch independent
// FullscreenActivity's.
intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
activity.startActivity(intent);
}
public static boolean shouldUseFullscreenActivity(Tab tab) {
if (!ChromeFeatureList.isEnabled(ChromeFeatureList.FULLSCREEN_ACTIVITY)) return false;
ChromeActivity activity = tab.getActivity();
if (!activity.supportsFullscreenActivity()) return false;
// FullscreenActivity transitions involve Intent-ing to a new Activity. If the current
// Activity is not in the foreground we don't want to do this (as it would re-launch
// Chrome).
return ApplicationStatus.getStateForActivity(activity) == ActivityState.RESUMED;
}
private static Tab getTabToSteal(int id) {
Tab tab = sTabsToSteal.get(id);
assert tab != null;
sTabsToSteal.remove(id);
return tab;
}
@Override
protected Tab restoreTab(Bundle savedInstanceState) {
return null;
}
}