blob: b303b120eac96d955a00ad1edb54b3334798a7c8 [file] [log] [blame]
// 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.customtabs;
import android.app.Application;
import android.os.IBinder;
import android.os.SystemClock;
import android.support.customtabs.CustomTabsCallback;
import org.chromium.base.metrics.RecordHistogram;
import org.chromium.chrome.browser.tab.EmptyTabObserver;
import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.browser.tab.TabObserver;
import org.chromium.components.security_state.ConnectionSecurityLevel;
import org.chromium.content_public.browser.LoadUrlParams;
import java.util.concurrent.TimeUnit;
/**
* A {@link TabObserver} that also handles custom tabs specific logging and messaging.
*/
class CustomTabObserver extends EmptyTabObserver {
private CustomTabsConnection mCustomTabsConnection;
private IBinder mSession;
private long mIntentReceivedTimestamp;
private long mPageLoadStartedTimestamp;
private static final int STATE_RESET = 0;
private static final int STATE_WAITING_LOAD_START = 1;
private static final int STATE_WAITING_LOAD_FINISH = 2;
private int mCurrentState;
public CustomTabObserver(Application application, IBinder session) {
mCustomTabsConnection = CustomTabsConnection.getInstance(application);
mSession = session;
resetPageLoadTracking();
}
/**
* Tracks the next page load, with timestamp as the origin of time.
*/
public void trackNextPageLoadFromTimestamp(long timestamp) {
mIntentReceivedTimestamp = timestamp;
mCurrentState = STATE_WAITING_LOAD_START;
}
@Override
public void onLoadUrl(Tab tab, LoadUrlParams params, int loadType) {
mCustomTabsConnection.registerLaunch(mSession, params.getUrl());
}
@Override
public void onPageLoadStarted(Tab tab, String url) {
if (mCurrentState == STATE_WAITING_LOAD_START) {
mPageLoadStartedTimestamp = SystemClock.elapsedRealtime();
mCurrentState = STATE_WAITING_LOAD_FINISH;
} else if (mCurrentState == STATE_WAITING_LOAD_FINISH) {
mCustomTabsConnection.notifyNavigationEvent(
mSession, CustomTabsCallback.NAVIGATION_ABORTED);
mPageLoadStartedTimestamp = SystemClock.elapsedRealtime();
}
mCustomTabsConnection.notifyNavigationEvent(
mSession, CustomTabsCallback.NAVIGATION_STARTED);
}
@Override
public void onShown(Tab tab) {
mCustomTabsConnection.notifyNavigationEvent(
mSession, CustomTabsCallback.TAB_SHOWN);
}
@Override
public void onPageLoadFinished(Tab tab) {
long pageLoadFinishedTimestamp = SystemClock.elapsedRealtime();
mCustomTabsConnection.notifyNavigationEvent(
mSession, CustomTabsCallback.NAVIGATION_FINISHED);
// Both histograms (commit and PLT) are reported here, to make sure
// that they are always recorded together, and that we only record
// commits for successful navigations.
if (mCurrentState == STATE_WAITING_LOAD_FINISH && mIntentReceivedTimestamp > 0) {
long timeToPageLoadStartedMs = mPageLoadStartedTimestamp - mIntentReceivedTimestamp;
long timeToPageLoadFinishedMs =
pageLoadFinishedTimestamp - mIntentReceivedTimestamp;
// Same bounds and bucket count as "Startup.FirstCommitNavigationTime"
RecordHistogram.recordCustomTimesHistogram(
"CustomTabs.IntentToFirstCommitNavigationTime", timeToPageLoadStartedMs,
1, TimeUnit.MINUTES.toMillis(1), TimeUnit.MILLISECONDS, 225);
// Same bounds and bucket count as PLT histograms.
RecordHistogram.recordCustomTimesHistogram("CustomTabs.IntentToPageLoadedTime",
timeToPageLoadFinishedMs, 10, TimeUnit.MINUTES.toMillis(10),
TimeUnit.MILLISECONDS, 100);
}
resetPageLoadTracking();
}
@Override
public void onDidAttachInterstitialPage(Tab tab) {
if (tab.getSecurityLevel() != ConnectionSecurityLevel.SECURITY_ERROR) return;
resetPageLoadTracking();
mCustomTabsConnection.notifyNavigationEvent(
mSession, CustomTabsCallback.NAVIGATION_FAILED);
}
@Override
public void onPageLoadFailed(Tab tab, int errorCode) {
resetPageLoadTracking();
mCustomTabsConnection.notifyNavigationEvent(
mSession, CustomTabsCallback.NAVIGATION_FAILED);
}
private void resetPageLoadTracking() {
mCurrentState = STATE_RESET;
mIntentReceivedTimestamp = -1;
}
}