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..56eac35de6d6dc6b4a6ba738a344ce52c311120b 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) { |
+ 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. |
@@ -252,6 +340,22 @@ public class ContextualSearchPanel extends ContextualSearchPanelAnimation |
} |
} |
+ @Override |
+ public void updateTopControlState() { |
pedro (no code reviews)
2015/09/02 22:59:25
Move this to the delegate section below.
mdjones
2015/09/03 17:07:32
Done.
|
+ 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); |
+ } |
+ } |
+ |
// ============================================================================================ |
// Gesture Event helpers |
// ============================================================================================ |
@@ -368,6 +472,176 @@ public class ContextualSearchPanel extends ContextualSearchPanelAnimation |
} |
// ============================================================================================ |
+ // ContextualSearchContentController |
+ // ============================================================================================ |
+ |
+ @Override |
+ public void createNewContentView() { |
+ // TODO(mdjones): This should not be a public API. |
+ 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) { |
+ 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); |
+ |
+ return getManagementDelegate().shouldIgnoreNavigation(mExternalNavHandler, |
pedro (no code reviews)
2015/09/02 22:59:26
Add a TODO to consider passing a boolean instead r
mdjones
2015/09/03 17:07:32
Done.
|
+ navigationParams); |
+ } |
+ } |
+ |
+ // ============================================================================================ |
// Panel Delegate |
// ============================================================================================ |
@@ -454,32 +728,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 +739,6 @@ public class ContextualSearchPanel extends ContextualSearchPanelAnimation |
super.setDidSearchInvolvePromo(); |
} |
- @Override |
public void setWasSearchContentViewSeen() { |
// NOTE(pedrosimonetti): exposing superclass method to the interface. |
super.setWasSearchContentViewSeen(); |
@@ -525,6 +772,43 @@ 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; |
+ } |
+ |
+ @Override |
+ public boolean didLoadAnyUrl() { |
+ return mDidLoadAnyUrl; |
+ } |
+ |
// ============================================================================================ |
// Methods for managing this panel's ContentViewCore. |
// ============================================================================================ |
@@ -546,42 +830,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 +848,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); |
} |