diff options
author | jdduke <jdduke@chromium.org> | 2015-03-04 11:38:54 -0800 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-03-04 19:39:22 +0000 |
commit | c747fed0edbe60e29c6810314021210687577cd6 (patch) | |
tree | 489e117c84afd67663d82014cde6a4596b93ac57 /content/public/android/java | |
parent | 5444415569f96d9e8c7a6224069560515f49aa91 (diff) | |
download | chromium_src-c747fed0edbe60e29c6810314021210687577cd6.zip chromium_src-c747fed0edbe60e29c6810314021210687577cd6.tar.gz chromium_src-c747fed0edbe60e29c6810314021210687577cd6.tar.bz2 |
[Android] Add proxy for Java-based WebContentsObservers
A good portion of the current WebContentsObserver instances for any
given tab are Java-based. Each of these require separate JNI hops, as
well as repeated string conversions, for each observer callback. Avoid
such costs by having just one Java-based WebContentsObserverProxy that
bridges from native and allows multiple Java-based WebContentsObserver
subscribers.
BUG=440134
Review URL: https://codereview.chromium.org/786933005
Cr-Commit-Position: refs/heads/master@{#319100}
Diffstat (limited to 'content/public/android/java')
-rw-r--r-- | content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java | 126 | ||||
-rw-r--r-- | content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsImpl.java | 25 | ||||
-rw-r--r-- | content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsObserverProxy.java | 236 | ||||
-rw-r--r-- | content/public/android/java/src/org/chromium/content_public/browser/WebContents.java | 14 | ||||
-rw-r--r-- | content/public/android/java/src/org/chromium/content_public/browser/WebContentsObserver.java (renamed from content/public/android/java/src/org/chromium/content/browser/WebContentsObserver.java) | 115 |
5 files changed, 386 insertions, 130 deletions
diff --git a/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java b/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java index 00ea68a..d98bad3 100644 --- a/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java +++ b/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java @@ -77,6 +77,7 @@ import org.chromium.content.browser.input.SelectPopupItem; import org.chromium.content.common.ContentSwitches; import org.chromium.content_public.browser.GestureStateListener; import org.chromium.content_public.browser.WebContents; +import org.chromium.content_public.browser.WebContentsObserver; import org.chromium.ui.base.DeviceFormFactor; import org.chromium.ui.base.ViewAndroid; import org.chromium.ui.base.ViewAndroidDelegate; @@ -86,6 +87,7 @@ import org.chromium.ui.gfx.DeviceDisplayInfo; import org.chromium.ui.touch_selection.SelectionEventType; import java.lang.annotation.Annotation; +import java.lang.ref.WeakReference; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.HashMap; @@ -278,6 +280,77 @@ public class ContentViewCore } /** + * A {@link WebContentsObserver} that listens to frame navigation events. + */ + private static class ContentViewWebContentsObserver extends WebContentsObserver { + // Using a weak reference avoids cycles that might prevent GC of WebView's WebContents. + private final WeakReference<ContentViewCore> mWeakContentViewCore; + + ContentViewWebContentsObserver(ContentViewCore contentViewCore) { + super(contentViewCore.getWebContents()); + mWeakContentViewCore = new WeakReference<ContentViewCore>(contentViewCore); + } + + @Override + public void didStartLoading(String url) { + ContentViewCore contentViewCore = mWeakContentViewCore.get(); + if (contentViewCore == null) return; + contentViewCore.mAccessibilityInjector.onPageLoadStarted(); + } + + @Override + public void didStopLoading(String url) { + ContentViewCore contentViewCore = mWeakContentViewCore.get(); + if (contentViewCore == null) return; + contentViewCore.mAccessibilityInjector.onPageLoadStopped(); + } + + @Override + public void didFailLoad(boolean isProvisionalLoad, boolean isMainFrame, int errorCode, + String description, String failingUrl) { + // Navigation that fails the provisional load will have the strong binding removed + // here. One for which the provisional load is commited will have the strong binding + // removed in navigationEntryCommitted() below. + if (isProvisionalLoad) determinedProcessVisibility(); + } + + @Override + public void didNavigateMainFrame(String url, String baseUrl, + boolean isNavigationToDifferentPage, boolean isFragmentNavigation) { + if (!isNavigationToDifferentPage) return; + resetPopupsAndInput(); + } + + @Override + public void renderProcessGone(boolean wasOomProtected) { + resetPopupsAndInput(); + } + + @Override + public void navigationEntryCommitted() { + determinedProcessVisibility(); + } + + private void resetPopupsAndInput() { + ContentViewCore contentViewCore = mWeakContentViewCore.get(); + if (contentViewCore == null) return; + contentViewCore.mIsMobileOptimizedHint = false; + contentViewCore.hidePopupsAndClearSelection(); + contentViewCore.resetScrollInProgress(); + } + + private void determinedProcessVisibility() { + ContentViewCore contentViewCore = mWeakContentViewCore.get(); + if (contentViewCore == null) return; + // Signal to the process management logic that we can now rely on the process + // visibility signal for binding management. Before the navigation commits, its + // renderer is considered background even if the pending navigation happens in the + // foreground renderer. + ChildProcessLauncher.determinedVisibility(contentViewCore.getCurrentRenderProcessId()); + } + } + + /** * Interface that consumers of {@link ContentViewCore} must implement to allow the proper * dispatching of view methods through the containing view. * @@ -747,56 +820,7 @@ public class ContentViewCore mAccessibilityInjector = AccessibilityInjector.newInstance(this); - mWebContentsObserver = new WebContentsObserver(mWebContents) { - @Override - public void didStartLoading(String url) { - mAccessibilityInjector.onPageLoadStarted(); - } - - @Override - public void didStopLoading(String url) { - mAccessibilityInjector.onPageLoadStopped(); - } - - @Override - public void didFailLoad(boolean isProvisionalLoad, boolean isMainFrame, int errorCode, - String description, String failingUrl) { - // Navigation that fails the provisional load will have the strong binding removed - // here. One for which the provisional load is commited will have the strong binding - // removed in navigationEntryCommitted() below. - if (isProvisionalLoad) determinedProcessVisibility(); - } - - @Override - public void didNavigateMainFrame(String url, String baseUrl, - boolean isNavigationToDifferentPage, boolean isFragmentNavigation) { - if (!isNavigationToDifferentPage) return; - mIsMobileOptimizedHint = false; - hidePopupsAndClearSelection(); - resetScrollInProgress(); - } - - @Override - public void renderProcessGone(boolean wasOomProtected) { - hidePopupsAndClearSelection(); - resetScrollInProgress(); - // No need to reset gesture detection as the detector will have - // been destroyed in the RenderWidgetHostView. - } - - @Override - public void navigationEntryCommitted() { - determinedProcessVisibility(); - } - - private void determinedProcessVisibility() { - // Signal to the process management logic that we can now rely on the process - // visibility signal for binding management. Before the navigation commits, its - // renderer is considered background even if the pending navigation happens in the - // foreground renderer. - ChildProcessLauncher.determinedVisibility(getCurrentRenderProcessId()); - } - }; + mWebContentsObserver = new ContentViewWebContentsObserver(this); } @VisibleForTesting @@ -946,7 +970,7 @@ public class ContentViewCore if (mNativeContentViewCore != 0) { nativeOnJavaContentViewCoreDestroyed(mNativeContentViewCore); } - mWebContentsObserver.detachFromWebContents(); + mWebContentsObserver.destroy(); mWebContentsObserver = null; setSmartClipDataListener(null); setZoomControlsDelegate(null); diff --git a/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsImpl.java b/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsImpl.java index 049e5af..f7a82e6 100644 --- a/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsImpl.java +++ b/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsImpl.java @@ -10,6 +10,7 @@ import org.chromium.content_public.browser.JavaScriptCallback; import org.chromium.content_public.browser.NavigationController; import org.chromium.content_public.browser.NavigationTransitionDelegate; import org.chromium.content_public.browser.WebContents; +import org.chromium.content_public.browser.WebContentsObserver; /** * The WebContentsImpl Java wrapper to allow communicating with the native WebContentsImpl @@ -23,6 +24,9 @@ import org.chromium.content_public.browser.WebContents; private long mNativeWebContentsAndroid; private NavigationController mNavigationController; + // Lazily created proxy observer for handling all Java-based WebContentsObservers. + private WebContentsObserverProxy mObserverProxy; + private NavigationTransitionDelegate mNavigationTransitionDelegate = null; private WebContentsImpl( @@ -41,6 +45,10 @@ import org.chromium.content_public.browser.WebContents; private void clearNativePtr() { mNativeWebContentsAndroid = 0; mNavigationController = null; + if (mObserverProxy != null) { + mObserverProxy.destroy(); + mObserverProxy = null; + } } @CalledByNative @@ -312,6 +320,23 @@ import org.chromium.content_public.browser.WebContents; callback.handleJavaScriptResult(jsonResult); } + @Override + public void addObserver(WebContentsObserver observer) { + assert mNativeWebContentsAndroid != 0; + if (mObserverProxy == null) mObserverProxy = new WebContentsObserverProxy(this); + mObserverProxy.addObserver(observer); + } + + @Override + public void removeObserver(WebContentsObserver observer) { + if (mObserverProxy == null) return; + mObserverProxy.removeObserver(observer); + if (!mObserverProxy.hasObservers()) { + mObserverProxy.destroy(); + mObserverProxy = null; + } + } + // This is static to avoid exposing a public destroy method on the native side of this class. private static native void nativeDestroyWebContents(long webContentsAndroidPtr); diff --git a/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsObserverProxy.java b/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsObserverProxy.java new file mode 100644 index 0000000..fdae8f3a --- /dev/null +++ b/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsObserverProxy.java @@ -0,0 +1,236 @@ +// 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.content.browser.webcontents; + +import org.chromium.base.CalledByNative; +import org.chromium.base.JNINamespace; +import org.chromium.base.ObserverList; +import org.chromium.base.ObserverList.RewindableIterator; +import org.chromium.base.ThreadUtils; +import org.chromium.content_public.browser.WebContentsObserver; + +/** + * Serves as a compound observer proxy for dispatching WebContentsObserver callbacks, + * avoiding redundant JNI-related work when there are multiple Java-based observers. + */ +@JNINamespace("content") +class WebContentsObserverProxy extends WebContentsObserver { + private long mNativeWebContentsObserverProxy; + private final ObserverList<WebContentsObserver> mObservers; + private final RewindableIterator<WebContentsObserver> mObserversIterator; + + /** + * Constructs a new WebContentsObserverProxy for a given WebContents + * instance. A native WebContentsObserver instance will be created, which + * will observe the native counterpart to the provided WebContents. + * + * @param webContents The WebContents instance to observe. + */ + public WebContentsObserverProxy(WebContentsImpl webContents) { + ThreadUtils.assertOnUiThread(); + mNativeWebContentsObserverProxy = nativeInit(webContents); + mObservers = new ObserverList<WebContentsObserver>(); + mObserversIterator = mObservers.rewindableIterator(); + } + + /** + * Add an observer to the list of proxied observers. + * @param observer The WebContentsObserver instance to add. + */ + void addObserver(WebContentsObserver observer) { + assert mNativeWebContentsObserverProxy != 0; + mObservers.addObserver(observer); + } + + /** + * Remove an observer from the list of proxied observers. + * @param observer The WebContentsObserver instance to remove. + */ + void removeObserver(WebContentsObserver observer) { + mObservers.removeObserver(observer); + } + + /** + * @return Whether there are any active, proxied observers. + */ + boolean hasObservers() { + return !mObservers.isEmpty(); + } + + @Override + @CalledByNative + public void renderViewReady() { + for (mObserversIterator.rewind(); mObserversIterator.hasNext();) { + mObserversIterator.next().renderViewReady(); + } + } + + @Override + @CalledByNative + public void renderProcessGone(boolean wasOomProtected) { + for (mObserversIterator.rewind(); mObserversIterator.hasNext();) { + mObserversIterator.next().renderProcessGone(wasOomProtected); + } + } + + @Override + @CalledByNative + public void didStartLoading(String url) { + for (mObserversIterator.rewind(); mObserversIterator.hasNext();) { + mObserversIterator.next().didStartLoading(url); + } + } + + @Override + @CalledByNative + public void didStopLoading(String url) { + for (mObserversIterator.rewind(); mObserversIterator.hasNext();) { + mObserversIterator.next().didStopLoading(url); + } + } + + @Override + @CalledByNative + public void didFailLoad(boolean isProvisionalLoad, boolean isMainFrame, int errorCode, + String description, String failingUrl) { + for (mObserversIterator.rewind(); mObserversIterator.hasNext();) { + mObserversIterator.next().didFailLoad( + isProvisionalLoad, isMainFrame, errorCode, description, failingUrl); + } + } + + @Override + public void didNavigateMainFrame(String url, String baseUrl, + boolean isNavigationToDifferentPage, boolean isFragmentNavigation) { + for (mObserversIterator.rewind(); mObserversIterator.hasNext();) { + mObserversIterator.next().didNavigateMainFrame( + url, baseUrl, isNavigationToDifferentPage, isFragmentNavigation); + } + } + + @Override + @CalledByNative + public void didNavigateMainFrame(String url, String baseUrl, + boolean isNavigationToDifferentPage, boolean isFragmentNavigation, int statusCode) { + didNavigateMainFrame(url, baseUrl, isNavigationToDifferentPage, isFragmentNavigation); + } + + @Override + @CalledByNative + public void didFirstVisuallyNonEmptyPaint() { + for (mObserversIterator.rewind(); mObserversIterator.hasNext();) { + mObserversIterator.next().didFirstVisuallyNonEmptyPaint(); + } + } + + @Override + @CalledByNative + public void didNavigateAnyFrame(String url, String baseUrl, boolean isReload) { + for (mObserversIterator.rewind(); mObserversIterator.hasNext();) { + mObserversIterator.next().didNavigateAnyFrame(url, baseUrl, isReload); + } + } + + @Override + @CalledByNative + public void documentAvailableInMainFrame() { + for (mObserversIterator.rewind(); mObserversIterator.hasNext();) { + mObserversIterator.next().documentAvailableInMainFrame(); + } + } + + @Override + @CalledByNative + public void didStartProvisionalLoadForFrame(long frameId, long parentFrameId, + boolean isMainFrame, String validatedUrl, boolean isErrorPage, boolean isIframeSrcdoc) { + for (mObserversIterator.rewind(); mObserversIterator.hasNext();) { + mObserversIterator.next().didStartProvisionalLoadForFrame( + frameId, parentFrameId, isMainFrame, validatedUrl, isErrorPage, isIframeSrcdoc); + } + } + + @Override + @CalledByNative + public void didCommitProvisionalLoadForFrame( + long frameId, boolean isMainFrame, String url, int transitionType) { + for (mObserversIterator.rewind(); mObserversIterator.hasNext();) { + mObserversIterator.next().didCommitProvisionalLoadForFrame( + frameId, isMainFrame, url, transitionType); + } + } + + @Override + @CalledByNative + public void didFinishLoad(long frameId, String validatedUrl, boolean isMainFrame) { + for (mObserversIterator.rewind(); mObserversIterator.hasNext();) { + mObserversIterator.next().didFinishLoad(frameId, validatedUrl, isMainFrame); + } + } + + @Override + @CalledByNative + public void documentLoadedInFrame(long frameId) { + for (mObserversIterator.rewind(); mObserversIterator.hasNext();) { + mObserversIterator.next().documentLoadedInFrame(frameId); + } + } + + @Override + @CalledByNative + public void navigationEntryCommitted() { + for (mObserversIterator.rewind(); mObserversIterator.hasNext();) { + mObserversIterator.next().navigationEntryCommitted(); + } + } + + @Override + @CalledByNative + public void didAttachInterstitialPage() { + for (mObserversIterator.rewind(); mObserversIterator.hasNext();) { + mObserversIterator.next().didAttachInterstitialPage(); + } + } + + @Override + @CalledByNative + public void didDetachInterstitialPage() { + for (mObserversIterator.rewind(); mObserversIterator.hasNext();) { + mObserversIterator.next().didDetachInterstitialPage(); + } + } + + @Override + @CalledByNative + public void didChangeThemeColor(int color) { + for (mObserversIterator.rewind(); mObserversIterator.hasNext();) { + mObserversIterator.next().didChangeThemeColor(color); + } + } + + @Override + @CalledByNative + public void didStartNavigationToPendingEntry(String url) { + for (mObserversIterator.rewind(); mObserversIterator.hasNext();) { + mObserversIterator.next().didStartNavigationToPendingEntry(url); + } + } + + @Override + @CalledByNative + public void destroy() { + // Super destruction semantics (removing the observer from the + // Java-based WebContents) are quite different, so we explicitly avoid + // calling it here. + ThreadUtils.assertOnUiThread(); + mObservers.clear(); + if (mNativeWebContentsObserverProxy != 0) { + nativeDestroy(mNativeWebContentsObserverProxy); + mNativeWebContentsObserverProxy = 0; + } + } + + private native long nativeInit(WebContentsImpl webContents); + private native void nativeDestroy(long nativeWebContentsObserverProxy); +} diff --git a/content/public/android/java/src/org/chromium/content_public/browser/WebContents.java b/content/public/android/java/src/org/chromium/content_public/browser/WebContents.java index 19b00b2..06bf7ae 100644 --- a/content/public/android/java/src/org/chromium/content_public/browser/WebContents.java +++ b/content/public/android/java/src/org/chromium/content_public/browser/WebContents.java @@ -229,4 +229,18 @@ public interface WebContents { * @return Whether the initial empty page has been accessed by a script. */ public boolean hasAccessedInitialDocument(); + + /** + * Add an observer to the WebContents + * + * @param observer The observer to add. + */ + void addObserver(WebContentsObserver observer); + + /** + * Remove an observer from the WebContents + * + * @param observer The observer to remove. + */ + void removeObserver(WebContentsObserver observer); } diff --git a/content/public/android/java/src/org/chromium/content/browser/WebContentsObserver.java b/content/public/android/java/src/org/chromium/content_public/browser/WebContentsObserver.java index f1bf6a2..3d239db 100644 --- a/content/public/android/java/src/org/chromium/content/browser/WebContentsObserver.java +++ b/content/public/android/java/src/org/chromium/content_public/browser/WebContentsObserver.java @@ -2,53 +2,44 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -package org.chromium.content.browser; +package org.chromium.content_public.browser; -import org.chromium.base.CalledByNative; -import org.chromium.base.JNINamespace; -import org.chromium.base.ThreadUtils; -import org.chromium.content_public.browser.WebContents; +import java.lang.ref.WeakReference; /** * This class receives callbacks that act as hooks for various a native web contents events related * to loading a url. A single web contents can have multiple WebContentObservers. */ -@JNINamespace("content") public abstract class WebContentsObserver { - private long mNativeWebContentsObserverAndroid; + // TODO(jdduke): Remove the destroy method and hold observer embedders + // responsible for explicit observer detachment. + // Using a weak reference avoids cycles that might prevent GC of WebView's WebContents. + private WeakReference<WebContents> mWebContents; public WebContentsObserver(WebContents webContents) { - ThreadUtils.assertOnUiThread(); - mNativeWebContentsObserverAndroid = nativeInit(webContents); + mWebContents = new WeakReference<WebContents>(webContents); + webContents.addObserver(this); } /** * Called when the RenderView of the current RenderViewHost is ready, e.g. because we recreated * it after a crash. */ - @CalledByNative - public void renderViewReady() { - } + public void renderViewReady() {} - @CalledByNative - public void renderProcessGone(boolean wasOomProtected) { - } + public void renderProcessGone(boolean wasOomProtected) {} /** * Called when the a page starts loading. * @param url The validated url for the loading page. */ - @CalledByNative - public void didStartLoading(String url) { - } + public void didStartLoading(String url) {} /** * Called when the a page finishes loading. * @param url The validated url for the page. */ - @CalledByNative - public void didStopLoading(String url) { - } + public void didStopLoading(String url) {} /** * Called when an error occurs while loading a page and/or the page fails to load. @@ -56,10 +47,8 @@ public abstract class WebContentsObserver { * @param description The description for the error. * @param failingUrl The url that was loading when the error occurred. */ - @CalledByNative - public void didFailLoad(boolean isProvisionalLoad, - boolean isMainFrame, int errorCode, String description, String failingUrl) { - } + public void didFailLoad(boolean isProvisionalLoad, boolean isMainFrame, int errorCode, + String description, String failingUrl) {} /** * Called when the main frame of the page has committed. @@ -71,8 +60,7 @@ public abstract class WebContentsObserver { * document (for example scrolling to a named anchor or PopState). */ public void didNavigateMainFrame(String url, String baseUrl, - boolean isNavigationToDifferentPage, boolean isFragmentNavigation) { - } + boolean isNavigationToDifferentPage, boolean isFragmentNavigation) {} /** * Called when the main frame of the page has committed. @@ -83,7 +71,6 @@ public abstract class WebContentsObserver { * document (for example scrolling to a named anchor or PopState). * @param statusCode The HTTP status code of the navigation. */ - @CalledByNative public void didNavigateMainFrame(String url, String baseUrl, boolean isNavigationToDifferentPage, boolean isFragmentNavigation, int statusCode) { didNavigateMainFrame(url, baseUrl, isNavigationToDifferentPage, isFragmentNavigation); @@ -92,9 +79,7 @@ public abstract class WebContentsObserver { /** * Called when the page had painted something non-empty. */ - @CalledByNative - public void didFirstVisuallyNonEmptyPaint() { - } + public void didFirstVisuallyNonEmptyPaint() {} /** * Similar to didNavigateMainFrame but also called on subframe navigations. @@ -102,16 +87,12 @@ public abstract class WebContentsObserver { * @param baseUrl The validated base url for the page. * @param isReload True if this navigation is a reload. */ - @CalledByNative - public void didNavigateAnyFrame(String url, String baseUrl, boolean isReload) { - } + public void didNavigateAnyFrame(String url, String baseUrl, boolean isReload) {} /** * Called once the window.document object of the main frame was created. */ - @CalledByNative - public void documentAvailableInMainFrame() { - } + public void documentAvailableInMainFrame() {} /** * Notifies that a load is started for a given frame. @@ -123,14 +104,8 @@ public abstract class WebContentsObserver { * @param isErrorPage Whether this is navigating to an error page. * @param isIframeSrcdoc Whether this is navigating to about:srcdoc. */ - @CalledByNative - public void didStartProvisionalLoadForFrame( - long frameId, - long parentFrameId, - boolean isMainFrame, - String validatedUrl, - boolean isErrorPage, - boolean isIframeSrcdoc) { + public void didStartProvisionalLoadForFrame(long frameId, long parentFrameId, + boolean isMainFrame, String validatedUrl, boolean isErrorPage, boolean isIframeSrcdoc) { } /** @@ -142,11 +117,8 @@ public abstract class WebContentsObserver { * @param transitionType The transition type as defined in * {@link org.chromium.ui.base.PageTransition} for the load. */ - @CalledByNative public void didCommitProvisionalLoadForFrame( - long frameId, boolean isMainFrame, String url, int transitionType) { - - } + long frameId, boolean isMainFrame, String url, int transitionType) {} /** * Notifies that a load has finished for a given frame. @@ -154,66 +126,51 @@ public abstract class WebContentsObserver { * @param validatedUrl The validated URL that is being navigated to. * @param isMainFrame Whether the load is happening for the main frame. */ - @CalledByNative - public void didFinishLoad(long frameId, String validatedUrl, boolean isMainFrame) { - } + public void didFinishLoad(long frameId, String validatedUrl, boolean isMainFrame) {} /** * Notifies that the document has finished loading for the given frame. * @param frameId A positive, non-zero integer identifying the navigating frame. */ - @CalledByNative - public void documentLoadedInFrame(long frameId) { - } + public void documentLoadedInFrame(long frameId) {} /** * Notifies that a navigation entry has been committed. */ - @CalledByNative - public void navigationEntryCommitted() { - } + public void navigationEntryCommitted() {} /** * Called when an interstitial page gets attached to the tab content. */ - @CalledByNative - public void didAttachInterstitialPage() { - } + public void didAttachInterstitialPage() {} /** * Called when an interstitial page gets detached from the tab content. */ - @CalledByNative - public void didDetachInterstitialPage() { - } + public void didDetachInterstitialPage() {} /** * Called when the theme color was changed. * @param color the new color in ARGB format */ - @CalledByNative - public void didChangeThemeColor(int color) { - } + public void didChangeThemeColor(int color) {} /** * Called when we started navigation to the pending entry. * @param url The URL that we are navigating to. */ - @CalledByNative - public void didStartNavigationToPendingEntry(String url) { - } + public void didStartNavigationToPendingEntry(String url) {} /** - * Destroy the corresponding native object. + * Stop observing the web contents and clean up associated references. */ - @CalledByNative - public void detachFromWebContents() { - if (mNativeWebContentsObserverAndroid != 0) { - nativeDestroy(mNativeWebContentsObserverAndroid); - mNativeWebContentsObserverAndroid = 0; - } + public void destroy() { + if (mWebContents == null) return; + final WebContents webContents = mWebContents.get(); + mWebContents = null; + if (webContents == null) return; + webContents.removeObserver(this); } - private native long nativeInit(WebContents webContents); - private native void nativeDestroy(long nativeWebContentsObserverAndroid); + protected WebContentsObserver() {} } |