blob: 733c6aedac0de34526e45d92689d0dce46cc98dc [file] [log] [blame]
// Copyright 2020 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.webapps;
import static org.chromium.chrome.browser.dependency_injection.ChromeCommonQualifiers.SAVED_INSTANCE_SUPPLIER;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.os.SystemClock;
import androidx.annotation.VisibleForTesting;
import org.chromium.base.ActivityState;
import org.chromium.base.ApplicationStatus;
import org.chromium.base.ApplicationStatus.ActivityStateListener;
import org.chromium.base.library_loader.LibraryLoader;
import org.chromium.base.supplier.Supplier;
import org.chromium.chrome.browser.browserservices.intents.BrowserServicesIntentDataProvider;
import org.chromium.chrome.browser.browserservices.intents.WebApkExtras;
import org.chromium.chrome.browser.browserservices.intents.WebappIntentUtils;
import org.chromium.chrome.browser.browserservices.metrics.WebApkUkmRecorder;
import org.chromium.chrome.browser.browserservices.metrics.WebApkUmaRecorder;
import org.chromium.chrome.browser.browserservices.ui.splashscreen.SplashController;
import org.chromium.chrome.browser.dependency_injection.ActivityScope;
import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher;
import org.chromium.chrome.browser.lifecycle.InflationObserver;
import org.chromium.chrome.browser.lifecycle.PauseResumeWithNativeObserver;
import org.chromium.chrome.browser.metrics.ActivityTabStartupMetricsTracker;
import org.chromium.chrome.browser.metrics.WebApkSplashscreenMetrics;
import javax.inject.Inject;
import javax.inject.Named;
import dagger.Lazy;
/**
* Handles recording user metrics for WebAPK activities.
*/
@ActivityScope
public class WebApkActivityLifecycleUmaTracker
implements ActivityStateListener, InflationObserver, PauseResumeWithNativeObserver {
@VisibleForTesting
public static final String STARTUP_UMA_HISTOGRAM_SUFFIX = ".WebApk";
private final Activity mActivity;
private final BrowserServicesIntentDataProvider mIntentDataProvider;
private final SplashController mSplashController;
private final Lazy<ActivityTabStartupMetricsTracker> mStartupMetricsTracker;
private final Supplier<Bundle> mSavedInstanceStateSupplier;
/** The start time that the activity becomes focused in milliseconds since boot. */
private long mStartTime;
@Inject
public WebApkActivityLifecycleUmaTracker(Activity activity,
BrowserServicesIntentDataProvider intentDataProvider, SplashController splashController,
ActivityLifecycleDispatcher lifecycleDispatcher,
WebappDeferredStartupWithStorageHandler deferredStartupWithStorageHandler,
Lazy<ActivityTabStartupMetricsTracker> startupMetricsTracker,
@Named(SAVED_INSTANCE_SUPPLIER) Supplier<Bundle> savedInstanceStateSupplier) {
mActivity = activity;
mIntentDataProvider = intentDataProvider;
mSplashController = splashController;
mStartupMetricsTracker = startupMetricsTracker;
mSavedInstanceStateSupplier = savedInstanceStateSupplier;
lifecycleDispatcher.register(this);
ApplicationStatus.registerStateListenerForActivity(this, mActivity);
// Add UMA recording task at the front of the deferred startup queue as it has a higher
// priority than other deferred startup tasks like checking for a WebAPK update.
deferredStartupWithStorageHandler.addTaskToFront((storage, didCreateStorage) -> {
if (lifecycleDispatcher.isActivityFinishingOrDestroyed()) return;
WebApkExtras webApkExtras = mIntentDataProvider.getWebApkExtras();
WebApkUmaRecorder.recordShellApkVersion(
webApkExtras.shellApkVersion, webApkExtras.distributor);
});
}
@Override
public void onActivityStateChange(Activity activity, @ActivityState int newState) {
if (newState == ActivityState.RESUMED) {
mStartTime = SystemClock.elapsedRealtime();
}
}
@Override
public void onPreInflationStartup() {
// Decide whether to record startup UMA histograms. This is a similar check to the one done
// in ChromeTabbedActivity.performPreInflationStartup refer to the comment there for why.
if (!LibraryLoader.getInstance().isInitialized()) {
mStartupMetricsTracker.get().trackStartupMetrics(STARTUP_UMA_HISTOGRAM_SUFFIX);
// If there is a saved instance state, then the intent (and its stored timestamp) might
// be stale (Android replays intents if there is a recents entry for the activity).
if (mSavedInstanceStateSupplier.get() == null) {
Intent intent = mActivity.getIntent();
// Splash observers are removed once the splash screen is hidden.
mSplashController.addObserver(new WebApkSplashscreenMetrics(
WebappIntentUtils.getWebApkShellLaunchTime(intent),
WebappIntentUtils.getNewStyleWebApkSplashShownTime(intent)));
}
}
}
@Override
public void onPostInflationStartup() {}
@Override
public void onResumeWithNative() {}
@Override
public void onPauseWithNative() {
WebApkExtras webApkExtras = mIntentDataProvider.getWebApkExtras();
long sessionDuration = SystemClock.elapsedRealtime() - mStartTime;
WebApkUmaRecorder.recordWebApkSessionDuration(webApkExtras.distributor, sessionDuration);
WebApkUkmRecorder.recordWebApkSessionDuration(webApkExtras.manifestUrl,
webApkExtras.distributor, webApkExtras.webApkVersionCode, sessionDuration);
}
}