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; ...@@ -16,6 +16,7 @@ import android.os.IBinder;
import android.os.Parcel; import android.os.Parcel;
import android.os.Parcelable; import android.os.Parcelable;
import android.os.TransactionTooLargeException; import android.os.TransactionTooLargeException;
import android.text.TextUtils;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting; import androidx.annotation.VisibleForTesting;
...@@ -473,4 +474,13 @@ public class IntentUtils { ...@@ -473,4 +474,13 @@ public class IntentUtils {
throw e; 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 = [ ...@@ -274,6 +274,7 @@ chrome_test_java_sources = [
"javatests/src/org/chromium/chrome/browser/metrics/MainIntentBehaviorMetricsIntegrationTest.java", "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/PageLoadMetricsTest.java",
"javatests/src/org/chromium/chrome/browser/metrics/StartupLoadingMetricsTest.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/ChromeTabModalPresenterTest.java",
"javatests/src/org/chromium/chrome/browser/modaldialog/ModalDialogViewRenderTest.java", "javatests/src/org/chromium/chrome/browser/modaldialog/ModalDialogViewRenderTest.java",
"javatests/src/org/chromium/chrome/browser/multiwindow/MultiWindowIntegrationTest.java", "javatests/src/org/chromium/chrome/browser/multiwindow/MultiWindowIntegrationTest.java",
......
...@@ -924,7 +924,7 @@ public class ChromeTabbedActivity extends ChromeActivity<ChromeActivityComponent ...@@ -924,7 +924,7 @@ public class ChromeTabbedActivity extends ChromeActivity<ChromeActivityComponent
TraceEvent.begin("ChromeTabbedActivity.onNewIntentWithNative"); TraceEvent.begin("ChromeTabbedActivity.onNewIntentWithNative");
super.onNewIntentWithNative(intent); super.onNewIntentWithNative(intent);
if (isMainIntentFromLauncher(intent)) { if (IntentUtils.isMainIntentFromLauncher(intent)) {
logMainIntentBehavior(intent); logMainIntentBehavior(intent);
} }
...@@ -1027,7 +1027,8 @@ public class ChromeTabbedActivity extends ChromeActivity<ChromeActivityComponent ...@@ -1027,7 +1027,8 @@ public class ChromeTabbedActivity extends ChromeActivity<ChromeActivityComponent
showOverview(StartSurfaceState.SHOWING_START); showOverview(StartSurfaceState.SHOWING_START);
} }
if (isMainIntentFromLauncher(getIntent()) && mOverviewModeController.overviewVisible()) { if (IntentUtils.isMainIntentFromLauncher(getIntent())
&& mOverviewModeController.overviewVisible()) {
RecordUserAction.record("MobileStartup.UserEnteredTabSwitcher"); RecordUserAction.record("MobileStartup.UserEnteredTabSwitcher");
} }
} }
...@@ -1039,24 +1040,18 @@ public class ChromeTabbedActivity extends ChromeActivity<ChromeActivityComponent ...@@ -1039,24 +1040,18 @@ public class ChromeTabbedActivity extends ChromeActivity<ChromeActivityComponent
// Handle NTP intent. // Handle NTP intent.
return true; return true;
} else if (ReturnToChromeExperimentsUtil.shouldShowStartSurfaceAsTheHomePageNoTabs() } else if (ReturnToChromeExperimentsUtil.shouldShowStartSurfaceAsTheHomePageNoTabs()
&& isMainIntentFromLauncher(getIntent()) && IntentUtils.isMainIntentFromLauncher(getIntent())
&& ReturnToChromeExperimentsUtil.getTotalTabCount(getTabModelSelector()) <= 0) { && ReturnToChromeExperimentsUtil.getTotalTabCount(getTabModelSelector()) <= 0) {
// Handle initial tab creation. // Handle initial tab creation.
return true; return true;
} }
long lastBackgroundedTimeMillis = mInactivityTracker.getLastBackgroundedTimeMs(); long lastBackgroundedTimeMillis = mInactivityTracker.getLastBackgroundedTimeMs();
return isMainIntentFromLauncher(getIntent()) return IntentUtils.isMainIntentFromLauncher(getIntent())
&& ReturnToChromeExperimentsUtil.shouldShowTabSwitcher(lastBackgroundedTimeMillis); && 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) { 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 // 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 // values of this depending on when it is called after the activity was
// shown. // shown.
...@@ -1137,7 +1132,7 @@ public class ChromeTabbedActivity extends ChromeActivity<ChromeActivityComponent ...@@ -1137,7 +1132,7 @@ public class ChromeTabbedActivity extends ChromeActivity<ChromeActivityComponent
isIntentWithEffect = mIntentHandler.onNewIntent(intent); isIntentWithEffect = mIntentHandler.onNewIntent(intent);
} }
if (isMainIntentFromLauncher(intent)) { if (IntentUtils.isMainIntentFromLauncher(intent)) {
isMainIntentFromLauncher = true; isMainIntentFromLauncher = true;
logMainIntentBehavior(intent); logMainIntentBehavior(intent);
} }
......
...@@ -55,7 +55,8 @@ public abstract class LaunchCauseMetrics implements ApplicationStatus.Applicatio ...@@ -55,7 +55,8 @@ public abstract class LaunchCauseMetrics implements ApplicationStatus.Applicatio
// These values are persisted in histograms. Please do not renumber. Append only. // These values are persisted in histograms. Please do not renumber. Append only.
@IntDef({LaunchCause.OTHER, LaunchCause.CUSTOM_TAB, LaunchCause.TWA, LaunchCause.RECENTS, @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) @Retention(RetentionPolicy.SOURCE)
public @interface LaunchCause { public @interface LaunchCause {
int OTHER = 0; int OTHER = 0;
...@@ -64,8 +65,9 @@ public abstract class LaunchCauseMetrics implements ApplicationStatus.Applicatio ...@@ -64,8 +65,9 @@ public abstract class LaunchCauseMetrics implements ApplicationStatus.Applicatio
int RECENTS = 3; int RECENTS = 3;
int RECENTS_OR_BACK = 4; int RECENTS_OR_BACK = 4;
int FOREGROUND_WHEN_LOCKED = 5; 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 ...@@ -216,6 +218,9 @@ public abstract class LaunchCauseMetrics implements ApplicationStatus.Applicatio
case LaunchCause.FOREGROUND_WHEN_LOCKED: case LaunchCause.FOREGROUND_WHEN_LOCKED:
launchCause = "FOREGROUND_WHEN_LOCKED"; launchCause = "FOREGROUND_WHEN_LOCKED";
break; break;
case LaunchCause.MAIN_LAUNCHER_ICON:
launchCause = "MAIN_LAUNCHER_ICON";
break;
} }
Log.d(TAG, "Launch Cause: " + launchCause); Log.d(TAG, "Launch Cause: " + launchCause);
} }
......
...@@ -5,18 +5,33 @@ ...@@ -5,18 +5,33 @@
package org.chromium.chrome.browser.metrics; package org.chromium.chrome.browser.metrics;
import android.app.Activity; import android.app.Activity;
import android.content.Intent;
import org.chromium.base.IntentUtils;
/** /**
* LaunchCauseMetrics for ChromeTabbedActivity. * LaunchCauseMetrics for ChromeTabbedActivity.
*/ */
public class TabbedActivityLaunchCauseMetrics extends LaunchCauseMetrics { public class TabbedActivityLaunchCauseMetrics extends LaunchCauseMetrics {
private final Activity mActivity;
public TabbedActivityLaunchCauseMetrics(Activity activity) { public TabbedActivityLaunchCauseMetrics(Activity activity) {
super(activity); super(activity);
mActivity = activity;
} }
@Override @Override
public @LaunchCause int computeLaunchCause() { 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; return LaunchCause.OTHER;
} }
} }
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
package org.chromium.chrome.browser.bookmarks; package org.chromium.chrome.browser.bookmarks;
import static androidx.test.espresso.Espresso.onView; 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.action.ViewActions.click;
import static androidx.test.espresso.assertion.ViewAssertions.doesNotExist; import static androidx.test.espresso.assertion.ViewAssertions.doesNotExist;
import static androidx.test.espresso.assertion.ViewAssertions.matches; import static androidx.test.espresso.assertion.ViewAssertions.matches;
...@@ -45,6 +46,7 @@ import org.mockito.junit.MockitoJUnit; ...@@ -45,6 +46,7 @@ import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule; import org.mockito.junit.MockitoRule;
import org.chromium.base.ApplicationStatus; import org.chromium.base.ApplicationStatus;
import org.chromium.base.metrics.RecordHistogram;
import org.chromium.base.test.params.ParameterAnnotations; import org.chromium.base.test.params.ParameterAnnotations;
import org.chromium.base.test.params.ParameterizedRunner; import org.chromium.base.test.params.ParameterizedRunner;
import org.chromium.base.test.util.ApplicationTestUtils; import org.chromium.base.test.util.ApplicationTestUtils;
...@@ -65,6 +67,7 @@ import org.chromium.chrome.browser.bookmarks.BookmarkPromoHeader.PromoState; ...@@ -65,6 +67,7 @@ import org.chromium.chrome.browser.bookmarks.BookmarkPromoHeader.PromoState;
import org.chromium.chrome.browser.customtabs.CustomTabActivity; import org.chromium.chrome.browser.customtabs.CustomTabActivity;
import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.flags.ChromeFeatureList;
import org.chromium.chrome.browser.flags.ChromeSwitches; 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.night_mode.ChromeNightModeTestUtils;
import org.chromium.chrome.browser.offlinepages.OfflinePageItem; import org.chromium.chrome.browser.offlinepages.OfflinePageItem;
import org.chromium.chrome.browser.offlinepages.OfflineTestUtil; import org.chromium.chrome.browser.offlinepages.OfflineTestUtil;
...@@ -1792,6 +1795,29 @@ public class BookmarkTest { ...@@ -1792,6 +1795,29 @@ public class BookmarkTest {
onView(withText("Reading list")).check(matches(isDisplayed())); 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. * 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.--> ...@@ -41255,6 +41255,7 @@ Called by update_gpu_driver_bug_workaround_entries.py.-->
<int value="3" label="Recents (aka App Overview)"/> <int value="3" label="Recents (aka App Overview)"/>
<int value="4" label="Recents or Back"/> <int value="4" label="Recents or Back"/>
<int value="5" label="Foreground when Locked (Power Button)"/> <int value="5" label="Foreground when Locked (Power Button)"/>
<int value="6" label="Main Chrome Launcher Icon"/>
</enum> </enum>
<enum name="LauncherRankingItemType"> <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