Commit a84056e0 authored by Jinsuk Kim's avatar Jinsuk Kim Committed by Commit Bot

Android: Manage Tab's associated app as UserData

Moves the app ID associated with a Tab out to manage it as UserData.
It also observes IME event to update the present id, so helps break down
the ImeEventObserver into more relevant classes.

Bug: 925242
Change-Id: I16637e98b52a07bf5199240c780c62990315b7db
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1532137
Commit-Queue: Jinsuk Kim <jinsukkim@chromium.org>
Reviewed-by: default avatarTed Choc <tedchoc@chromium.org>
Cr-Commit-Position: refs/heads/master@{#647077}
parent 9822ae8d
...@@ -1507,6 +1507,7 @@ chrome_java_sources = [ ...@@ -1507,6 +1507,7 @@ chrome_java_sources = [
"java/src/org/chromium/chrome/browser/tab/SadTab.java", "java/src/org/chromium/chrome/browser/tab/SadTab.java",
"java/src/org/chromium/chrome/browser/tab/SadTabView.java", "java/src/org/chromium/chrome/browser/tab/SadTabView.java",
"java/src/org/chromium/chrome/browser/tab/Tab.java", "java/src/org/chromium/chrome/browser/tab/Tab.java",
"java/src/org/chromium/chrome/browser/tab/TabAssociatedApp.java",
"java/src/org/chromium/chrome/browser/tab/TabAttributeKeys.java", "java/src/org/chromium/chrome/browser/tab/TabAttributeKeys.java",
"java/src/org/chromium/chrome/browser/tab/TabAttributes.java", "java/src/org/chromium/chrome/browser/tab/TabAttributes.java",
"java/src/org/chromium/chrome/browser/tab/TabBrowserControlsOffsetHelper.java", "java/src/org/chromium/chrome/browser/tab/TabBrowserControlsOffsetHelper.java",
......
...@@ -40,6 +40,7 @@ import org.chromium.chrome.browser.compositor.CompositorView; ...@@ -40,6 +40,7 @@ import org.chromium.chrome.browser.compositor.CompositorView;
import org.chromium.chrome.browser.page_info.PageInfoController; import org.chromium.chrome.browser.page_info.PageInfoController;
import org.chromium.chrome.browser.tab.EmptyTabObserver; import org.chromium.chrome.browser.tab.EmptyTabObserver;
import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.browser.tab.TabAssociatedApp;
import org.chromium.chrome.browser.tab.TabObserver; import org.chromium.chrome.browser.tab.TabObserver;
import org.chromium.chrome.browser.tab.TabRedirectHandler; import org.chromium.chrome.browser.tab.TabRedirectHandler;
import org.chromium.chrome.browser.tabmodel.ChromeTabCreator; import org.chromium.chrome.browser.tabmodel.ChromeTabCreator;
...@@ -1117,7 +1118,7 @@ public class VrShell extends GvrLayout ...@@ -1117,7 +1118,7 @@ public class VrShell extends GvrLayout
// If hitting back would minimize Chrome, disable the back button. // If hitting back would minimize Chrome, disable the back button.
// See ChromeTabbedActivity#handleBackPressed(). // See ChromeTabbedActivity#handleBackPressed().
willCloseTab = ChromeTabbedActivity.backShouldCloseTab(mTab) willCloseTab = ChromeTabbedActivity.backShouldCloseTab(mTab)
&& !mTab.isCreatedForExternalApp(); && !TabAssociatedApp.isOpenedFromExternalApp(mTab);
} }
boolean canGoBack = mTab.canGoBack() || willCloseTab; boolean canGoBack = mTab.canGoBack() || willCloseTab;
boolean canGoForward = mTab.canGoForward(); boolean canGoForward = mTab.canGoForward();
......
...@@ -125,6 +125,7 @@ import org.chromium.chrome.browser.suggestions.SuggestionsMetrics; ...@@ -125,6 +125,7 @@ import org.chromium.chrome.browser.suggestions.SuggestionsMetrics;
import org.chromium.chrome.browser.survey.ChromeSurveyController; import org.chromium.chrome.browser.survey.ChromeSurveyController;
import org.chromium.chrome.browser.tab.BrowserControlsVisibilityDelegate; import org.chromium.chrome.browser.tab.BrowserControlsVisibilityDelegate;
import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.browser.tab.TabAssociatedApp;
import org.chromium.chrome.browser.tab.TabDelegateFactory; import org.chromium.chrome.browser.tab.TabDelegateFactory;
import org.chromium.chrome.browser.tab.TabRedirectHandler; import org.chromium.chrome.browser.tab.TabRedirectHandler;
import org.chromium.chrome.browser.tab.TabStateBrowserControlsVisibilityDelegate; import org.chromium.chrome.browser.tab.TabStateBrowserControlsVisibilityDelegate;
...@@ -1954,7 +1955,8 @@ public class ChromeTabbedActivity ...@@ -1954,7 +1955,8 @@ public class ChromeTabbedActivity
// - we decided not to close the tab // - we decided not to close the tab
// - we decided to close the tab, but it was opened by an external app, so we will go // - we decided to close the tab, but it was opened by an external app, so we will go
// exit Chrome on top of closing the tab // exit Chrome on top of closing the tab
final boolean minimizeApp = !shouldCloseTab || currentTab.isCreatedForExternalApp(); final boolean minimizeApp =
!shouldCloseTab || TabAssociatedApp.isOpenedFromExternalApp(currentTab);
if (minimizeApp) { if (minimizeApp) {
if (shouldCloseTab) { if (shouldCloseTab) {
recordBackPressedUma( recordBackPressedUma(
......
...@@ -74,6 +74,7 @@ import org.chromium.chrome.browser.night_mode.NightModeStateProvider; ...@@ -74,6 +74,7 @@ import org.chromium.chrome.browser.night_mode.NightModeStateProvider;
import org.chromium.chrome.browser.page_info.PageInfoController; import org.chromium.chrome.browser.page_info.PageInfoController;
import org.chromium.chrome.browser.tab.EmptyTabObserver; import org.chromium.chrome.browser.tab.EmptyTabObserver;
import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.browser.tab.TabAssociatedApp;
import org.chromium.chrome.browser.tabmodel.ChromeTabCreator; import org.chromium.chrome.browser.tabmodel.ChromeTabCreator;
import org.chromium.chrome.browser.tabmodel.TabModelSelector; import org.chromium.chrome.browser.tabmodel.TabModelSelector;
import org.chromium.chrome.browser.tabmodel.TabModelSelectorImpl; import org.chromium.chrome.browser.tabmodel.TabModelSelectorImpl;
...@@ -648,7 +649,7 @@ public class CustomTabActivity extends ChromeActivity<CustomTabActivityComponent ...@@ -648,7 +649,7 @@ public class CustomTabActivity extends ChromeActivity<CustomTabActivityComponent
private void recordClientConnectionStatus() { private void recordClientConnectionStatus() {
String packageName = String packageName =
(getActivityTab() == null) ? null : getActivityTab().getAppAssociatedWith(); (getActivityTab() == null) ? null : TabAssociatedApp.getAppId(getActivityTab());
if (packageName == null) return; // No associated package if (packageName == null) return; // No associated package
boolean isConnected = boolean isConnected =
......
...@@ -24,6 +24,7 @@ import org.chromium.chrome.browser.fullscreen.ComposedBrowserControlsVisibilityD ...@@ -24,6 +24,7 @@ import org.chromium.chrome.browser.fullscreen.ComposedBrowserControlsVisibilityD
import org.chromium.chrome.browser.multiwindow.MultiWindowUtils; import org.chromium.chrome.browser.multiwindow.MultiWindowUtils;
import org.chromium.chrome.browser.tab.BrowserControlsVisibilityDelegate; import org.chromium.chrome.browser.tab.BrowserControlsVisibilityDelegate;
import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.browser.tab.TabAssociatedApp;
import org.chromium.chrome.browser.tab.TabContextMenuItemDelegate; import org.chromium.chrome.browser.tab.TabContextMenuItemDelegate;
import org.chromium.chrome.browser.tab.TabDelegateFactory; import org.chromium.chrome.browser.tab.TabDelegateFactory;
import org.chromium.chrome.browser.tab.TabStateBrowserControlsVisibilityDelegate; import org.chromium.chrome.browser.tab.TabStateBrowserControlsVisibilityDelegate;
...@@ -272,8 +273,8 @@ public class CustomTabDelegateFactory extends TabDelegateFactory { ...@@ -272,8 +273,8 @@ public class CustomTabDelegateFactory extends TabDelegateFactory {
if (mIsOpenedByChrome) { if (mIsOpenedByChrome) {
mNavigationDelegate = new ExternalNavigationDelegateImpl(tab); mNavigationDelegate = new ExternalNavigationDelegateImpl(tab);
} else { } else {
mNavigationDelegate = new CustomTabNavigationDelegate(tab, tab.getAppAssociatedWith(), mNavigationDelegate = new CustomTabNavigationDelegate(
mExternalAuthUtils); tab, TabAssociatedApp.getAppId(tab), mExternalAuthUtils);
} }
return new ExternalNavigationHandler(mNavigationDelegate); return new ExternalNavigationHandler(mNavigationDelegate);
} }
......
...@@ -39,6 +39,7 @@ import org.chromium.chrome.browser.lifecycle.InflationObserver; ...@@ -39,6 +39,7 @@ import org.chromium.chrome.browser.lifecycle.InflationObserver;
import org.chromium.chrome.browser.lifecycle.NativeInitObserver; import org.chromium.chrome.browser.lifecycle.NativeInitObserver;
import org.chromium.chrome.browser.tab.EmptyTabObserver; import org.chromium.chrome.browser.tab.EmptyTabObserver;
import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.browser.tab.TabAssociatedApp;
import org.chromium.chrome.browser.tab.TabRedirectHandler; import org.chromium.chrome.browser.tab.TabRedirectHandler;
import org.chromium.chrome.browser.tabmodel.AsyncTabParams; import org.chromium.chrome.browser.tabmodel.AsyncTabParams;
import org.chromium.chrome.browser.tabmodel.AsyncTabParamsManager; import org.chromium.chrome.browser.tabmodel.AsyncTabParamsManager;
...@@ -292,7 +293,7 @@ public class CustomTabActivityTabController implements InflationObserver, Native ...@@ -292,7 +293,7 @@ public class CustomTabActivityTabController implements InflationObserver, Native
if (tab == null) return null; if (tab == null) return null;
RecordHistogram.recordEnumeratedHistogram("CustomTabs.WebContentsStateOnLaunch", RecordHistogram.recordEnumeratedHistogram("CustomTabs.WebContentsStateOnLaunch",
WebContentsState.PRERENDERED_WEBCONTENTS, WebContentsState.NUM_ENTRIES); WebContentsState.PRERENDERED_WEBCONTENTS, WebContentsState.NUM_ENTRIES);
tab.setAppAssociatedWith(mConnection.getClientPackageNameForSession(mSession)); TabAssociatedApp.from(tab).setAppId(mConnection.getClientPackageNameForSession(mSession));
if (mIntentDataProvider.shouldEnableEmbeddedMediaExperience()) { if (mIntentDataProvider.shouldEnableEmbeddedMediaExperience()) {
tab.enableEmbeddedMediaExperience(true); tab.enableEmbeddedMediaExperience(true);
} }
...@@ -307,9 +308,10 @@ public class CustomTabActivityTabController implements InflationObserver, Native ...@@ -307,9 +308,10 @@ public class CustomTabActivityTabController implements InflationObserver, Native
CustomTabIntentDataProvider.EXTRA_BROWSER_LAUNCH_SOURCE, LaunchSourceType.OTHER); CustomTabIntentDataProvider.EXTRA_BROWSER_LAUNCH_SOURCE, LaunchSourceType.OTHER);
if (launchSource == LaunchSourceType.WEBAPK) { if (launchSource == LaunchSourceType.WEBAPK) {
String webapkPackageName = mIntent.getStringExtra(Browser.EXTRA_APPLICATION_ID); String webapkPackageName = mIntent.getStringExtra(Browser.EXTRA_APPLICATION_ID);
tab.setAppAssociatedWith(webapkPackageName); TabAssociatedApp.from(tab).setAppId(webapkPackageName);
} else { } else {
tab.setAppAssociatedWith(mConnection.getClientPackageNameForSession(mSession)); TabAssociatedApp.from(tab).setAppId(
mConnection.getClientPackageNameForSession(mSession));
} }
tab.initialize(webContents, mCustomTabDelegateFactory.get(), false /*initiallyHidden*/, tab.initialize(webContents, mCustomTabDelegateFactory.get(), false /*initiallyHidden*/,
......
...@@ -18,6 +18,7 @@ import org.json.JSONException; ...@@ -18,6 +18,7 @@ import org.json.JSONException;
import org.chromium.base.VisibleForTesting; import org.chromium.base.VisibleForTesting;
import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.browser.tab.TabAssociatedApp;
import java.security.MessageDigest; import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
...@@ -32,7 +33,7 @@ public class OfflinePageOrigin { ...@@ -32,7 +33,7 @@ public class OfflinePageOrigin {
/** Creates origin based on the context and tab. */ /** Creates origin based on the context and tab. */
public OfflinePageOrigin(Context context, Tab tab) { public OfflinePageOrigin(Context context, Tab tab) {
this(context, tab.getAppAssociatedWith()); this(context, TabAssociatedApp.getAppId(tab));
} }
/** Creates origin based on the context and an app name. */ /** Creates origin based on the context and an app name. */
......
...@@ -204,12 +204,6 @@ public class Tab ...@@ -204,12 +204,6 @@ public class Tab
*/ */
private String mUrl; private String mUrl;
/**
* The external application that this Tab is associated with (null if not associated with any
* app). Allows reusing of tabs opened from the same application.
*/
private String mAppAssociatedWith;
/** /**
* True while a page load is in progress. * True while a page load is in progress.
*/ */
...@@ -370,12 +364,10 @@ public class Tab ...@@ -370,12 +364,10 @@ public class Tab
*/ */
private void restoreFieldsFromState(TabState state) { private void restoreFieldsFromState(TabState state) {
assert state != null; assert state != null;
mAppAssociatedWith = state.openerAppId; state.restoreFields(this);
mFrozenContentsState = state.contentsState; mFrozenContentsState = state.contentsState;
mTimestampMillis = state.timestampMillis; mTimestampMillis = state.timestampMillis;
mUrl = state.getVirtualUrlFromState(); mUrl = state.getVirtualUrlFromState();
TabThemeColorHelper.get(this).updateFromTabState(state);
mTitle = state.getDisplayTitleFromState(); mTitle = state.getDisplayTitleFromState();
mLaunchTypeAtCreation = state.tabLaunchTypeAtCreation; mLaunchTypeAtCreation = state.tabLaunchTypeAtCreation;
mRootId = state.rootId == Tab.INVALID_TAB_ID ? mId : state.rootId; mRootId = state.rootId == Tab.INVALID_TAB_ID ? mId : state.rootId;
...@@ -443,11 +435,6 @@ public class Tab ...@@ -443,11 +435,6 @@ public class Tab
mIsNativePageCommitPending = maybeShowNativePage(params.getUrl(), false); mIsNativePageCommitPending = maybeShowNativePage(params.getUrl(), false);
} }
// Clear the app association if the user navigated to a different page from the omnibox.
if ((params.getTransitionType() & PageTransition.FROM_ADDRESS_BAR)
== PageTransition.FROM_ADDRESS_BAR) {
mAppAssociatedWith = null;
}
if ("chrome://java-crash/".equals(params.getUrl())) { if ("chrome://java-crash/".equals(params.getUrl())) {
return handleJavaCrash(); return handleJavaCrash();
} }
...@@ -1786,29 +1773,6 @@ public class Tab ...@@ -1786,29 +1773,6 @@ public class Tab
return mPendingLoadParams; return mPendingLoadParams;
} }
/**
* @see #setAppAssociatedWith(String) for more information.
* TODO(aurimas): investigate reducing the visibility of this method after TabModel refactoring.
*
* @return The id of the application associated with that tab (null if not
* associated with an app).
*/
public String getAppAssociatedWith() {
return mAppAssociatedWith;
}
/**
* Associates this tab with the external app with the specified id. Once a Tab is associated
* with an app, it is reused when a new page is opened from that app (unless the user typed in
* the location bar or in the page, in which case the tab is dissociated from any app)
* TODO(aurimas): investigate reducing the visibility of this method after TabModel refactoring.
*
* @param appId The ID of application associated with the tab.
*/
public void setAppAssociatedWith(String appId) {
mAppAssociatedWith = appId;
}
/** /**
* @return See {@link #mTimestampMillis}. * @return See {@link #mTimestampMillis}.
*/ */
...@@ -2126,15 +2090,6 @@ public class Tab ...@@ -2126,15 +2090,6 @@ public class Tab
return mIsRendererUnresponsive; return mIsRendererUnresponsive;
} }
/**
* @return Whether or not the tab was opened by an app other than Chrome.
*/
public boolean isCreatedForExternalApp() {
String packageName = ContextUtils.getApplicationContext().getPackageName();
return getLaunchType() == TabLaunchType.FROM_EXTERNAL_APP
&& !TextUtils.equals(getAppAssociatedWith(), packageName);
}
/** /**
* Set the Webapp manifest scope, which is used to allow frames within the scope to autoplay * Set the Webapp manifest scope, which is used to allow frames within the scope to autoplay
* media unmuted. * media unmuted.
......
// Copyright 2019 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.tab;
import android.text.TextUtils;
import org.chromium.base.ContextUtils;
import org.chromium.chrome.browser.tabmodel.TabLaunchType;
import org.chromium.content_public.browser.ImeAdapter;
import org.chromium.content_public.browser.ImeEventObserver;
import org.chromium.content_public.browser.LoadUrlParams;
import org.chromium.content_public.browser.WebContents;
import org.chromium.ui.base.PageTransition;
/**
* User data for a {@link Tab} managing an ID of an external application that opened it.
*/
public final class TabAssociatedApp extends TabWebContentsUserData implements ImeEventObserver {
private static final Class<TabAssociatedApp> USER_DATA_KEY = TabAssociatedApp.class;
/**
* The external application that this Tab is associated with (null if not associated with any
* app). Allows reusing of tabs opened from the same application.
*/
private String mId;
public static TabAssociatedApp from(Tab tab) {
TabAssociatedApp app = get(tab);
if (app == null) {
app = tab.getUserDataHost().setUserData(USER_DATA_KEY, new TabAssociatedApp(tab));
}
return app;
}
private TabAssociatedApp(Tab tab) {
super(tab);
tab.addObserver(new EmptyTabObserver() {
@Override
public void onLoadUrl(Tab tab, LoadUrlParams params, int loadType) {
// Clear the app association if the user navigated to a different page from the
// omnibox.
if ((params.getTransitionType() & PageTransition.FROM_ADDRESS_BAR)
== PageTransition.FROM_ADDRESS_BAR) {
mId = null;
}
}
@Override
public void onDestroyed(Tab tab) {
tab.removeObserver(this);
}
});
}
private static TabAssociatedApp get(Tab tab) {
return tab.getUserDataHost().getUserData(USER_DATA_KEY);
}
/**
* @see #getAppId()
*/
public static String getAppId(Tab tab) {
TabAssociatedApp app = get(tab);
return app != null ? app.getAppId() : null;
}
/**
* @return Whether or not the tab was opened by an app other than Chrome.
*/
public static boolean isOpenedFromExternalApp(Tab tab) {
TabAssociatedApp app = get(tab);
if (app == null) return false;
String packageName = ContextUtils.getApplicationContext().getPackageName();
return tab.getLaunchType() == TabLaunchType.FROM_EXTERNAL_APP
&& !TextUtils.equals(app.getAppId(), packageName);
}
@Override
public void initWebContents(WebContents webContents) {
ImeAdapter.fromWebContents(webContents).addEventObserver(this);
}
@Override
public void cleanupWebContents(WebContents webContents) {}
/**
* Associates this tab with the external app with the specified id. Once a Tab is associated
* with an app, it is reused when a new page is opened from that app (unless the user typed in
* the location bar or in the page, in which case the tab is dissociated from any app)
*
* @param appId The ID of application associated with the tab.
*/
public void setAppId(String name) {
mId = name;
}
/**
* @see #setAppId(String) for more information.
*
* @return The id of the application associated with that tab (null if not
* associated with an app).
*/
public String getAppId() {
return mId;
}
// ImeEventObserver
@Override
public void onImeEvent() {
// Some text was set in the page. Don't reuse it if a tab is open from the same
// external application, we might lose some user data.
mId = null;
}
}
...@@ -4,16 +4,17 @@ ...@@ -4,16 +4,17 @@
package org.chromium.chrome.browser.tab; package org.chromium.chrome.browser.tab;
import org.chromium.base.UserData;
import org.chromium.base.UserDataHost;
import org.chromium.chrome.browser.fullscreen.FullscreenOptions; import org.chromium.chrome.browser.fullscreen.FullscreenOptions;
import org.chromium.content_public.browser.ImeAdapter;
import org.chromium.content_public.browser.ImeEventObserver;
import org.chromium.content_public.browser.SelectionPopupController; import org.chromium.content_public.browser.SelectionPopupController;
import org.chromium.content_public.browser.WebContents;
import org.chromium.content_public.common.BrowserControlsState; import org.chromium.content_public.common.BrowserControlsState;
/** /**
* {@link TabObserver} for basic fullscreen operations for {@link Tab}. * {@link TabObserver} for basic fullscreen operations for {@link Tab}.
*/ */
public final class TabFullscreenHandler extends EmptyTabObserver implements UserData { public final class TabFullscreenHandler extends TabWebContentsUserData implements ImeEventObserver {
private static final Class<TabFullscreenHandler> USER_DATA_KEY = TabFullscreenHandler.class; private static final Class<TabFullscreenHandler> USER_DATA_KEY = TabFullscreenHandler.class;
private final Tab mTab; private final Tab mTab;
...@@ -22,89 +23,108 @@ public final class TabFullscreenHandler extends EmptyTabObserver implements User ...@@ -22,89 +23,108 @@ public final class TabFullscreenHandler extends EmptyTabObserver implements User
private Runnable mEnterFullscreenRunnable; private Runnable mEnterFullscreenRunnable;
public static void createForTab(Tab tab) { public static void createForTab(Tab tab) {
UserDataHost host = tab.getUserDataHost(); assert get(tab) == null;
assert host.getUserData(USER_DATA_KEY) == null; tab.getUserDataHost().setUserData(USER_DATA_KEY, new TabFullscreenHandler(tab));
host.setUserData(USER_DATA_KEY, new TabFullscreenHandler(tab));
} }
private TabFullscreenHandler(Tab tab) { private TabFullscreenHandler(Tab tab) {
super(tab);
mTab = tab; mTab = tab;
mTab.addObserver(this); mTab.addObserver(new EmptyTabObserver() {
} @Override
public void onSSLStateUpdated(Tab tab) {
// UserData tab.updateFullscreenEnabledState();
}
@Override
public void destroy() { @Override
mTab.removeObserver(this); public void onInteractabilityChanged(boolean interactable) {
} if (interactable && mEnterFullscreenRunnable != null)
mEnterFullscreenRunnable.run();
@Override }
public void onSSLStateUpdated(Tab tab) {
tab.updateFullscreenEnabledState(); @Override
} public void onEnterFullscreenMode(Tab tab, final FullscreenOptions options) {
if (!tab.isUserInteractable()) {
mEnterFullscreenRunnable = new Runnable() {
@Override
public void run() {
enterFullscreenInternal(tab, options);
mEnterFullscreenRunnable = null;
}
};
return;
}
@Override enterFullscreenInternal(tab, options);
public void onInteractabilityChanged(boolean interactable) { }
if (interactable && mEnterFullscreenRunnable != null) mEnterFullscreenRunnable.run();
}
@Override @Override
public void onEnterFullscreenMode(Tab tab, final FullscreenOptions options) { public void onExitFullscreenMode(Tab tab) {
if (!tab.isUserInteractable()) { if (mEnterFullscreenRunnable != null) {
mEnterFullscreenRunnable = new Runnable() {
@Override
public void run() {
enterFullscreenInternal(tab, options);
mEnterFullscreenRunnable = null; mEnterFullscreenRunnable = null;
return;
} }
};
return;
}
enterFullscreenInternal(tab, options); if (tab.getFullscreenManager() != null) {
} tab.getFullscreenManager().exitPersistentFullscreenMode();
}
}
/**
* Do the actual enter of fullscreen mode.
* @param options Options adjust fullscreen mode.
*/
private void enterFullscreenInternal(Tab tab, FullscreenOptions options) {
if (tab.getFullscreenManager() != null) {
tab.getFullscreenManager().enterPersistentFullscreenMode(options);
}
@Override if (tab.getWebContents() != null) {
public void onExitFullscreenMode(Tab tab) { SelectionPopupController controller =
if (mEnterFullscreenRunnable != null) { SelectionPopupController.fromWebContents(tab.getWebContents());
mEnterFullscreenRunnable = null; controller.destroySelectActionMode();
return; }
} }
if (tab.getFullscreenManager() != null) { @Override
tab.getFullscreenManager().exitPersistentFullscreenMode(); public void onRendererResponsiveStateChanged(Tab tab, boolean isResponsive) {
} if (tab.getFullscreenManager() == null) return;
if (isResponsive) {
tab.updateFullscreenEnabledState();
} else {
tab.updateBrowserControlsState(BrowserControlsState.SHOWN, false);
}
}
@Override
public void onPageLoadFinished(Tab tab, String url) {
tab.updateFullscreenEnabledState();
}
@Override
public void onDestroyed(Tab tab) {
tab.removeObserver(this);
}
});
} }
/** static TabFullscreenHandler get(Tab tab) {
* Do the actual enter of fullscreen mode. return tab.getUserDataHost().getUserData(USER_DATA_KEY);
* @param options Options adjust fullscreen mode.
*/
private void enterFullscreenInternal(Tab tab, FullscreenOptions options) {
if (tab.getFullscreenManager() != null) {
tab.getFullscreenManager().enterPersistentFullscreenMode(options);
}
if (tab.getWebContents() != null) {
SelectionPopupController controller =
SelectionPopupController.fromWebContents(tab.getWebContents());
controller.destroySelectActionMode();
}
} }
@Override @Override
public void onRendererResponsiveStateChanged(Tab tab, boolean isResponsive) { public void initWebContents(WebContents webContents) {
if (tab.getFullscreenManager() == null) return; ImeAdapter.fromWebContents(webContents).addEventObserver(this);
if (isResponsive) {
tab.updateFullscreenEnabledState();
} else {
tab.updateBrowserControlsState(BrowserControlsState.SHOWN, false);
}
} }
@Override @Override
public void onPageLoadFinished(Tab tab, String url) { public void cleanupWebContents(WebContents webContents) {}
tab.updateFullscreenEnabledState();
// ImeEventObserver
@Override
public void onNodeAttributeUpdated(boolean editable, boolean password) {
if (mTab.getFullscreenManager() == null) return;
mTab.updateFullscreenEnabledState();
} }
} }
...@@ -13,8 +13,6 @@ import org.chromium.chrome.browser.media.ui.MediaSessionTabHelper; ...@@ -13,8 +13,6 @@ import org.chromium.chrome.browser.media.ui.MediaSessionTabHelper;
import org.chromium.chrome.browser.tab.TabUma.TabCreationState; import org.chromium.chrome.browser.tab.TabUma.TabCreationState;
import org.chromium.components.content_capture.ContentCaptureFeatures; import org.chromium.components.content_capture.ContentCaptureFeatures;
import org.chromium.components.content_capture.ContentCaptureReceiverManager; import org.chromium.components.content_capture.ContentCaptureReceiverManager;
import org.chromium.content_public.browser.ImeAdapter;
import org.chromium.content_public.browser.ImeEventObserver;
import org.chromium.content_public.browser.SelectionPopupController; import org.chromium.content_public.browser.SelectionPopupController;
import org.chromium.content_public.browser.WebContents; import org.chromium.content_public.browser.WebContents;
import org.chromium.content_public.browser.WebContentsAccessibility; import org.chromium.content_public.browser.WebContentsAccessibility;
...@@ -58,26 +56,11 @@ public final class TabHelpers { ...@@ -58,26 +56,11 @@ public final class TabHelpers {
SwipeRefreshHandler.from(tab); SwipeRefreshHandler.from(tab);
TabFavicon.from(tab); TabFavicon.from(tab);
TrustedCdn.from(tab); TrustedCdn.from(tab);
TabAssociatedApp.from(tab);
WebContents webContents = tab.getWebContents(); WebContents webContents = tab.getWebContents();
// Initializes WebContents objects. // Initializes WebContents objects.
// TODO(jinsukkim): Split this up into a new userdata and FullscreenHandler.
ImeAdapter.fromWebContents(webContents).addEventObserver(new ImeEventObserver() {
@Override
public void onImeEvent() {
// Some text was set in the page. Don't reuse it if a tab is open from the same
// external application, we might lose some user data.
tab.setAppAssociatedWith(null);
}
@Override
public void onNodeAttributeUpdated(boolean editable, boolean password) {
if (tab.getFullscreenManager() == null) return;
tab.updateFullscreenEnabledState();
}
});
SelectionPopupController.fromWebContents(webContents) SelectionPopupController.fromWebContents(webContents)
.setActionModeCallback(new ChromeActionModeCallback(tab, webContents)); .setActionModeCallback(new ChromeActionModeCallback(tab, webContents));
......
...@@ -358,7 +358,7 @@ public class TabState { ...@@ -358,7 +358,7 @@ public class TabState {
if (!tab.isInitialized()) return null; if (!tab.isInitialized()) return null;
TabState tabState = new TabState(); TabState tabState = new TabState();
tabState.contentsState = getWebContentsState(tab); tabState.contentsState = getWebContentsState(tab);
tabState.openerAppId = tab.getAppAssociatedWith(); tabState.openerAppId = TabAssociatedApp.getAppId(tab);
tabState.parentId = tab.getParentId(); tabState.parentId = tab.getParentId();
tabState.timestampMillis = tab.getTimestampMillis(); tabState.timestampMillis = tab.getTimestampMillis();
tabState.tabLaunchTypeAtCreation = tab.getLaunchTypeAtInitialTabCreation(); tabState.tabLaunchTypeAtCreation = tab.getLaunchTypeAtInitialTabCreation();
...@@ -371,6 +371,16 @@ public class TabState { ...@@ -371,6 +371,16 @@ public class TabState {
return tabState; return tabState;
} }
/**
* Restores fields of a Tab from this TabState.
* @param tab Tab to restore.
*/
public void restoreFields(Tab tab) {
// TODO(jinsukkim): Handle this with a new TabObserver method.
TabAssociatedApp.from(tab).setAppId(openerAppId);
TabThemeColorHelper.get(tab).updateFromTabState(this);
}
/** Returns an object representing the state of the Tab's WebContents. */ /** Returns an object representing the state of the Tab's WebContents. */
private static WebContentsState getWebContentsState(Tab tab) { private static WebContentsState getWebContentsState(Tab tab) {
if (tab.getFrozenContentsState() != null) return tab.getFrozenContentsState(); if (tab.getFrozenContentsState() != null) return tab.getFrozenContentsState();
......
...@@ -14,6 +14,7 @@ import org.chromium.chrome.browser.IntentHandler; ...@@ -14,6 +14,7 @@ import org.chromium.chrome.browser.IntentHandler;
import org.chromium.chrome.browser.ServiceTabLauncher; import org.chromium.chrome.browser.ServiceTabLauncher;
import org.chromium.chrome.browser.net.spdyproxy.DataReductionProxySettings; import org.chromium.chrome.browser.net.spdyproxy.DataReductionProxySettings;
import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.browser.tab.TabAssociatedApp;
import org.chromium.chrome.browser.tab.TabBuilder; import org.chromium.chrome.browser.tab.TabBuilder;
import org.chromium.chrome.browser.tab.TabDelegateFactory; import org.chromium.chrome.browser.tab.TabDelegateFactory;
import org.chromium.chrome.browser.tab.TabParentIntent; import org.chromium.chrome.browser.tab.TabParentIntent;
...@@ -268,7 +269,7 @@ public class ChromeTabCreator extends TabCreatorManager.TabCreator { ...@@ -268,7 +269,7 @@ public class ChromeTabCreator extends TabCreatorManager.TabCreator {
// Let's try to find an existing tab that was started by that app. // Let's try to find an existing tab that was started by that app.
for (int i = 0; i < mTabModel.getCount(); i++) { for (int i = 0; i < mTabModel.getCount(); i++) {
Tab tab = mTabModel.getTabAt(i); Tab tab = mTabModel.getTabAt(i);
if (appId.equals(tab.getAppAssociatedWith())) { if (appId.equals(TabAssociatedApp.getAppId(tab))) {
// We don't reuse the tab, we create a new one at the same index instead. // We don't reuse the tab, we create a new one at the same index instead.
// Reusing a tab would require clearing the navigation history and clearing the // Reusing a tab would require clearing the navigation history and clearing the
// contents (we would not want the previous content to show). // contents (we would not want the previous content to show).
...@@ -276,7 +277,7 @@ public class ChromeTabCreator extends TabCreatorManager.TabCreator { ...@@ -276,7 +277,7 @@ public class ChromeTabCreator extends TabCreatorManager.TabCreator {
loadUrlParams.setIntentReceivedTimestamp(intentTimestamp); loadUrlParams.setIntentReceivedTimestamp(intentTimestamp);
Tab newTab = createNewTab( Tab newTab = createNewTab(
loadUrlParams, TabLaunchType.FROM_EXTERNAL_APP, null, i, intent); loadUrlParams, TabLaunchType.FROM_EXTERNAL_APP, null, i, intent);
newTab.setAppAssociatedWith(appId); TabAssociatedApp.from(newTab).setAppId(appId);
mTabModel.closeTab(tab, false, false, false); mTabModel.closeTab(tab, false, false, false);
return newTab; return newTab;
} }
...@@ -284,7 +285,7 @@ public class ChromeTabCreator extends TabCreatorManager.TabCreator { ...@@ -284,7 +285,7 @@ public class ChromeTabCreator extends TabCreatorManager.TabCreator {
// No tab for that app, we'll have to create a new one. // No tab for that app, we'll have to create a new one.
Tab tab = launchUrl(url, TabLaunchType.FROM_EXTERNAL_APP, intent, intentTimestamp); Tab tab = launchUrl(url, TabLaunchType.FROM_EXTERNAL_APP, intent, intentTimestamp);
tab.setAppAssociatedWith(appId); TabAssociatedApp.from(tab).setAppId(appId);
return tab; return tab;
} }
......
...@@ -16,6 +16,7 @@ import org.junit.Rule; ...@@ -16,6 +16,7 @@ import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.chromium.base.ThreadUtils;
import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.CommandLineFlags;
import org.chromium.base.test.util.RetryOnFailure; import org.chromium.base.test.util.RetryOnFailure;
import org.chromium.chrome.browser.ChromeSwitches; import org.chromium.chrome.browser.ChromeSwitches;
...@@ -76,7 +77,8 @@ public class CustomTabExternalNavigationTest { ...@@ -76,7 +77,8 @@ public class CustomTabExternalNavigationTest {
Assert.assertTrue(delegateFactory instanceof CustomTabDelegateFactory); Assert.assertTrue(delegateFactory instanceof CustomTabDelegateFactory);
CustomTabDelegateFactory customTabDelegateFactory = CustomTabDelegateFactory customTabDelegateFactory =
((CustomTabDelegateFactory) delegateFactory); ((CustomTabDelegateFactory) delegateFactory);
mUrlHandler = customTabDelegateFactory.createExternalNavigationHandler(tab); mUrlHandler = ThreadUtils.runOnUiThreadBlocking(
() -> customTabDelegateFactory.createExternalNavigationHandler(tab));
Assert.assertTrue(customTabDelegateFactory.getExternalNavigationDelegate() Assert.assertTrue(customTabDelegateFactory.getExternalNavigationDelegate()
instanceof CustomTabNavigationDelegate); instanceof CustomTabNavigationDelegate);
mNavigationDelegate = (CustomTabNavigationDelegate) mNavigationDelegate = (CustomTabNavigationDelegate)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment