Commit 62ad864c authored by Michael Thiessen's avatar Michael Thiessen Committed by Chromium LUCI CQ

Implement Main Launcher Intent LaunchCauseMetrics

Implements LaunchCause.MAIN_LAUNCHER_ICON, and adds tests to ensure that
Activity transitions within Chrome don't trigger additional Launch
Metrics.

Bug: 1163961
Change-Id: Idc23d799693750965364ca95073c084a7d4bf3c5
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2627764
Commit-Queue: Michael Thiessen <mthiesse@chromium.org>
Reviewed-by: default avatarYaron Friedman <yfriedman@chromium.org>
Cr-Commit-Position: refs/heads/master@{#843931}
parent bd72038d
......@@ -16,6 +16,7 @@ import android.os.IBinder;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.TransactionTooLargeException;
import android.text.TextUtils;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
......@@ -473,4 +474,13 @@ public class IntentUtils {
throw e;
}
}
/**
* @return True if the intent is a MAIN intent a launcher would send.
*/
public static boolean isMainIntentFromLauncher(Intent intent) {
return intent != null && TextUtils.equals(intent.getAction(), Intent.ACTION_MAIN)
&& intent.hasCategory(Intent.CATEGORY_LAUNCHER)
&& 0 == (intent.getFlags() & Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY);
}
}
......@@ -274,6 +274,7 @@ chrome_test_java_sources = [
"javatests/src/org/chromium/chrome/browser/metrics/MainIntentBehaviorMetricsIntegrationTest.java",
"javatests/src/org/chromium/chrome/browser/metrics/PageLoadMetricsTest.java",
"javatests/src/org/chromium/chrome/browser/metrics/StartupLoadingMetricsTest.java",
"javatests/src/org/chromium/chrome/browser/metrics/TabbedActivityLaunchCauseMetricsTest.java",
"javatests/src/org/chromium/chrome/browser/modaldialog/ChromeTabModalPresenterTest.java",
"javatests/src/org/chromium/chrome/browser/modaldialog/ModalDialogViewRenderTest.java",
"javatests/src/org/chromium/chrome/browser/multiwindow/MultiWindowIntegrationTest.java",
......
......@@ -924,7 +924,7 @@ public class ChromeTabbedActivity extends ChromeActivity<ChromeActivityComponent
TraceEvent.begin("ChromeTabbedActivity.onNewIntentWithNative");
super.onNewIntentWithNative(intent);
if (isMainIntentFromLauncher(intent)) {
if (IntentUtils.isMainIntentFromLauncher(intent)) {
logMainIntentBehavior(intent);
}
......@@ -1027,7 +1027,8 @@ public class ChromeTabbedActivity extends ChromeActivity<ChromeActivityComponent
showOverview(StartSurfaceState.SHOWING_START);
}
if (isMainIntentFromLauncher(getIntent()) && mOverviewModeController.overviewVisible()) {
if (IntentUtils.isMainIntentFromLauncher(getIntent())
&& mOverviewModeController.overviewVisible()) {
RecordUserAction.record("MobileStartup.UserEnteredTabSwitcher");
}
}
......@@ -1039,24 +1040,18 @@ public class ChromeTabbedActivity extends ChromeActivity<ChromeActivityComponent
// Handle NTP intent.
return true;
} else if (ReturnToChromeExperimentsUtil.shouldShowStartSurfaceAsTheHomePageNoTabs()
&& isMainIntentFromLauncher(getIntent())
&& IntentUtils.isMainIntentFromLauncher(getIntent())
&& ReturnToChromeExperimentsUtil.getTotalTabCount(getTabModelSelector()) <= 0) {
// Handle initial tab creation.
return true;
}
long lastBackgroundedTimeMillis = mInactivityTracker.getLastBackgroundedTimeMs();
return isMainIntentFromLauncher(getIntent())
return IntentUtils.isMainIntentFromLauncher(getIntent())
&& ReturnToChromeExperimentsUtil.shouldShowTabSwitcher(lastBackgroundedTimeMillis);
}
private boolean isMainIntentFromLauncher(Intent intent) {
return intent != null && TextUtils.equals(intent.getAction(), Intent.ACTION_MAIN)
&& intent.hasCategory(Intent.CATEGORY_LAUNCHER)
&& 0 == (intent.getFlags() & Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY);
}
private void logMainIntentBehavior(Intent intent) {
assert isMainIntentFromLauncher(intent);
assert IntentUtils.isMainIntentFromLauncher(intent);
// TODO(tedchoc): We should cache the last visible time and reuse it to avoid different
// values of this depending on when it is called after the activity was
// shown.
......@@ -1137,7 +1132,7 @@ public class ChromeTabbedActivity extends ChromeActivity<ChromeActivityComponent
isIntentWithEffect = mIntentHandler.onNewIntent(intent);
}
if (isMainIntentFromLauncher(intent)) {
if (IntentUtils.isMainIntentFromLauncher(intent)) {
isMainIntentFromLauncher = true;
logMainIntentBehavior(intent);
}
......
......@@ -55,7 +55,8 @@ public abstract class LaunchCauseMetrics implements ApplicationStatus.Applicatio
// These values are persisted in histograms. Please do not renumber. Append only.
@IntDef({LaunchCause.OTHER, LaunchCause.CUSTOM_TAB, LaunchCause.TWA, LaunchCause.RECENTS,
LaunchCause.RECENTS_OR_BACK, LaunchCause.FOREGROUND_WHEN_LOCKED})
LaunchCause.RECENTS_OR_BACK, LaunchCause.FOREGROUND_WHEN_LOCKED,
LaunchCause.MAIN_LAUNCHER_ICON})
@Retention(RetentionPolicy.SOURCE)
public @interface LaunchCause {
int OTHER = 0;
......@@ -64,8 +65,9 @@ public abstract class LaunchCauseMetrics implements ApplicationStatus.Applicatio
int RECENTS = 3;
int RECENTS_OR_BACK = 4;
int FOREGROUND_WHEN_LOCKED = 5;
int MAIN_LAUNCHER_ICON = 6;
int NUM_ENTRIES = 6;
int NUM_ENTRIES = 7;
}
/**
......@@ -216,6 +218,9 @@ public abstract class LaunchCauseMetrics implements ApplicationStatus.Applicatio
case LaunchCause.FOREGROUND_WHEN_LOCKED:
launchCause = "FOREGROUND_WHEN_LOCKED";
break;
case LaunchCause.MAIN_LAUNCHER_ICON:
launchCause = "MAIN_LAUNCHER_ICON";
break;
}
Log.d(TAG, "Launch Cause: " + launchCause);
}
......
......@@ -5,18 +5,33 @@
package org.chromium.chrome.browser.metrics;
import android.app.Activity;
import android.content.Intent;
import org.chromium.base.IntentUtils;
/**
* LaunchCauseMetrics for ChromeTabbedActivity.
*/
public class TabbedActivityLaunchCauseMetrics extends LaunchCauseMetrics {
private final Activity mActivity;
public TabbedActivityLaunchCauseMetrics(Activity activity) {
super(activity);
mActivity = activity;
}
@Override
public @LaunchCause int computeLaunchCause() {
// TODO(https://crbug.com/1163961): Implement ChromeTabbedActivity launch cause metrics.
Intent launchIntent = mActivity.getIntent();
if (launchIntent == null) return LaunchCause.OTHER;
if (IntentUtils.isMainIntentFromLauncher(launchIntent)) {
return LaunchCause.MAIN_LAUNCHER_ICON;
}
// TODO(https://crbug.com/1163961): Implement remaining ChromeTabbedActivity launch cause
// metrics.
return LaunchCause.OTHER;
}
}
......@@ -5,6 +5,7 @@
package org.chromium.chrome.browser.bookmarks;
import static androidx.test.espresso.Espresso.onView;
import static androidx.test.espresso.Espresso.pressBack;
import static androidx.test.espresso.action.ViewActions.click;
import static androidx.test.espresso.assertion.ViewAssertions.doesNotExist;
import static androidx.test.espresso.assertion.ViewAssertions.matches;
......@@ -45,6 +46,7 @@ import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import org.chromium.base.ApplicationStatus;
import org.chromium.base.metrics.RecordHistogram;
import org.chromium.base.test.params.ParameterAnnotations;
import org.chromium.base.test.params.ParameterizedRunner;
import org.chromium.base.test.util.ApplicationTestUtils;
......@@ -65,6 +67,7 @@ import org.chromium.chrome.browser.bookmarks.BookmarkPromoHeader.PromoState;
import org.chromium.chrome.browser.customtabs.CustomTabActivity;
import org.chromium.chrome.browser.flags.ChromeFeatureList;
import org.chromium.chrome.browser.flags.ChromeSwitches;
import org.chromium.chrome.browser.metrics.LaunchCauseMetrics;
import org.chromium.chrome.browser.night_mode.ChromeNightModeTestUtils;
import org.chromium.chrome.browser.offlinepages.OfflinePageItem;
import org.chromium.chrome.browser.offlinepages.OfflineTestUtil;
......@@ -1792,6 +1795,29 @@ public class BookmarkTest {
onView(withText("Reading list")).check(matches(isDisplayed()));
}
@Test
@MediumTest
public void testBookmarksDoesNotRecordLaunchMetrics() throws Throwable {
Assert.assertEquals(1,
RecordHistogram.getHistogramTotalCountForTesting(
LaunchCauseMetrics.LAUNCH_CAUSE_HISTOGRAM));
addBookmark(TEST_PAGE_TITLE_GOOGLE, mTestPage);
openBookmarkManager();
pressBack();
waitForTabbedActivity();
Assert.assertEquals(1,
RecordHistogram.getHistogramTotalCountForTesting(
LaunchCauseMetrics.LAUNCH_CAUSE_HISTOGRAM));
openBookmarkManager();
onView(withText(TEST_PAGE_TITLE_GOOGLE)).perform(click());
waitForTabbedActivity();
Assert.assertEquals(1,
RecordHistogram.getHistogramTotalCountForTesting(
LaunchCauseMetrics.LAUNCH_CAUSE_HISTOGRAM));
}
/**
* Adds a bookmark in the scenario where we have partner bookmarks.
*
......
// 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.metrics;
import android.app.Activity;
import android.content.Intent;
import androidx.test.filters.MediumTest;
import org.hamcrest.Matchers;
import org.junit.Assert;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.chromium.base.ActivityState;
import org.chromium.base.ApplicationStatus;
import org.chromium.base.library_loader.LibraryLoader;
import org.chromium.base.metrics.RecordHistogram;
import org.chromium.base.test.util.Batch;
import org.chromium.base.test.util.CommandLineFlags;
import org.chromium.base.test.util.Criteria;
import org.chromium.base.test.util.CriteriaHelper;
import org.chromium.chrome.browser.flags.ChromeSwitches;
import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
import org.chromium.chrome.test.util.ChromeApplicationTestUtils;
/**
* Integration tests for TabbedActivityLaunchCauseMetrics.
*/
@RunWith(ChromeJUnit4ClassRunner.class)
@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
@Batch(Batch.PER_CLASS)
public final class TabbedActivityLaunchCauseMetricsTest {
@Rule
public final ChromeTabbedActivityTestRule mActivityTestRule =
new ChromeTabbedActivityTestRule();
private static int histogramCountForValue(int value) {
if (!LibraryLoader.getInstance().isInitialized()) return 0;
return RecordHistogram.getHistogramValueCountForTesting(
LaunchCauseMetrics.LAUNCH_CAUSE_HISTOGRAM, value);
}
@Test
@MediumTest
public void testMainIntentMetrics() throws Throwable {
final int count = histogramCountForValue(LaunchCauseMetrics.LaunchCause.MAIN_LAUNCHER_ICON);
mActivityTestRule.startMainActivityFromLauncher();
CriteriaHelper.pollInstrumentationThread(() -> {
Criteria.checkThat(
histogramCountForValue(LaunchCauseMetrics.LaunchCause.MAIN_LAUNCHER_ICON),
Matchers.is(count + 1));
});
ChromeApplicationTestUtils.fireHomeScreenIntent(mActivityTestRule.getActivity());
mActivityTestRule.resumeMainActivityFromLauncher();
CriteriaHelper.pollInstrumentationThread(() -> {
Criteria.checkThat(
histogramCountForValue(LaunchCauseMetrics.LaunchCause.MAIN_LAUNCHER_ICON),
Matchers.is(count + 2));
});
}
@Test
@MediumTest
public void testNoMainIntentMetricsFromRecents() throws Throwable {
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
ApplicationStatus.ActivityStateListener listener =
new ApplicationStatus.ActivityStateListener() {
@Override
public void onActivityStateChange(
Activity activity, @ActivityState int newState) {
if (newState == ActivityState.CREATED) {
// Android strips FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY from sent intents,
// so we have to inject it as early as possible during startup.
activity.setIntent(activity.getIntent().addFlags(
Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY));
}
};
};
ApplicationStatus.registerStateListenerForAllActivities(listener);
final int mainCount =
histogramCountForValue(LaunchCauseMetrics.LaunchCause.MAIN_LAUNCHER_ICON);
final int recentsCount = histogramCountForValue(LaunchCauseMetrics.LaunchCause.RECENTS);
mActivityTestRule.startMainActivityFromIntent(intent, null);
CriteriaHelper.pollInstrumentationThread(() -> {
Criteria.checkThat(histogramCountForValue(LaunchCauseMetrics.LaunchCause.RECENTS),
Matchers.is(recentsCount + 1));
});
Assert.assertEquals(mainCount,
histogramCountForValue(LaunchCauseMetrics.LaunchCause.MAIN_LAUNCHER_ICON));
ApplicationStatus.unregisterActivityStateListener(listener);
}
}
......@@ -41255,6 +41255,7 @@ Called by update_gpu_driver_bug_workaround_entries.py.-->
<int value="3" label="Recents (aka App Overview)"/>
<int value="4" label="Recents or Back"/>
<int value="5" label="Foreground when Locked (Power Button)"/>
<int value="6" label="Main Chrome Launcher Icon"/>
</enum>
<enum name="LauncherRankingItemType">
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