| 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 57cdbac647e4ac4bd52427f86a456f04042c9d68..26ac4a2704e81678e69c8ddeafe7a3f55b187673 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,32 @@ 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.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.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.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 +68,11 @@ 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;
|
| +
|
| /**
|
| * The ContentViewCore that this panel will display.
|
| */
|
| @@ -66,6 +84,51 @@ public class ContextualSearchPanel extends ContextualSearchPanelAnimation
|
| private long mNativeContextualSearchPanelPtr;
|
|
|
| /**
|
| + * Used for progress bar handling.
|
| + */
|
| + private final WebContentsDelegateAndroid mWebContentsDelegate;
|
| +
|
| + /**
|
| + * The activity this panel is in.
|
| + */
|
| + private ChromeActivity mActivity;
|
| +
|
| + /**
|
| + * The window android for the above activity.
|
| + */
|
| + private WindowAndroid mWindowAndroid;
|
| +
|
| + /**
|
| + * Observes the ContentViewCore for this panel.
|
| + */
|
| + private WebContentsObserver mWebContentsObserver;
|
| +
|
| + /**
|
| + * Handles tab redirection requests.
|
| + */
|
| + private TabRedirectHandler mTabRedirectHandler;
|
| +
|
| + /**
|
| + * Used to detect if a URL was loaded in the ContentViewCore.
|
| + */
|
| + private boolean mDidLoadAnyUrl;
|
| +
|
| + /**
|
| + * Used to track if the ContentViewCore is showing.
|
| + */
|
| + private boolean mIsContentViewShowing;
|
| +
|
| + /**
|
| + * This is primarily used for injecting test functionaluty into the panel for creating and
|
| + * destroying ContentViewCores.
|
| + */
|
| + private ContextualSearchContentController mContentController;
|
| +
|
| + // 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.
|
| */
|
| private static final long HIDE_PROGRESS_BAR_DELAY = 1000 / 60 * 4;
|
| @@ -106,6 +169,40 @@ public class ContextualSearchPanel extends ContextualSearchPanelAnimation
|
| public ContextualSearchPanel(Context context, LayoutUpdateHost updateHost) {
|
| super(context, updateHost);
|
| nativeInit();
|
| +
|
| + // TODO(mdjones): The following is for testing purposes, refactor the need for this out.
|
| + mContentController = this;
|
| +
|
| + mWebContentsDelegate = new WebContentsDelegateAndroid() {
|
| + @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 +221,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 +242,7 @@ public class ContextualSearchPanel extends ContextualSearchPanelAnimation
|
|
|
| @Override
|
| protected void onClose(StateChangeReason reason) {
|
| + mContentController.destroyContentView();
|
| getManagementDelegate().onCloseContextualSearch(reason);
|
| }
|
|
|
| @@ -183,7 +271,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.
|
| @@ -368,6 +456,178 @@ public class ContextualSearchPanel extends ContextualSearchPanelAnimation
|
| }
|
|
|
| // ============================================================================================
|
| + // ContextualSearchContentController
|
| + // ============================================================================================
|
| +
|
| + @Override
|
| + public void createNewContentView() {
|
| + // TODO(mdjones): This should not be a public API.
|
| + if (mContentViewCore != null) {
|
| + mContentController.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) {
|
| + getManagementDelegate().onStartedLoading();
|
| + }
|
| +
|
| + @Override
|
| + public void didStartProvisionalLoadForFrame(long frameId, long parentFrameId,
|
| + boolean isMainFrame, String validatedUrl, boolean isErrorPage,
|
| + boolean isIframeSrcdoc) {
|
| + if (isMainFrame) getManagementDelegate().onExternalNavigation(validatedUrl);
|
| + }
|
| +
|
| + @Override
|
| + public void didNavigateMainFrame(String url, String baseUrl,
|
| + boolean isNavigationToDifferentPage, boolean isNavigationInPage,
|
| + int httpResultCode) {
|
| + getManagementDelegate().handleDidNavigateMainFrame(url, httpResultCode);
|
| + mDidLoadAnyUrl = false;
|
| + }
|
| +
|
| + @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() {
|
| + // TODO(mdjones): This should not be a public API.
|
| + 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 loadUrl(String url) {
|
| + mContentController.destroyContentView();
|
| + createNewPanelContentView();
|
| + if (mContentViewCore != null && mContentViewCore.getWebContents() != null) {
|
| + mDidLoadAnyUrl = true;
|
| + mContentViewCore.getWebContents().getNavigationController().loadUrl(
|
| + new LoadUrlParams(url));
|
| + }
|
| + }
|
| +
|
| + 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();
|
| + }
|
| + }
|
| +
|
| + // ============================================================================================
|
| + // 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);
|
| +
|
| + // TODO(mdjones): Rather than passing the two navigation params, instead consider
|
| + // passing a boolean to make this API simpler.
|
| + return !getManagementDelegate().shouldInterceptNavigation(mExternalNavHandler,
|
| + navigationParams);
|
| + }
|
| + }
|
| +
|
| + // ============================================================================================
|
| // Panel Delegate
|
| // ============================================================================================
|
|
|
| @@ -454,32 +714,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();
|
| @@ -491,7 +725,6 @@ public class ContextualSearchPanel extends ContextualSearchPanelAnimation
|
| super.setDidSearchInvolvePromo();
|
| }
|
|
|
| - @Override
|
| public void setWasSearchContentViewSeen() {
|
| // NOTE(pedrosimonetti): exposing superclass method to the interface.
|
| super.setWasSearchContentViewSeen();
|
| @@ -545,6 +778,58 @@ public class ContextualSearchPanel extends ContextualSearchPanelAnimation
|
| animateSearchTermResolution();
|
| }
|
|
|
| + @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;
|
| + }
|
| +
|
| + @Override
|
| + public boolean didLoadAnyUrl() {
|
| + return mDidLoadAnyUrl;
|
| + }
|
| +
|
| + @Override
|
| + public void updateTopControlState() {
|
| + 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);
|
| + }
|
| + }
|
|
|
| // ============================================================================================
|
| // Methods for managing this panel's ContentViewCore.
|
| @@ -567,42 +852,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.
|
| @@ -613,7 +870,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);
|
| }
|
|
|