Index: content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsObserverProxy.java |
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 0000000000000000000000000000000000000000..fdae8f3a3afe3a0c9de2649107d28757a127c843 |
--- /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); |
+} |