Chromium Code Reviews| Index: chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelContent.java |
| diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelContent.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelContent.java |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..34d68e4ee4e5c5a5c844a5b9aeb5887c46b85606 |
| --- /dev/null |
| +++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelContent.java |
| @@ -0,0 +1,416 @@ |
| +// Copyright 2015 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.compositor.bottombar; |
| + |
| +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.externalnav.ExternalNavigationHandler; |
| +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; |
| + |
| +/** |
| + * Controls the Contextual Search Panel. |
| + */ |
| +public class OverlayPanelContent { |
| + |
| + /** |
| + * The ContentViewCore that this panel will display. |
| + */ |
| + private ContentViewCore mContentViewCore; |
| + |
| + /** |
| + * The pointer to the native version of this class. |
| + */ |
| + private long mNativeOverlayPanelContentPtr; |
| + |
| + /** |
| + * Used for progress bar events. |
| + */ |
| + private final WebContentsDelegateAndroid mWebContentsDelegate; |
| + |
| + /** |
| + * The activity that this content is contained in. |
| + */ |
| + private ChromeActivity mActivity; |
| + |
| + /** |
| + * Observer used for tracking loading and navigation. |
| + */ |
| + private WebContentsObserver mWebContentsObserver; |
| + |
| + /** |
| + * If the ContentViewCore has loaded a URL. |
| + */ |
| + private boolean mDidLoadAnyUrl; |
| + |
| + /** |
| + * If the content view is currently being displayed. |
| + */ |
| + private boolean mIsContentViewShowing; |
| + |
| + /** |
| + * The ContentViewCore responsible for displaying content. |
| + */ |
| + private ContentViewClient mContentViewClient; |
| + |
| + /** |
| + * The observer used by this object to inform inplementers of different events. |
| + */ |
| + private OverlayContentDelegate mOverlayObserver; |
| + |
| + /** |
| + * Used to observe progress bar events. |
| + */ |
| + private OverlayContentProgressObserver mProgressObserver; |
| + |
| + // http://crbug.com/522266 : An instance of InterceptNavigationDelegateImpl should be kept in |
| + // java layer. Otherwise, the instance could be garbage-collected unexpectedly. |
| + private InterceptNavigationDelegate mInterceptNavigationDelegate; |
| + |
| + // ============================================================================================ |
| + // 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) { |
| + // TODO(mdjones): Rather than passing the two navigation params, instead consider |
| + // passing a boolean to make this API simpler. |
| + return !mOverlayObserver.shouldInterceptNavigation(mExternalNavHandler, |
| + navigationParams); |
| + } |
| + } |
| + |
| + // ============================================================================================ |
| + // Constructor |
| + // ============================================================================================ |
| + |
| + /** |
| + * @param overlayObserver An observer for events that occur on this content. If null is passed |
| + * for this parameter, the default one will be used. |
| + * @param progresObserver An observer for progress related events. |
| + */ |
| + public OverlayPanelContent(OverlayContentDelegate overlayObserver, |
| + OverlayContentProgressObserver progressObserver) { |
| + nativeInit(); |
| + mOverlayObserver = overlayObserver; |
| + mProgressObserver = progressObserver; |
| + |
| + mWebContentsDelegate = new WebContentsDelegateAndroid() { |
| + @Override |
| + public void onLoadStarted() { |
| + super.onLoadStarted(); |
| + mProgressObserver.onProgressBarStarted(); |
| + } |
| + |
| + @Override |
| + public void onLoadStopped() { |
| + super.onLoadStopped(); |
| + mProgressObserver.onProgressBarFinished(); |
| + } |
| + |
| + @Override |
| + public void onLoadProgressChanged(int progress) { |
| + super.onLoadProgressChanged(progress); |
| + mProgressObserver.onProgressBarUpdated(progress); |
| + } |
| + }; |
| + } |
| + |
| + /** |
| + * Create a largely empty OverlayPanelContent for testing. |
| + */ |
| + @VisibleForTesting |
| + public OverlayPanelContent() { |
| + // NOTE: This constructor is intentionally sparse for testing. |
|
pedro (no code reviews)
2015/09/23 00:00:11
Nit: Include your ldap on NOTE comments, so that o
mdjones
2015/09/23 00:29:31
Done.
|
| + mWebContentsDelegate = null; |
| + } |
| + |
| + // ============================================================================================ |
| + // ContentViewCore related |
| + // ============================================================================================ |
| + |
| + /** |
| + * @param observer The OverlayContentDelegate to use. |
| + */ |
| + @VisibleForTesting |
| + public void setOverlayObserver(OverlayContentDelegate observer) { |
| + mOverlayObserver = observer; |
| + } |
| + |
| + /** |
| + * Create a new ContetnViewCore that will be managed by this panel. |
| + * TODO(mdjones): Make this private and create a new instance of this class per request. |
| + */ |
| + public void createNewContentView() { |
| + if (mContentViewCore != null) { |
|
pedro (no code reviews)
2015/09/23 00:00:11
Please incorporate my recent change to prevent the
|
| + destroyContentView(); |
| + } |
| + |
| + mContentViewCore = new ContentViewCore(mActivity); |
| + |
| + if (mContentViewClient == null) { |
| + mContentViewClient = new ContentViewClient(); |
| + } |
| + |
| + mContentViewCore.setContentViewClient(mContentViewClient); |
| + |
| + 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), mActivity.getWindowAndroid()); |
| + |
| + // Transfers the ownership of the WebContents to the native OverlayPanelContent. |
| + nativeSetWebContents(mNativeOverlayPanelContentPtr, mContentViewCore, |
| + mWebContentsDelegate); |
| + |
| + mWebContentsObserver = |
| + new WebContentsObserver(mContentViewCore.getWebContents()) { |
| + @Override |
| + public void didStartLoading(String url) { |
| + mOverlayObserver.onContentLoadStarted(url); |
| + } |
| + |
| + @Override |
| + public void didStartProvisionalLoadForFrame(long frameId, long parentFrameId, |
| + boolean isMainFrame, String validatedUrl, boolean isErrorPage, |
| + boolean isIframeSrcdoc) { |
| + if (isMainFrame) { |
| + mOverlayObserver.onMainFrameLoadStarted(validatedUrl); |
| + } |
| + } |
| + |
| + @Override |
| + public void didNavigateMainFrame(String url, String baseUrl, |
| + boolean isNavigationToDifferentPage, boolean isNavigationInPage, |
| + int httpResultCode) { |
| + // TODO(mdjones): Instead of tracking this, create a new instance of this |
| + // class per request. |
| + mDidLoadAnyUrl = false; |
| + mOverlayObserver.onMainFrameNavigation(url, |
| + isHttpFailureCode(httpResultCode)); |
| + } |
| + |
| + @Override |
| + public void didFinishLoad(long frameId, String validatedUrl, |
| + boolean isMainFrame) { |
| + mOverlayObserver.onContentLoadFinished(); |
| + } |
| + }; |
| + |
| + mInterceptNavigationDelegate = new InterceptNavigationDelegateImpl(); |
| + if (mInterceptNavigationDelegate != null) { |
| + nativeSetInterceptNavigationDelegate(mNativeOverlayPanelContentPtr, |
| + mInterceptNavigationDelegate, mContentViewCore.getWebContents()); |
| + } |
| + |
| + mOverlayObserver.onContentViewCreated(mContentViewCore); |
| + } |
| + |
| + /** |
| + * Destroy this panel's ContentViewCore. |
| + * TODO(mdjones): Make this private. |
| + */ |
| + public void destroyContentView() { |
| + if (mContentViewCore != null) { |
| + nativeDestroyWebContents(mNativeOverlayPanelContentPtr); |
| + mContentViewCore.getWebContents().destroy(); |
| + mContentViewCore.destroy(); |
| + mContentViewCore = null; |
| + if (mWebContentsObserver != null) { |
| + mWebContentsObserver.destroy(); |
| + mWebContentsObserver = null; |
| + } |
| + } |
| + |
| + setVisibility(false); |
|
pedro (no code reviews)
2015/09/23 00:00:11
Similarly, please incorporate my recent change to
|
| + |
| + mOverlayObserver.onContentViewDestroyed(); |
| + } |
| + |
| + /** |
| + * Load a URL, this will trigger creation of a new ContentViewCore. |
| + * @param url The URL that should be loaded. |
| + */ |
| + public void loadUrl(String url) { |
| + createNewContentView(); |
| + if (mContentViewCore != null && mContentViewCore.getWebContents() != null) { |
| + mDidLoadAnyUrl = true; |
| + mContentViewCore.getWebContents().getNavigationController().loadUrl( |
| + new LoadUrlParams(url)); |
| + } |
| + mContentViewCore.onShow(); |
| + } |
| + |
| + // ============================================================================================ |
| + // Utilities |
| + // ============================================================================================ |
| + |
| + /** |
| + * Calls updateTopControlsState on the ContentViewCore. |
| + * @param enableHiding Enable the toolbar's ability to hide. |
| + * @param enableShowing If the toolbar is allowed to show. |
| + * @param animate If the toolbar should animate when showing/hiding. |
| + */ |
| + public void updateTopControlsState(boolean enableHiding, boolean enableShowing, |
| + boolean animate) { |
| + if (mContentViewCore != null && mContentViewCore.getWebContents() != null) { |
| + mContentViewCore.getWebContents().updateTopControlsState(enableHiding, enableShowing, |
| + animate); |
| + } |
| + } |
| + |
| + /** |
| + * @return true if the panel loaded a URL. |
| + */ |
| + public boolean didLoadAnyUrl() { |
| + return mDidLoadAnyUrl; |
| + } |
| + |
| + /** |
| + * Reset the ContentViewCore's scroll position to (0, 0). |
| + */ |
| + public void resetContentViewScroll() { |
| + if (mContentViewCore != null) { |
| + mContentViewCore.scrollTo(0, 0); |
| + } |
| + } |
| + |
| + /** |
| + * @return The Y scroll position. |
| + */ |
| + public float getContentViewVerticalScroll() { |
| + return mContentViewCore != null |
| + ? mContentViewCore.computeVerticalScrollOffset() : -1.f; |
| + } |
| + |
| + /** |
| + * Sets the visibility of the Search Content View. |
| + * @param isVisible True to make it visible. |
| + */ |
| + public void setVisibility(boolean isVisible) { |
| + if (mIsContentViewShowing == isVisible) return; |
| + |
| + mIsContentViewShowing = 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) { |
| + createNewContentView(); |
| + } |
| + if (mContentViewCore != null) mContentViewCore.onShow(); |
| + mOverlayObserver.onContentViewSeen(); |
| + } else { |
| + if (mContentViewCore != null) mContentViewCore.onHide(); |
| + destroyContentView(); |
| + } |
| + |
| + mOverlayObserver.onVisibilityChanged(isVisible); |
| + } |
| + |
| + /** |
| + * @return Whether the given HTTP result code represents a failure or not. |
| + */ |
| + private boolean isHttpFailureCode(int httpResultCode) { |
| + return httpResultCode <= 0 || httpResultCode >= 400; |
| + } |
| + |
| + /** |
| + * Set a ContentViewClient for this panel to use (will be reused for each new ContentViewCore). |
| + * @param viewClient The ContentViewClient to use. |
| + */ |
| + public void setContentViewClient(ContentViewClient viewClient) { |
| + mContentViewClient = viewClient; |
| + } |
| + |
| + /** |
| + * @return true if the ContentViewCore is visible on the page. |
| + */ |
| + public boolean isContentViewShowing() { |
| + return mIsContentViewShowing; |
| + } |
| + |
| + /** |
| + * @param activity The ChromeActivity that this panel lives in. |
| + */ |
| + public void setChromeActivity(ChromeActivity activity) { |
| + mActivity = activity; |
| + } |
| + |
| + // ============================================================================================ |
| + // Methods for managing this panel's ContentViewCore. |
| + // ============================================================================================ |
| + |
| + /** |
| + * Reset this object's native pointer to 0; |
| + */ |
| + @CalledByNative |
| + public void clearNativePanelContentPtr() { |
| + assert mNativeOverlayPanelContentPtr != 0; |
| + mNativeOverlayPanelContentPtr = 0; |
| + } |
| + |
| + /** |
| + * Set this object's native poiner. |
| + * @param nativePtr The pointer to the native component of this class. |
| + */ |
| + @CalledByNative |
| + public void setNativePanelContentPtr(long nativePtr) { |
| + assert mNativeOverlayPanelContentPtr == 0; |
| + mNativeOverlayPanelContentPtr = nativePtr; |
| + } |
| + |
| + /** |
| + * @return This panel's ContentViewCore. |
| + */ |
| + @VisibleForTesting |
| + public ContentViewCore getContentViewCore() { |
| + return mContentViewCore; |
| + } |
| + |
| + /** |
| + * Remove the list history entry from this panel if it was within a certain timeframe. |
| + * @param historyUrl The URL to remove. |
| + * @param urlTimeMS The time the URL was navigated to. |
| + */ |
| + public void removeLastHistoryEntry(String historyUrl, long urlTimeMs) { |
| + nativeRemoveLastHistoryEntry(mNativeOverlayPanelContentPtr, historyUrl, urlTimeMs); |
| + } |
| + |
| + /** |
| + * Destroy the native component of this class. |
| + */ |
| + @VisibleForTesting |
| + public void destroy() { |
| + destroyContentView(); |
| + nativeDestroy(mNativeOverlayPanelContentPtr); |
| + } |
| + |
| + // Native calls. |
| + private native long nativeInit(); |
| + private native void nativeDestroy(long nativeOverlayPanelContent); |
| + private native void nativeRemoveLastHistoryEntry( |
| + long nativeOverlayPanelContent, String historyUrl, long urlTimeMs); |
| + private native void nativeSetWebContents(long nativeOverlayPanelContent, |
| + ContentViewCore contentViewCore, WebContentsDelegateAndroid delegate); |
| + private native void nativeDestroyWebContents(long nativeOverlayPanelContent); |
| + private native void nativeSetInterceptNavigationDelegate(long nativeOverlayPanelContent, |
| + InterceptNavigationDelegate delegate, WebContents webContents); |
| +} |