Commit 72306e5c authored by John Abd-El-Malek's avatar John Abd-El-Malek Committed by Commit Bot

Plumb first contentful paint notification to WebLayer Java API.

This is needed for embedders to calculate metrics.

Change-Id: Id804dab8eea8e55eebdde52f0aa44157e9a7be5f
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1869339
Commit-Queue: John Abd-El-Malek <jam@chromium.org>
Reviewed-by: default avatarScott Violet <sky@chromium.org>
Cr-Commit-Position: refs/heads/master@{#707938}
parent 94e76f4e
......@@ -238,11 +238,6 @@ blink::mojom::DisplayMode BrowserControllerImpl::GetDisplayMode(
: blink::mojom::DisplayMode::kBrowser;
}
void BrowserControllerImpl::DidFirstVisuallyNonEmptyPaint() {
for (auto& observer : observers_)
observer.FirstContentfulPaint();
}
void BrowserControllerImpl::DidFinishNavigation(
content::NavigationHandle* navigation_handle) {
#if defined(OS_ANDROID)
......
......@@ -95,7 +95,6 @@ class BrowserControllerImpl : public BrowserController,
const content::WebContents* web_contents) override;
// content::WebContentsObserver:
void DidFirstVisuallyNonEmptyPaint() override;
void DidFinishNavigation(
content::NavigationHandle* navigation_handle) override;
......
......@@ -46,8 +46,6 @@ void BrowserObserverProxy::LoadProgressChanged(double progress) {
Java_BrowserObserverProxy_loadProgressChanged(env, java_observer_, progress);
}
void BrowserObserverProxy::FirstContentfulPaint() {}
static jlong JNI_BrowserObserverProxy_CreateBrowserObserverProxy(
JNIEnv* env,
const base::android::JavaParamRef<jobject>& proxy,
......
......@@ -29,7 +29,6 @@ class BrowserObserverProxy : public BrowserObserver {
void LoadingStateChanged(bool is_loading,
bool to_different_document) override;
void LoadProgressChanged(double progress) override;
void FirstContentfulPaint() override;
private:
BrowserController* browser_controller_;
......
......@@ -142,6 +142,15 @@ public final class NavigationControllerImpl extends INavigationController.Stub {
}
}
@CalledByNative
private void onFirstContentfulPaint() {
try {
mNavigationControllerClient.onFirstContentfulPaint();
} catch (RemoteException e) {
throw new APICallException(e);
}
}
@NativeMethods
interface Natives {
void setNavigationControllerImpl(
......
......@@ -20,4 +20,6 @@ interface INavigationControllerClient {
void navigationCompleted(IClientNavigation navigation) = 4;
void navigationFailed(IClientNavigation navigation) = 5;
void onFirstContentfulPaint() = 6;
}
......@@ -206,6 +206,16 @@ void NavigationControllerImpl::DidFinishNavigation(
navigation_map_.erase(navigation_map_.find(navigation_handle));
}
void NavigationControllerImpl::DidFirstVisuallyNonEmptyPaint() {
#if defined(OS_ANDROID)
Java_NavigationControllerImpl_onFirstContentfulPaint(AttachCurrentThread(),
java_controller_);
#endif
for (auto& observer : observers_)
observer.OnFirstContentfulPaint();
}
#if defined(OS_ANDROID)
static jlong JNI_NavigationControllerImpl_GetNavigationController(
JNIEnv* env,
......
......@@ -91,6 +91,7 @@ class NavigationControllerImpl : public NavigationController,
content::NavigationHandle* navigation_handle) override;
void DidFinishNavigation(
content::NavigationHandle* navigation_handle) override;
void DidFirstVisuallyNonEmptyPaint() override;
BrowserControllerImpl* browser_controller_;
base::ObserverList<NavigationObserver>::Unchecked observers_;
......
......@@ -27,10 +27,6 @@ class BrowserObserver {
// corresponds to WebContentsDelegate::LoadProgressChanged, meaning |progress|
// ranges from 0.0 to 1.0.
virtual void LoadProgressChanged(double progress) {}
// This is fired after each navigation has completed, to indicate that the
// first paint after a non-empty layout has finished.
virtual void FirstContentfulPaint() {}
};
} // namespace weblayer
......
......@@ -165,5 +165,12 @@ public final class NavigationController {
observer.navigationFailed((Navigation) navigation);
}
}
@Override
public void onFirstContentfulPaint() {
for (NavigationObserver observer : mObservers) {
observer.onFirstContentfulPaint();
}
}
}
}
......@@ -13,15 +13,85 @@ package org.chromium.weblayer;
* 2) 0 or more navigationRedirected()
* 3) 0 or 1 navigationCommitted()
* 4) navigationCompleted() or navigationFailed()
* 5) onFirstContentfulPaint
*/
public abstract class NavigationObserver {
/**
* Called when a navigation started in the BrowserController. |navigation| is unique to a
* specific navigation. The same |navigation| will be provided on subsequent calls to
* NavigationRedirected, NavigationCommitted, NavigationCompleted and NavigationFailed when
* related to this navigation. Observers should clear any references to |navigation| in
* NavigationCompleted or NavigationFailed, just before it is destroyed.
*
* Note that this is only fired by navigations in the main frame.
*
* Note that this is fired by same-document navigations, such as fragment navigations or
* pushState/replaceState, which will not result in a document change. To filter these out, use
* Navigation::IsSameDocument.
*
* Note that more than one navigation can be ongoing in the BrowserController at the same time.
* Each will get its own Navigation object.
*
* Note that there is no guarantee that NavigationCompleted/NavigationFailed will be called for
* any particular navigation before NavigationStarted is called on the next.
*
* @param navigation the unique object for this navigation.
*/
public void navigationStarted(Navigation navigation) {}
/**
* Called when a navigation encountered a server redirect.
*
* @param navigation the unique object for this navigation.
*/
public void navigationRedirected(Navigation navigation) {}
/**
* Called when the navigation is ready to be committed in a renderer. A navigation is considered
* committed when the response code isn't 204/205 (which tell the browser that the request is
* successful but there's no content that follows) or a download (either from a response header
* or based on mime sniffing the response). The browser then is ready to switch rendering the
* new document. Most observers should use NavigationCompleted or NavigationFailed instead,
* which happens right after the navigation commits. This method is for observers that want to
* initialize renderer-side state just before the BrowserController commits the navigation.
*
* This is the first point in time where a BrowserController is associated with the navigation.
*
* @param navigation the unique object for this navigation.
*/
public void navigationCommitted(Navigation navigation) {}
/**
* Called when a navigation completes successfully in the BrowserController.
*
* The document load will still be ongoing in the BrowserController. Use the document loads
* events such as onFirstContentfulPaint and related methods to listen for continued events from
* this BrowserController.
*
* Note that this is fired by same-document navigations, such as fragment navigations or
* pushState/replaceState, which will not result in a document change. To filter these out, use
* NavigationHandle::IsSameDocument.
*
* Note that |navigation| will be destroyed at the end of this call, so do not keep a reference
* to it afterward.
*
* @param navigation the unique object for this navigation.
*/
public void navigationCompleted(Navigation navigation) {}
/**
* Called when a navigation aborts in the BrowserController.
*
* Note that |navigation| will be destroyed at the end of this call, so do not keep a reference
* to it afterward.
*
* @param navigation the unique object for this navigation.
*/
public void navigationFailed(Navigation navigation) {}
/**
* This is fired after each navigation has completed to indicate that the first paint after a
* non-empty layout has finished.
*/
public void onFirstContentfulPaint() {}
}
......@@ -34,6 +34,8 @@ class Navigation {
};
virtual State GetState() = 0;
// TODO(jam): add IsSameDocument
};
} // namespace weblayer
......
......@@ -20,15 +20,67 @@ class NavigationObserver {
public:
virtual ~NavigationObserver() {}
// Called when a navigation started in the BrowserController. |navigation| is
// unique to a specific navigation. The same |navigation| will be provided on
// subsequent calls to NavigationRedirected, NavigationCommitted,
// NavigationCompleted and NavigationFailed when related to this navigation.
// Observers should clear any references to |navigation| in
// NavigationCompleted or NavigationFailed, just before it is destroyed.
//
// Note that this is only fired by navigations in the main frame.
//
// Note that this is fired by same-document navigations, such as fragment
// navigations or pushState/replaceState, which will not result in a document
// change. To filter these out, use Navigation::IsSameDocument.
//
// Note that more than one navigation can be ongoing in the BrowserController
// at the same time. Each will get its own Navigation object.
//
// Note that there is no guarantee that NavigationCompleted/NavigationFailed
// will be called for any particular navigation before NavigationStarted is
// called on the next.
virtual void NavigationStarted(Navigation* navigation) {}
// Called when a navigation encountered a server redirect.
virtual void NavigationRedirected(Navigation* navigation) {}
// Called when the navigation is ready to be committed in a renderer. A
// navigation is considered committed when the response code isn't 204/205
// (which tell the browser that the request is successful but there's no
// content that follows) or a download (either from a response header or based
// on mime sniffing the response). The browser then is ready to switch
// rendering the new document. Most observers should use NavigationCompleted
// or NavigationFailed instead, which happens right after the navigation
// commits. This method is for observers that want to initialize renderer-side
// state just before the BrowserController commits the navigation.
//
// This is the first point in time where a BrowserController is associated
// with the navigation.
virtual void NavigationCommitted(Navigation* navigation) {}
// Called when a navigation completes successfully in the BrowserController.
//
// The document load will still be ongoing in the BrowserController. Use the
// document loads events such as OnFirstContentfulPaint and related methods to
// listen for continued events from this BrowserController.
//
// Note that this is fired by same-document navigations, such as fragment
// navigations or pushState/replaceState, which will not result in a document
// change. To filter these out, use NavigationHandle::IsSameDocument.
//
// Note that |navigation| will be destroyed at the end of this call, so do not
// keep a reference to it afterward.
virtual void NavigationCompleted(Navigation* navigation) {}
// Called when a navigation aborts in the BrowserController.
//
// Note that |navigation| will be destroyed at the end of this call, so do not
// keep a reference to it afterward.
virtual void NavigationFailed(Navigation* navigation) {}
// This is fired after each navigation has completed to indicate that the
// first paint after a non-empty layout has finished.
virtual void OnFirstContentfulPaint() {}
};
} // namespace weblayer
......
......@@ -57,6 +57,7 @@ public class NavigationTest {
public NavigationCallbackHelper onStartedCallback = new NavigationCallbackHelper();
public NavigationCallbackHelper onCommittedCallback = new NavigationCallbackHelper();
public NavigationCallbackHelper onCompletedCallback = new NavigationCallbackHelper();
public CallbackHelper onFirstContentfulPaintCallback = new CallbackHelper();
@Override
public void navigationStarted(Navigation navigation) {
......@@ -72,6 +73,11 @@ public class NavigationTest {
public void navigationCompleted(Navigation navigation) {
onCompletedCallback.notifyCalled(navigation.getUri());
}
@Override
public void onFirstContentfulPaint() {
onFirstContentfulPaintCallback.notifyCalled();
}
}
private final Observer mObserver = new Observer();
......@@ -85,12 +91,15 @@ public class NavigationTest {
int curStartedCount = mObserver.onStartedCallback.getCallCount();
int curCommittedCount = mObserver.onCommittedCallback.getCallCount();
int curCompletedCount = mObserver.onCompletedCallback.getCallCount();
int curOnFirstContentfulPaintCount =
mObserver.onFirstContentfulPaintCallback.getCallCount();
mActivityTestRule.navigateAndWait(URL2);
mObserver.onStartedCallback.assertCalledWith(curStartedCount, URL2);
mObserver.onCommittedCallback.assertCalledWith(curCommittedCount, URL2);
mObserver.onCompletedCallback.assertCalledWith(curCompletedCount, URL2);
mObserver.onFirstContentfulPaintCallback.waitForCallback(curOnFirstContentfulPaintCount);
}
@Test
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment