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

Unified Diff: chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchPanel.java

Issue 1304013002: Move functionality for ContentViewCore to ContextualSearchPanel (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@simple-move-cvc-to-panel
Patch Set: Rebase & revert ContextualSearchRequest Created 5 years, 4 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 side-by-side diff with in-line comments
Download patch
Index: chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchPanel.java
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchPanel.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchPanel.java
index b13f30c6dcd1d7dac97ef5d0b7b303df58d4a7aa..a24f9faa25913fb8e8c8cfede7c69e244020bff0 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchPanel.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchPanel.java
@@ -6,19 +6,36 @@ package org.chromium.chrome.browser.compositor.bottombar.contextualsearch;
import android.content.Context;
import android.os.Handler;
+import android.view.View.MeasureSpec;
+import org.chromium.base.VisibleForTesting;
import org.chromium.base.annotations.CalledByNative;
+import org.chromium.chrome.R;
+import org.chromium.chrome.browser.ChromeActivity;
+import org.chromium.chrome.browser.WebContentsFactory;
import org.chromium.chrome.browser.compositor.layouts.LayoutUpdateHost;
+import org.chromium.chrome.browser.contextualsearch.ContextualSearchContentController;
+import org.chromium.chrome.browser.externalnav.ExternalNavigationHandler;
+import org.chromium.chrome.browser.externalnav.ExternalNavigationHandler.OverrideUrlLoadingResult;
+import org.chromium.chrome.browser.externalnav.ExternalNavigationParams;
+import org.chromium.chrome.browser.tab.TabRedirectHandler;
import org.chromium.components.navigation_interception.InterceptNavigationDelegate;
+import org.chromium.components.navigation_interception.NavigationParams;
import org.chromium.components.web_contents_delegate_android.WebContentsDelegateAndroid;
+import org.chromium.content.browser.ContentView;
+import org.chromium.content.browser.ContentViewClient;
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 org.chromium.content_public.common.ConsoleMessageLevel;
+import org.chromium.ui.base.WindowAndroid;
/**
* Controls the Contextual Search Panel.
*/
public class ContextualSearchPanel extends ContextualSearchPanelAnimation
- implements ContextualSearchPanelDelegate {
+ implements ContextualSearchPanelDelegate, ContextualSearchContentController {
/**
* State of the Contextual Search Panel.
@@ -55,6 +72,14 @@ public class ContextualSearchPanel extends ContextualSearchPanelAnimation
CLOSE_BUTTON;
}
+ // The animation duration of a URL being promoted to a tab when triggered by an
+ // intercept navigation. This is faster than the standard tab promotion animation
+ // so that it completes before the navigation.
+ private static final long INTERCEPT_NAVIGATION_PROMOTION_ANIMATION_DURATION_MS = 40;
+ // We blacklist this URL because malformed URLs may bring up this page.
+ private static final String BLACKLISTED_URL = "about:blank";
+ private static final String INTENT_URL_PREFIX = "intent:";
+
/**
* The ContentViewCore that this panel will display.
*/
@@ -65,6 +90,23 @@ public class ContextualSearchPanel extends ContextualSearchPanelAnimation
*/
private long mNativeContextualSearchPanelPtr;
+ private final WebContentsDelegateAndroid mWebContentsDelegate;
+
+ private ChromeActivity mActivity;
+ private WindowAndroid mWindowAndroid;
+
+ private WebContentsObserver mWebContentsObserver;
+ private TabRedirectHandler mTabRedirectHandler;
+ private boolean mDidLoadAnyUrl;
+ private boolean mDidPromoteSearchNavigation;
+ private boolean mIsContentViewShowing;
+
+ private ContextualSearchContentController mContentController;
David Trainor- moved to gerrit 2015/08/28 22:02:18 This parameter feels weird because we're just sett
mdjones 2015/08/28 23:51:58 Yeah, the manager does something similar. I'm not
+
+ // http://crbug.com/522266 : An instance of InterceptNavigationDelegateImpl should be kept in
+ // java layer. Otherwise, the instance could be garbage-collected unexpectedly.
+ private InterceptNavigationDelegateImpl mInterceptNavigationDelegate;
+
/**
* The delay after which the hide progress will be hidden.
*/
@@ -106,6 +148,38 @@ public class ContextualSearchPanel extends ContextualSearchPanelAnimation
public ContextualSearchPanel(Context context, LayoutUpdateHost updateHost) {
super(context, updateHost);
nativeInit();
+ mContentController = this;
+
+ mWebContentsDelegate = new WebContentsDelegateAndroid() {
David Trainor- moved to gerrit 2015/08/28 22:02:18 I'm assuming all of the actual logic is moved from
mdjones 2015/08/28 23:51:58 Correct
+ @Override
+ public void onLoadStarted() {
+ super.onLoadStarted();
+ setProgressBarCompletion(0);
+ setProgressBarVisible(true);
+ requestUpdate();
+ }
+
+ @Override
+ public void onLoadStopped() {
+ super.onLoadStopped();
+ // Hides the Progress Bar after a delay to make sure it is rendered for at least
+ // a few frames, otherwise its completion won't be visually noticeable.
+ new Handler().postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ setProgressBarVisible(false);
+ requestUpdate();
+ }
+ }, HIDE_PROGRESS_BAR_DELAY);
+ }
+
+ @Override
+ public void onLoadProgressChanged(int progress) {
+ super.onLoadProgressChanged(progress);
+ setProgressBarCompletion(progress);
+ requestUpdate();
+ }
+ };
}
// ============================================================================================
@@ -124,16 +198,6 @@ public class ContextualSearchPanel extends ContextualSearchPanelAnimation
// Contextual Search Manager Integration
// ============================================================================================
- /**
- * Sets the visibility of the Search Content View.
- * @param isVisible True to make it visible.
- */
- public void setSearchContentViewVisibility(boolean isVisible) {
- if (getManagementDelegate() != null) {
- getManagementDelegate().setSearchContentViewVisibility(isVisible);
- }
- }
-
@Override
public void setPreferenceState(boolean enabled) {
if (getManagementDelegate() != null) {
@@ -155,6 +219,7 @@ public class ContextualSearchPanel extends ContextualSearchPanelAnimation
@Override
protected void onClose(StateChangeReason reason) {
+ destroyContentView();
getManagementDelegate().onCloseContextualSearch(reason);
}
@@ -183,7 +248,7 @@ public class ContextualSearchPanel extends ContextualSearchPanelAnimation
if (ty > 0 && getPanelState() == PanelState.MAXIMIZED) {
// Resets the Search Content View scroll position when swiping the Panel down
// after being maximized.
- getManagementDelegate().resetSearchContentViewScroll();
+ resetSearchContentViewScroll();
}
// Negative ty value means an upward movement so subtracting ty means expanding the panel.
@@ -252,6 +317,39 @@ public class ContextualSearchPanel extends ContextualSearchPanelAnimation
}
}
+ /**
+ * Called to check if an external navigation is being done and take the appropriate action:
+ * Auto-promotes the panel into a separate tab if that's not already being done.
+ * @param url The URL we are navigating to.
+ */
+ private void onExternalNavigation(String url) {
+ if (isFullscreenSizePanel()) {
+ // Consider the ContentView height to be fullscreen, and inform the system that
+ // the Toolbar is always visible (from the Compositor's perspective), even though
+ // the Toolbar and Base Page might be offset outside the screen. This means the
+ // renderer will consider the ContentView height to be the fullscreen height
+ // minus the Toolbar height.
+ //
+ // This is necessary to fix the bugs: crbug.com/510205 and crbug.com/510206
+ mContentViewCore.getWebContents().updateTopControlsState(false, true, false);
+ } else {
+ mContentViewCore.getWebContents().updateTopControlsState(true, false, false);
+ }
+
+ if (!mDidPromoteSearchNavigation
+ && !BLACKLISTED_URL.equals(url)
+ && !url.startsWith(INTENT_URL_PREFIX)
+ && shouldPromoteSearchNavigation()) {
+ // Do not promote to a regular tab if we're loading our Resolved Search
+ // URL, otherwise we'll promote it when prefetching the Serp.
+ // Don't promote URLs when they are navigating to an intent - this is
+ // handled by the InterceptNavigationDelegate which uses a faster
+ // maximizing animation.
+ mDidPromoteSearchNavigation = true;
+ maximizePanelThenPromoteToTab(StateChangeReason.SERP_NAVIGATION);
+ }
+ }
+
// ============================================================================================
// Gesture Event helpers
// ============================================================================================
@@ -368,6 +466,230 @@ public class ContextualSearchPanel extends ContextualSearchPanelAnimation
}
// ============================================================================================
+ // ContextualSearchContentController
+ // ============================================================================================
+
+ @Override
+ public void createNewContentView() {
+ if (mContentViewCore != null) {
+ destroyContentView();
+ }
+
+ mTabRedirectHandler = new TabRedirectHandler(mActivity);
+ mContentViewCore = new ContentViewCore(mActivity);
+
+ // Adds a ContentViewClient to override the default fullscreen size.
+ if (!isFullscreenSizePanel()) {
+ mContentViewCore.setContentViewClient(new ContentViewClient() {
+ @Override
+ public int getDesiredWidthMeasureSpec() {
+ return MeasureSpec.makeMeasureSpec(
+ getSearchContentViewWidthPx(),
+ MeasureSpec.EXACTLY);
+ }
+
+ @Override
+ public int getDesiredHeightMeasureSpec() {
+ return MeasureSpec.makeMeasureSpec(
+ getSearchContentViewHeightPx(),
+ MeasureSpec.EXACTLY);
+ }
+ });
+ }
+
+ ContentView cv = new ContentView(mActivity, mContentViewCore);
+ // Creates an initially hidden WebContents which gets shown when the panel is opened.
+ mContentViewCore.initialize(cv, cv,
+ WebContentsFactory.createWebContents(false, true), mWindowAndroid);
+
+ // Transfers the ownership of the WebContents to the native ContextualSearchManager.
+ nativeSetWebContents(mNativeContextualSearchPanelPtr, mContentViewCore,
+ mWebContentsDelegate);
+
+ mWebContentsObserver =
+ new WebContentsObserver(mContentViewCore.getWebContents()) {
+ @Override
+ public void didStartLoading(String url) {
+ mDidPromoteSearchNavigation = false;
+ }
+
+ @Override
+ public void didStartProvisionalLoadForFrame(long frameId, long parentFrameId,
+ boolean isMainFrame, String validatedUrl, boolean isErrorPage,
+ boolean isIframeSrcdoc) {
+ if (isMainFrame) onExternalNavigation(validatedUrl);
+ }
+
+ @Override
+ public void didNavigateMainFrame(String url, String baseUrl,
+ boolean isNavigationToDifferentPage, boolean isNavigationInPage,
+ int httpResultCode) {
+ handleDidNavigateMainFrame(url, httpResultCode);
+ }
+
+ @Override
+ public void didFinishLoad(long frameId, String validatedUrl,
+ boolean isMainFrame) {
+ getManagementDelegate().onSearchResultsLoaded();
+ }
+ };
+
+ mInterceptNavigationDelegate = new InterceptNavigationDelegateImpl();
+ nativeSetInterceptNavigationDelegate(mNativeContextualSearchPanelPtr,
+ mInterceptNavigationDelegate, mContentViewCore.getWebContents());
+ getManagementDelegate().onContentViewCreated(mContentViewCore);
+ }
+
+ @Override
+ public void destroyContentView() {
+ if (mContentViewCore != null) {
+ nativeDestroyWebContents(mNativeContextualSearchPanelPtr);
+ mContentViewCore.getWebContents().destroy();
+ mContentViewCore.destroy();
+ mContentViewCore = null;
+ if (mWebContentsObserver != null) {
+ mWebContentsObserver.destroy();
+ mWebContentsObserver = null;
+ }
+ }
+
+ // This should be called last here. The setSearchContentViewVisibility method
+ // will change the visibility the SearchContentView but also set the value of the
+ // internal property mIsSearchContentViewShowing. If we call this after deleting
+ // the SearchContentView, it will be faster, because only the internal property
+ // will be changed, since there will be no need to change the visibility of the
+ // SearchContentView.
+ setSearchContentViewVisibility(false);
+
+ getManagementDelegate().onContentViewDestroyed();
+ }
+
+ @Override
+ public void handleDidNavigateMainFrame(String url, int httpResultCode) {
+ if (shouldPromoteSearchNavigation()) {
+ onExternalNavigation(url);
+ } else {
+ // Could be just prefetching, check if that failed.
+ boolean isFailure = isHttpFailureCode(httpResultCode);
+ getManagementDelegate().onContextualSearchRequestNavigation(isFailure);
+ }
+ mDidLoadAnyUrl = false;
+ }
+
+ @Override
+ public void loadUrl(String url) {
+ mContentController.destroyContentView();
+ createNewPanelContentView();
+ if (mContentViewCore != null && mContentViewCore.getWebContents() != null) {
+ mDidLoadAnyUrl = true;
+ mContentViewCore.getWebContents().getNavigationController().loadUrl(
+ new LoadUrlParams(url));
+ }
+ }
+
+ // ============================================================================================
+ // Utilities
+ // ============================================================================================
+
+ public void resetSearchContentViewScroll() {
+ if (mContentViewCore != null) {
+ mContentViewCore.scrollTo(0, 0);
+ }
+ }
+
+ public float getSearchContentViewVerticalScroll() {
+ return mContentViewCore != null
+ ? mContentViewCore.computeVerticalScrollOffset() : -1.f;
+ }
+
+ /**
+ * Sets the visibility of the Search Content View.
+ * @param isVisible True to make it visible.
+ */
+ public void setSearchContentViewVisibility(boolean isVisible) {
+ if (mIsContentViewShowing == isVisible) return;
+
+ mIsContentViewShowing = isVisible;
+ getManagementDelegate().onContentViewVisibilityChanged(isVisible);
+
+ if (isVisible) {
+ // The CVC is created with the search request, but if none was made we'll need
+ // one in order to display an empty panel.
+ if (mContentViewCore == null) {
+ createNewPanelContentView();
+ }
+ if (mContentViewCore != null) mContentViewCore.onShow();
+ setWasSearchContentViewSeen();
+ } else {
+ if (mContentViewCore != null) mContentViewCore.onHide();
+ }
+ }
+
+ /**
+ * @return Whether the given HTTP result code represents a failure or not.
+ */
+ private boolean isHttpFailureCode(int httpResultCode) {
+ return httpResultCode <= 0 || httpResultCode >= 400;
+ }
+
+ /**
+ * @return whether a navigation in the search content view should promote to a separate tab.
+ */
+ private boolean shouldPromoteSearchNavigation() {
+ // A navigation can be due to us loading a URL, or a touch in the search content view.
+ // Require a touch, but no recent loading, in order to promote to a separate tab.
+ // Note that tapping the opt-in button requires checking for recent loading.
+ return didTouchSearchContentView() && !mDidLoadAnyUrl;
+ }
+
+ // ============================================================================================
+ // InterceptNavigationDelegateImpl
+ // ============================================================================================
+
+ // Used to intercept intent navigations.
+ // TODO(jeremycho): Consider creating a Tab with the Panel's ContentViewCore,
+ // which would also handle functionality like long-press-to-paste.
+ private class InterceptNavigationDelegateImpl implements InterceptNavigationDelegate {
+ final ExternalNavigationHandler mExternalNavHandler = new ExternalNavigationHandler(
+ mActivity);
+ @Override
+ public boolean shouldIgnoreNavigation(NavigationParams navigationParams) {
+ mTabRedirectHandler.updateNewUrlLoading(navigationParams.pageTransitionType,
+ navigationParams.isRedirect,
+ navigationParams.hasUserGesture || navigationParams.hasUserGestureCarryover,
+ mActivity.getLastUserInteractionTime(), TabRedirectHandler.INVALID_ENTRY_INDEX);
+
+ ExternalNavigationParams params = new ExternalNavigationParams.Builder(
+ navigationParams.url, false, navigationParams.referrer,
+ navigationParams.pageTransitionType, navigationParams.isRedirect)
+ .setApplicationMustBeInForeground(true)
+ .setRedirectHandler(mTabRedirectHandler)
+ .setIsMainFrame(navigationParams.isMainFrame)
+ .build();
+ if (mExternalNavHandler.shouldOverrideUrlLoading(params)
+ != OverrideUrlLoadingResult.NO_OVERRIDE) {
+ maximizePanelThenPromoteToTab(StateChangeReason.TAB_PROMOTION,
+ INTERCEPT_NAVIGATION_PROMOTION_ANIMATION_DURATION_MS);
+ return true;
+ }
+ if (navigationParams.isExternalProtocol) {
+ ContentViewCore baseContentView = getManagementDelegate().getBaseContentView();
+ if (baseContentView != null) {
+ int resId = mExternalNavHandler.canExternalAppHandleUrl(navigationParams.url)
+ ? R.string.blocked_navigation_warning
+ : R.string.unreachable_navigation_warning;
+ String message = mActivity.getApplicationContext().getString(
+ resId, navigationParams.url);
+ baseContentView.getWebContents().addMessageToDevToolsConsole(
+ ConsoleMessageLevel.WARNING, message);
+ }
+ return true;
+ }
+ return false;
+ }
+ }
+
+ // ============================================================================================
// Panel Delegate
// ============================================================================================
@@ -454,32 +776,6 @@ public class ContextualSearchPanel extends ContextualSearchPanelAnimation
}
@Override
- public void onLoadStarted() {
- setProgressBarCompletion(0);
- setProgressBarVisible(true);
- requestUpdate();
- }
-
- @Override
- public void onLoadStopped() {
- // Hides the Progress Bar after a delay to make sure it is rendered for at least
- // a few frames, otherwise its completion won't be visually noticeable.
- new Handler().postDelayed(new Runnable() {
- @Override
- public void run() {
- setProgressBarVisible(false);
- requestUpdate();
- }
- }, HIDE_PROGRESS_BAR_DELAY);
- }
-
- @Override
- public void onLoadProgressChanged(int progress) {
- setProgressBarCompletion(progress);
- requestUpdate();
- }
-
- @Override
public PanelState getPanelState() {
// NOTE(pedrosimonetti): exposing superclass method to the interface.
return super.getPanelState();
@@ -525,6 +821,38 @@ public class ContextualSearchPanel extends ContextualSearchPanelAnimation
return mSearchPanelFeatures.shouldAnimatePanelCloseOnPromoteToTab();
}
+ @Override
+ public boolean isContentViewShowing() {
+ return mIsContentViewShowing;
+ }
+
+ @Override
+ public void setChromeActivity(ChromeActivity activity) {
+ mActivity = activity;
+ mWindowAndroid = mActivity.getWindowAndroid();
+ }
+
+ @Override
+ public void createNewPanelContentView() {
+ mContentController.createNewContentView();
+ }
+
+ @Override
+ public void loadUrlInPanel(String url) {
+ mContentController.loadUrl(url);
+ }
+
+ @Override
+ public void setContentController(ContextualSearchContentController controller) {
+ mContentController = controller;
+ }
+
+ @VisibleForTesting
+ @Override
+ public ContextualSearchContentController getContentController() {
+ return this;
+ }
+
// ============================================================================================
// Methods for managing this panel's ContentViewCore.
// ============================================================================================
@@ -546,42 +874,14 @@ public class ContextualSearchPanel extends ContextualSearchPanelAnimation
return mContentViewCore;
}
- public void resetContentViewCore() {
- // TODO(mdjones): Merge all code related to deleting/resetting the ContentViewCore.
- mContentViewCore = null;
- }
-
- @Override
- public void destroy() {
- nativeDestroy(mNativeContextualSearchPanelPtr);
- }
-
@Override
public void removeLastHistoryEntry(String historyUrl, long urlTimeMs) {
nativeRemoveLastHistoryEntry(mNativeContextualSearchPanelPtr, historyUrl, urlTimeMs);
}
- @Override
- public void setWebContents(ContentViewCore contentView, WebContentsDelegateAndroid delegate) {
- mContentViewCore = contentView;
- nativeSetWebContents(mNativeContextualSearchPanelPtr, contentView, delegate);
- }
-
- @Override
- public void destroyWebContents() {
- nativeDestroyWebContents(mNativeContextualSearchPanelPtr);
- }
-
- @Override
- public void releaseWebContents() {
- nativeReleaseWebContents(mNativeContextualSearchPanelPtr);
- }
-
- @Override
- public void setInterceptNavigationDelegate(
- InterceptNavigationDelegate delegate, WebContents webContents) {
- nativeSetInterceptNavigationDelegate(mNativeContextualSearchPanelPtr,
- delegate, webContents);
+ @VisibleForTesting
+ public void destroy() {
+ nativeDestroy(mNativeContextualSearchPanelPtr);
}
// Native calls.
@@ -592,7 +892,6 @@ public class ContextualSearchPanel extends ContextualSearchPanelAnimation
private native void nativeSetWebContents(long nativeContextualSearchPanel,
ContentViewCore contentViewCore, WebContentsDelegateAndroid delegate);
private native void nativeDestroyWebContents(long nativeContextualSearchPanel);
- private native void nativeReleaseWebContents(long nativeContextualSearchPanel);
private native void nativeSetInterceptNavigationDelegate(long nativeContextualSearchPanel,
InterceptNavigationDelegate delegate, WebContents webContents);
}

Powered by Google App Engine
This is Rietveld 408576698